Thread overview
weird behavior for machine epsilon in float, double and real
Apr 11, 2009
Andrew Spott
Apr 11, 2009
bearophile
Apr 11, 2009
BCS
Apr 11, 2009
Walter Bright
April 11, 2009
So, for the following code, I get something I think is a little off.  I get the same value for all three variable types.  I'm kind of new to this, but I would think that a 32 bit would give me a different "smallest value" than a 64 bit or 80 bit (if real even evaluates to 80 bit on my machine).

What am I doing wrong, or is this a bug?

import std.stdio;

void main() {

	//Find Machine Epsilon:

	double ep = 1.0;
	double n = 1.0;

	while (ep + n != n) {
		ep = ep / 2;
	}

	writefln(ep);

	real epr = 1.0;
	real nr = 1.0;

	while (epr + nr != nr)
		epr = epr / 2;

	writefln(epr);

	float epf = 1.0;
	float nf = 1.0;

	while (epf + nf != nf)
		epf = epf / 2;

	writefln(epr);
}
April 11, 2009
Andrew Spott:
> import std.stdio;
> [...]

This is the same code of yours, a bit refactored:

import std.stdio: writefln;

template Tuple(T...) { alias T Tuple; }

void computeEpsilon(T)() {
    T ep = 1;
    T n = 1;

    while ((ep + n) != n)
        ep /= 2;

    writefln("%.30f type: %s", ep, typeid(T));
}

void main() {
    foreach (T; Tuple!(float, double, real))
        computeEpsilon!(T)();
}

Bye,
bearophile
April 11, 2009
Hello Andrew,

> So, for the following code, I get something I think is a little off.
> I get the same value for all three variable types.  I'm kind of new to
> this, but I would think that a 32 bit would give me a different
> "smallest value" than a 64 bit or 80 bit (if real even evaluates to 80
> bit on my machine).
> 
> What am I doing wrong, or is this a bug?
> 

This is a classic case of the optimizer getting in your way by doing all the math in the FPU (the other classic cases is it noting that as long as ep!=0, ep+n "can't" equal n). If you are on x86 than the only type the FPU uses inside is 80bit-real.


> import std.stdio;
> 
> void main() {
> 
> //Find Machine Epsilon:
> 
> double ep = 1.0;
> double n = 1.0;
> while (ep + n != n) {
> ep = ep / 2;
> }
> writefln(ep);
> 
> real epr = 1.0;
> real nr = 1.0;
> while (epr + nr != nr)
> epr = epr / 2;
> writefln(epr);
> 
> float epf = 1.0;
> float nf = 1.0;
> while (epf + nf != nf)
> epf = epf / 2;
> writefln(epr);
> }


April 11, 2009
Andrew Spott wrote:
> So, for the following code, I get something I think is a little off.
> I get the same value for all three variable types.  I'm kind of new
> to this, but I would think that a 32 bit would give me a different
> "smallest value" than a 64 bit or 80 bit (if real even evaluates to
> 80 bit on my machine).
> 
> What am I doing wrong, or is this a bug?

The expression: (ep + n != n) is evaluated at 80 bit precision, regardless of the size of its operands. The idea is that the floating point sizes only specify a minimum precision, and the compiler (where it makes sense) can use a larger precision to do constant folding and/or for intermediate values.

If you need the epsilon values, use float.epsilon, double.epsilon, and real.epsilon.