tags:

views:

135

answers:

5

I want to find value of In(x) without using math.h function

I am following this formula which I found in my math book:

log(m) base e = 2[ (m-1/m+1) + (1/3) * (m-1/m+1)^3 + (1/5) * (m-1/m+1)^5 + ... ]

Here is my code:

i = 3;
logx = 0 ;
ty = (x-1)/(x+1) ;
do
{
    logx = logx + ty ;
    tty = ty ;
    ty = (ty * ((x-1)/(x+1)) * ((x-1)/(x+1))) / i ;
    i = i + 2 ;
} while(tty - ty > 0.0000005 );
logx = 2*logx ;
printf("\n ln (%g) = %g \n", x, logx);

but this shows ln(2) = 0.691916 instead of 0.693147 and ln(3) = 1.08765 instead of 1.098612 etc. What is wrong?

+4  A: 

You should not divide by i and then assign to ty, devide by i after the addition, i.e. logx = logx + ty / i.

Edit this should work:

i=1;   // (i.e. not 3)
logx = 0 ;
ty = (x-1)/(x+1) ;
do
{
    logx = logx + ty / i;
    tty = ty ;
    ty = (ty * ((x-1)/(x+1)) * ((x-1)/(x+1)));
    i = i + 2 ;
} while(tty - ty > 0.0000005 );
mvds
Yes it is. mathoverflow is for reseach. This is very much an implementation question.
duffymo
now there's a `c` tag on the question, I agree ;-)
mvds
Yup. That looks better. And although its outside the scope of the question I personally would prefer to see the logx assignment happen at the end of the loop. Otherwise you waste your last loop (you get the next ty but then never use it).
Chris
That, plus storing `(x-1)/(x+1) * (x-1)/(x+1)` once outside the loop. `gcc -O3` apparently doesn't notice that the factor is the same every iteration.
mvds
thank you. I get it.
Barshan Das
A: 

you're approximating a function with a finite number of iterations (the stop condition is tty-ty > ...); decrease the 0.00000005 and you should obtain better precision

then you might run into numerical precision problems, so try using double instead of float if you're not already doing so

finally remember that generally logarithms are irrational numbers so they just can't be represented with a finite number of digits

Nicola Montecchio
A: 

ISTR that the rate of convergence of log series are notoriously slow.

Visage
+3  A: 

Actually what OP's computing is

$2\sum_{n=1,n\text{ odd}}^\infty\frac1{n!!}\left(\frac{m-1}{m+1}\right)^n = \sqrt{2\pi} \exp\left(\frac12\left(\frac{m-1}{m+1}\right)^2\right)\operatorname{erf}\left(\frac1{\sqrt2}\frac{m-1}{m+1}\right)$

instead of

$2\sum_{n=1,n\text{ odd}}^\infty\frac1{n}\left(\frac{m-1}{m+1}\right)^n = 2\tanh^{-1}\frac{m-1}{m+1} = \ln m$

BTW, it's better to factor out the ((x-1)/(x+1)) * ((x-1)/(x+1)) to avoid recomputing it. (The compiler may or may not treat this as a loop invariant and take it out.)

double ty = (x-1)/(x+1);
double p = ty * ty;
int i = 1;
double logx = 0;
do {
  logx += ty / i;
  tty = ty;
  ty *= p;
  i += 2;
} while (tty/(i-2) - ty/i > 5e-6);
KennyTM
thank you very much.
Barshan Das
+1  A: 

Your C implementation is not correct for the algorithm.

log(m) base e = 2[ (m-1/m+1) + (1/3) * (m-1/m+1)^3 + (1/5) * (m-1/m+1)^5 + ... ]
                                ^^^ what is this      ^^^ and this

Your algorithm:

i = 3;
logx = 0 ;
ty = (x-1)/(x+1) ;
do
{
    logx = logx + ty ;
    tty = ty ;
    ty = (ty * ((x-1)/(x+1)) * ((x-1)/(x+1))) / i ; 
//  ^^ when i = 3 ty after this line = ((x-1)/(x+1) * ((x-1)/(x+1))^2) / 3
//     when i = 5 ty after this line = ((((x-1)/(x+1)^3) / 3) * ((x-1)/(x+1))^2) / 5 
//                                   = ((x-1)/(x+1)^5) / 15 <<< wrong divisor (see above, should be 5)
//     and it gets worse for each iteration of the loop
    i = i + 2 ;
} while(tty - ty > 0.0000005 );
logx = 2*logx ;
printf("\n ln (%g) = %g \n", x, logx);
JeremyP
thank you JeremyP. You perfectly showed me where I am doing wrong.Thanks a lot.
Barshan Das