Value of "e" in the C log() function

A

almurph

Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

Cheers,
Al.
 
J

jacob navia

Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

Cheers,
Al.

This question means that you haven't understood how the log function can
be implemented. There are many possible implementations, for instance as
a polynomial approximation, or others. None of them uses any value of "e".

The best thing would be to print a selected set of values and compare
those with the C# log to see if there are any differences. If there are
differences you should make sure you understand why.

In short:

It shouldn't be any differences if the log() of C# calculates the
natural logarithm
 
J

Jens Thoms Toerring

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

The C language doesn't "use" e in the log() function, it
only requires that the libc/math library supplies a log()
function. What exact algorithm is used in this function
for calculating the function value isn't specified. And I
would guess that rather likely e isn't used in the com-
putation but that either an approxiation method is used
or the calculation is passed on to a floating point pro-
cessor (if available). Just for the fun of it have a look
at what looks like a real-world implementation of the log()
function:

http://www.netlib.org/fdlibm/e_log.c

So, in short, you can't compare C#'s log() function to the
C log() function (except by comparing what the C standard
requires from the log() function and what is documented for
C#) since in C there's not one log() function that is used
on all systems.
Regards, Jens
 
E

Eric Sosman

Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

You could hope that log() and exp() are mutually
consistent and evaluate exp(1). Or you could use an
iterative method to find `x' satisfying log(x)==1.
Either way, the value will be system-dependent, that
is, the next system you try may give a slightly different
result. (Of course, *no* system will give `e' exactly.)
 
D

Dik T. Winter

>
> You could hope that log() and exp() are mutually
> consistent and evaluate exp(1).

If they are reasonably correct both would implement the function as defined
in mathematics, with rounding errors involved. But that is the best
consistency you can expect.
> evaluate exp(1). Or you could use an
> iterative method to find `x' satisfying log(x)==1.

I am quite certain that the two will not be identical, because in most
implementations of those functions the result will be perturbed by
rounding errors and you must be very lucky if they work out the same.
 
E

Eric Sosman

Dik said:
Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. [...]
[...]
evaluate exp(1). Or you could use an
iterative method to find `x' satisfying log(x)==1.

I am quite certain that the two will not be identical, because in most
implementations of those functions the result will be perturbed by
rounding errors and you must be very lucky if they work out the same.

They're quite likely to differ, in which case the O.P.'s
question becomes "Who ya gonna believe?" It seems to me the
latter has no easy answer.
 
D

Dik T. Winter

> Dik T. Winter wrote: ....
> > > (e-mail address removed) wrote:
> > > > Hi everyone,
> > > >
> > > > Does anyone know what is the exact value of "e" that the C
> > > > language uses in the log() function. [...]
> > > [...]
> > > evaluate exp(1). Or you could use an
> > > iterative method to find `x' satisfying log(x)==1.
> >
> > I am quite certain that the two will not be identical, because in most
> > implementations of those functions the result will be perturbed by
> > rounding errors and you must be very lucky if they work out the same.
>
> They're quite likely to differ, in which case the O.P.'s
> question becomes "Who ya gonna believe?" It seems to me the
> latter has no easy answer.

Moreover, it is almost certain that there are two different values for
which log gives exactly 1.0. So which of the two must be believed?

In any sane algorithm to calculate the logarithm 'e' itself plays no role
at all. The only irrational constant that will influence the outcome is
log(2).
 
M

Martin Ambuhl

Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

I guess it's understandable, although sad, that you don't know that your
question and the goal you are pursuing are meaningless. But, in any case:

/* You can modify the code below to run with your implementation.
* If you just want to see what one typical implementation does,
* check the output at the end of the code */

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

#define HAVE_LOGF
/* #define HAVE_LOGL */

const long double e = 2.7182818284590452353602874713526624977572L;

int main(void)
{
float xf = e, yf;
double xd = e, yd;
long double xld = e, yld;


int hexfracdigits;

if (FLT_RADIX != 2) {
fprintf(stderr,
"If your implementation uses a base other than 2,\n"
"I'll let you play with it yourself. The rest of my\n"
"code assumes FLT_RADIX == 2.\n");
exit(EXIT_FAILURE);
}
printf("There is, of course, no value that C uses for\n"
"e, since that is an implementation detail\n"
"for whatever library your program is linked\n"
"to. The library need not be written in C,\n"
"and can use whatever tricks it wants.\n\n"
"Here are some approximations for e on this implementation.\n"
"First we'll check what how good it could get.\n\n");
hexfracdigits = FLT_MANT_DIG / 4;
printf("FLT_DIG = %d, FLT_MANT_DIG/4 = %d\n"
"a float value for e might be\n"
"%.*e (decimal) %.*a (hex digits * power of 2)\n\n",
FLT_DIG, hexfracdigits, FLT_DIG, xf, hexfracdigits, xf);


hexfracdigits = DBL_MANT_DIG / 4;
printf("DBL_DIG = %d, DBL_MANT_DIG/4 = %d\n"
"a double value for e might be\n"
"%.*e (decimal) %.*a\n\n",
DBL_DIG, hexfracdigits, DBL_DIG, xd, hexfracdigits, xd);


hexfracdigits = LDBL_MANT_DIG / 4;
printf("LDBL_DIG = %d, LDBL_MANT_DIG/4 = %d\n"
"a long double value for e might be\n"
"%.*Le (decimal) %.*La\n\n",
LDBL_DIG, hexfracdigits, LDBL_DIG, xld, hexfracdigits, xld);


printf("Now let's look at the exp() family for some estimate\n"
"of what this implementation actually uses.\n\n");
#if defined(HAVE_LOGF)
printf("This implementation has the float version, so\n"
"let's see what expf() returns.\n");

xf = expf(1);
yf = logf(xf);
hexfracdigits = FLT_MANT_DIG / 4;
printf("xf = expf(1), %.*e %.*a\n"
"logf(xf) = %.*e %.*a\n\n",
FLT_DIG, xf, hexfracdigits, xf, FLT_DIG, yf, hexfracdigits,
yf);
#endif
printf("Now let's check the double version.\n");
xd = exp(1);
yd = log(xd);
hexfracdigits = DBL_MANT_DIG / 4;
printf("xd = exp(1), %.*e %.*a\n"
"log(xd) = %.*e %.*a\n\n",
DBL_DIG, xd, hexfracdigits, xd, DBL_DIG, yd, hexfracdigits,
yd);

#if defined(HAVE_LOGL)
printf("This implementation has the long double version, so\n"
"let's see what expl() returns.\n");

xld = expl(1);
yld = logl(xld);
hexfracdigits = LDBL_MANT_DIG / 4;
printf("xd = expl(1), %.*Le %.*La\n"
"logl(xdl) = %.*Le %.*La\n\n", LDBL_DIG, xld, hexfracdigits,
xld, LDBL_DIG, yld, hexfracdigits, yld);
#endif
return 0;
}

[Output]

There is, of course, no value that C uses for
e, since that is an implementation detail
for whatever library your program is linked
to. The library need not be written in C,
and can use whatever tricks it wants.

Here are some approximations for e on this implementation.
First we'll check what how good it could get.

FLT_DIG = 6, FLT_MANT_DIG/4 = 6
a double value for e might be
2.718282e+00 (decimal) 0xa.df8540p-2 (hex digits * power of 2)

DBL_DIG = 15, DBL_MANT_DIG/4 = 13
a float value for e might be
2.718281828459045e+00 (decimal) 0xa.df85458a2bb48p-2

LDBL_DIG = 18, LDBL_MANT_DIG/4 = 16
a long double value for e might be
2.718281828459045235e+00 (decimal) 0xa.df85458a2bb4a9b0p-2

Now let's look at the exp() family for some estimate
of what this implementation actually uses.

This implementation has the float version, so
let's see what expf() returns.
xf = expf(1), 2.718282e+00 0xa.df8540p-2
logf(xf) = 9.999999e-01 0xf.fffff0p-4

Now let's check the double version.
xd = exp(1), 2.718281828459045e+00 0xa.df85458a2bb48p-2
log(xd) = 1.000000000000000e+00 0x8.0000000000000p-3
 
C

CBFalconer

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. I ask as I am coparing the
respective function (C vs C#) to see if there are any differences.

e is a transcendental. It has no exact rational value.
 
K

Keith Thompson

Richard Heathfield said:
CBFalconer said:

Any approximation of e used by a C implementation, however, /does/
have an exact rational value, and this is the value he was asking
about. A better answer would be that the value used, if any,
depends on the implementation.

An even better answer (already given) is that the computation of log()
typically doesn't depend on any approximation of e.
 
D

Dik T. Winter

>
> You might well imagine that, and I suppose you would be right if
> we count people reinventing the wheel as implementors. For most
> functions, log in particular, the Taylor series is a terrible
> choice. A major reason why is that the error residual curve is
> not level.

Indeed. On the other hand, Richard Heathfield is right. In general the
approximation is based on a Taylor series, but not centered on the origin.
log(x - 1)/x gives good approximations (after range reduction, of course).
And you would of course not use the Taylor series itself, but truncated
Chebyshev series or Padé approximations or whatever. There is a lot of
literature about the approximation of special functions...
 
P

Phil Carmody

Richard Heathfield said:
CBFalconer said:


Any approximation of e used by a C implementation, however, /does/
have an exact rational value,

Not necessarily. Each pair in the mapping x -> log(x) defines an
upper and a lower bound in the reals that the the base of the
logarithm could have, and the intersection of all such ranges over
the entire domain of the mapping will either be empty or another
interval. If it's empty, then the C implementation isn't using any
consistent value for e, and should be shunned for numerical work.
If the interval you're left with contains a single representable
double, then it does make sense to claim that the implementation
does have an exact rational value, as you say. However, if the
interval contains either zero, or more than 1 representable doubles,
then such a claim is much harder to justify.
and this is the value he was asking
about. A better answer would be that the value used, if any,
depends on the implementation.

The interval does, certainly, and therefore everything that
follows from that interval. Yours is probably the simplest correct
useful answer.

Phil
 
P

Phil Carmody

Dik T. Winter said:
Dik T. Winter wrote: ...
(e-mail address removed) wrote:
Hi everyone,

Does anyone know what is the exact value of "e" that the C
language uses in the log() function. [...]
[...]
evaluate exp(1). Or you could use an
iterative method to find `x' satisfying log(x)==1.

I am quite certain that the two will not be identical, because in most
implementations of those functions the result will be perturbed by
rounding errors and you must be very lucky if they work out the same.

They're quite likely to differ, in which case the O.P.'s
question becomes "Who ya gonna believe?" It seems to me the
latter has no easy answer.

Moreover, it is almost certain that there are two different values for
which log gives exactly 1.0. So which of the two must be believed?

In any sane algorithm to calculate the logarithm 'e' itself plays no role
at all. The only irrational constant that will influence the outcome is
log(2).

Has CORDIC magically become insane in the last couple of decades?
Shifts, compares, conditional adds, all in a tight loop - what's
not to like? Apart from a bunch of irrational constants that aren't
log(2), that is?

Phil
 
D

Dik T. Winter

> On Thu, 5 Mar 2009 17:40:41 GMT, "Dik T. Winter"

>
> If you are doing a true Tchebyshev expansion you are doing the
> integrals rather converting a Taylor expansion into an equivalent
> series of Tchebyshev polynomials.

Not needed. You can use a truncated Taylor series where the truncation
error is much less than the error bound wanted (I always used a relative
error of 10^-50). The error of truncating the resulting Chebyshev series
is much larger than the initial truncation error. But you need very high
precision during the calculations of course. One thing I always did take
care of was that if the Taylor was centered on a zero of particular order
I did the approximation always on the Taylor series divided by x with the
appropriate exponent. Some people did not, resulting in an awful relative
precision near the zero.
> But then, I'm sure you know all that. The thing is, there is a
> lot of difference between the bit of algebra in elementary
> calculus and the kind of work that is needful in a quality
> function approximation. Many people don't appreciate the
> difference.

Indeed. It is good to do a thorough error analysis on your algorithm.
 
W

Walter Banks

Phil said:
Has CORDIC magically become insane in the last couple of decades?
Shifts, compares, conditional adds, all in a tight loop - what's
not to like?

There are a class of processors that CORDIC doesn't implement
well or fast on. CORDIC is not a win on many of the embedded
processors I support . On the other hand CORDIC is simple to
understand and seductive.

Been a while since I have done hard benchmarks.

Regards,
 
P

Phil Carmody

Walter Banks said:
There are a class of processors that CORDIC doesn't implement
well or fast on. CORDIC is not a win on many of the embedded
processors I support . On the other hand CORDIC is simple to
understand and seductive.

I suspect it performs reasonably well on machines with condition
codes on a wider class of operations than just branches (so ARM,
and {f,}cmov* on x86). Of course, the tightness of the loop makes
interdependencies turn into real latencies too, alas. FPU's have
certainly been the focus of an awful lot of developement in the
past few decades, and low-latency, high gate count multipliers have
become the hammer that's turned a lot of problems into nails.
Been a while since I have done hard benchmarks.

No need with long words, as the non-CORDIC algorithms scale
better. CORDIC loops on 64-bit significands may be pretty,
but leave you plenty of time to appreciate that ;-).

Phil
 
D

Dik T. Winter

>
> e is a transcendental. It has no exact rational value.

It might surprise you how many implementations of sin and cos use an
exact rational value for pi...
 

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

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,265
Latest member
TodLarocca

Latest Threads

Top