Beginner help

A

asadfag

So I'm learning C and here's the first thing I'm having problems with.

The goal is to compare the real ln and ln(x) computed using the
following sequence :
http://xs135.xs.to/xs135/09033/hw623.gif

And here's my try:

#include <stdio.h>
#include <math.h>

float power(float n, float m)
{
int i;
float p;

p = 1;
for (i = 1; i <= m; i++)
p = p * n;

return p;
}

float seqsum(int n, float x)
{
int i;
float r,s;

s = (x - 1) / (x + 1);
for (i = 1; i < n; i++)
s = s + (power(x - 1, 2 * i + 1)) / 3 * (power(x + 1, 2 * i +
1));
return s;
}

main()
{
float d,e;
int i;
printf("approx\t\tvalue\n");
for (i = 1; i <= 8; i = i * 2)
{
d = seqsum(i,0.1);
e = log(0.1);
printf("%f\t%f\n", d,e);
}
}

But the output values are horribly wrong for some inputs:

For x = 0.1
approx value
-1.636364 -2.302585
-2.283230 -2.302585
-3.538600 -2.302585
-5.902889 -2.302585

For x = 0.3
approx value
-1.076923 -1.203973
-1.579304 -1.203973
-2.339832 -1.203973
-3.219005 -1.203973

For x = 0.9
approx value
-0.105263 -0.105361
-0.109836 -0.105361
-0.110007 -0.105361
-0.110007 -0.105361


What could be the cause of this?
 
A

asadfag

     You might consider using C's pow() function instead.

I tried, but the compiler complains about "undefined reference to
`pow'"
     Here's your problem, or one of them at any rate.  Abbreviated,
this line is

        s = s + (power(...) / 3 * power(...));

... but that's not the formula from your link.  In C, multiplication
and division have equal precedence and are processed left-to-right,
so what you've written is equivalent to

        s = s + (power(...) / 3) * power(...);

... while what you actually want is

        s = s + power(...) / (3 * power(...));

Oh, that was so silly.
Thanks.
 
J

John Bode

     You might consider using C's pow() function instead.



     Here's your problem, or one of them at any rate.  Abbreviated,
this line is

        s = s + (power(...) / 3 * power(...));

... but that's not the formula from your link.  In C, multiplication
and division have equal precedence and are processed left-to-right,
so what you've written is equivalent to

        s = s + (power(...) / 3) * power(...);

... while what you actually want is

        s = s + power(...) / (3 * power(...));

It doesn't help that the formula given to the OP is wrong. The
correct formula is

2 * [(x-1)/(x+1) + (x-1)^3 / (3*(x+1)^3) + (x-1)^5 / (5*(x+1)^5)
+ ... ]

or

2 * SUM(i=1..N) [(x-1)^(2*i-1) / ((2*i-1) * (x+1)^(2*i-1))]
 
U

user923005

So I'm learning C and here's the first thing I'm having problems with.

The goal is to compare the real ln and ln(x) computed using the
following sequence :http://xs135.xs.to/xs135/09033/hw623.gif

And here's my try:

#include <stdio.h>
#include <math.h>

float power(float n, float m)
  {
    int i;
    float p;

    p = 1;
    for (i = 1; i <= m; i++)
      p = p * n;

    return p;
  }

float seqsum(int n, float x)
  {
    int i;
    float r,s;

    s = (x - 1) / (x + 1);
    for (i = 1; i < n; i++)
      s = s + (power(x - 1, 2 * i + 1)) / 3 * (power(x + 1, 2 * i +
1));
    return s;
  }

main()
  {
    float d,e;
    int i;
      printf("approx\t\tvalue\n");
      for (i = 1; i <= 8; i = i * 2)
        {
          d = seqsum(i,0.1);
          e = log(0.1);
          printf("%f\t%f\n", d,e);
        }
  }

But the output values are horribly wrong for some inputs:

For x = 0.1
approx          value
-1.636364       -2.302585
-2.283230       -2.302585
-3.538600       -2.302585
-5.902889       -2.302585

For x = 0.3
approx          value
-1.076923       -1.203973
-1.579304       -1.203973
-2.339832       -1.203973
-3.219005       -1.203973

For x = 0.9
approx          value
-0.105263       -0.105361
-0.109836       -0.105361
-0.110007       -0.105361
-0.110007       -0.105361

What could be the cause of this?

Besides what others have mentioned, the formula is simply *wrong*.
See the section "More Efficient Series" here:
http://en.wikipedia.org/wiki/Logarithm

Here is the solution with the formula corrected:

#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdio.h>

double lnx(double x)
{
int improving = 1;
const double xm1 = x - 1.0;
const double xp1 = x + 1.0;
const double xm1sq = xm1 * xm1;
const double xp1sq = xp1 * xp1;
double numerator = xm1;
double denominator = xp1;
double olddelta = DBL_MAX;
double sum = numerator / denominator;
double denominator_const = 1.0;
assert(x > 0);
do {
double oldsum = sum;
double delta;
numerator *= xm1sq;
denominator *= xp1sq;
denominator_const += 2;
sum += numerator / (denominator * denominator_const);
delta = fabs(sum - oldsum);
improving = delta < olddelta;
olddelta = delta;
} while (improving);
return sum + sum;
}

#ifdef UNIT_TEST
int main(void)
{
double d = 0.2;
int i;
for (i = 0; i < 6; i++) {
double r1,
r2,
delta;
r1 = log(d);
r2 = lnx(d);
delta = fabs(r1 - r2);
printf("log(%f)=%f, lnx(%f)=%f, difference=%g\n", d, r1, d,
r2, delta);

d += 0.2;
}
return 0;
}
#endif
/* Possible output:
log(0.200000)=-1.609438, lnx(0.200000)=-1.609438,
difference=4.44089e-016
log(0.400000)=-0.916291, lnx(0.400000)=-0.916291,
difference=1.11022e-016
log(0.600000)=-0.510826, lnx(0.600000)=-0.510826,
difference=1.11022e-016
log(0.800000)=-0.223144, lnx(0.800000)=-0.223144,
difference=2.77556e-017
log(1.000000)=0.000000, lnx(1.000000)=0.000000, difference=0
log(1.200000)=0.182322, lnx(1.200000)=0.182322, difference=0
*/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top