Machine epsilon: conclusion

J

jacob navia

Following the discussion about the machine epsilon, I have modified the
text as follows. I thank all people that contributed. It was
interesting, and I surely learned stuff I did not consider before.
--------------------------------------------------------------
The machine epsilon
-------------------
The standard defines for each floating point representation (float,
double, long double) the difference between 1 and the least value
greater than 1 that is representable in the given floating point type.
In IEEE754 representation this number has an exponent value of the bias,
and a fraction of 1. In hexadecimal notation this would be
0x1p-52
Another way to define this quantity in terms of the mathematical
functions of the C library is:

DBL_EPSILON = nextafter(1.0,2.0) - 1.0;

For the different representations we have in the standard header <float.h>:

#define FLT_EPSILON 1.19209290e-07F // float
#define DBL_EPSILON 2.2204460492503131e-16 // double
#define LDBL_EPSILON 1.084202172485504434007452e-19L //long double
// qfloat epsilon truncated so that it fits in this page...
#define QFLT_EPSILON 1.09003771904865842969737513593110651 ... E-106

These definitions (except the qfloat part) are part of the C99 ANSI
standard. For the standard types (float, double and long double) they
should always exist in other compilers.

Here is a program that will find out the machine epsilon for a given
floating point representation.

#include <stdio.h>
int main(void)
{
double float_radix=2.0;
double inverse_radix = 1.0/float_radix;
double machine_precision = 1.0;
double temp = 1.0 + machine_precision;

while (temp != 1.0) {
machine_precision *= inverse_radix;
temp = 1.0 + machine_precision ;
printf("%.17g\n",machine_precision);
}
return 0;
}
Exercises:
1: Explain why in the above program, the value of DBL_EPSILON is not the
last number but the number before.
2: An alternative version of the above program is:
#include <stdio.h>
int main(void)
{
volatile double oneplus = 2, epsilon = 1;
while (1 + epsilon/2 > 1) {
epsilon /= 2;
oneplus = 1 + epsilon;
}
epsilon = oneplus - 1;
printf("DBL_EPSILON is %g\n", epsilon);
return 0;
}

Explain why this program prints

DBL_EPSILON is 0

in lcc-win32.
 
R

Richard Heathfield

jacob navia said:

For the different representations we have in the standard header
<float.h>:

#define FLT_EPSILON 1.19209290e-07F // float
#define DBL_EPSILON 2.2204460492503131e-16 // double
#define LDBL_EPSILON 1.084202172485504434007452e-19L //long double
// qfloat epsilon truncated so that it fits in this page...
#define QFLT_EPSILON 1.09003771904865842969737513593110651 ... E-106

You have the same bug as last time. No standard-conforming
implementation may define QFLT_EPSILON in the standard header
<float.h>, as I pointed out to you earlier this week.
 
R

Richard Tobin

#define QFLT_EPSILON 1.09003771904865842969737513593110651 ... E-106
[/QUOTE]
You have the same bug as last time. No standard-conforming
implementation may define QFLT_EPSILON in the standard header
<float.h>, as I pointed out to you earlier this week.

Jacon already described how to suppress this definition if required.

-- Richard
 
A

Army1987

jacob navia said:
Following the discussion about the machine epsilon, I have modified the
text as follows. I thank all people that contributed. It was interesting, and I surely learned stuff I did not consider before.
Have you already explained that "a fraction of 1" actually means
"a significand of 1.00000000000000000000000000000000000000000000000000001" ?

In hexadecimal notation this would be
0x1p-52
Another way to define this quantity in terms of the mathematical functions of the C library is:

DBL_EPSILON = nextafter(1.0,2.0) - 1.0;

For the different representations we have in the standard header <float.h>:

#define FLT_EPSILON 1.19209290e-07F // float
#define DBL_EPSILON 2.2204460492503131e-16 // double
#define LDBL_EPSILON 1.084202172485504434007452e-19L //long double
// qfloat epsilon truncated so that it fits in this page...
#define QFLT_EPSILON 1.09003771904865842969737513593110651 ... E-106

These definitions (except the qfloat part) are part of the C99 ANSI standard. For the standard types (float, double and long
double) they should always exist in other compilers.
Add: "For the qfloat type, it invades the user name space, since I
was too lazy to call it _QFLT_EPSILON." Also you should explain by
which magic it doesn't have type double. (If it is because of the
capital E, I don't think anything in the Standard allows you to
treat it differently from a lowercase e).
Here is a program that will find out the machine epsilon for a given floating point representation.

#include <stdio.h>
int main(void)
{
double float_radix=2.0; Who says thay?
double inverse_radix = 1.0/float_radix;
double machine_precision = 1.0;
double temp = 1.0 + machine_precision;

while (temp != 1.0) {
machine_precision *= inverse_radix;
temp = 1.0 + machine_precision ;
printf("%.17g\n",machine_precision);
}
return 0;
}
Exercises:
1: Explain why in the above program, the value of DBL_EPSILON is not the last number but the number before.
2: An alternative version of the above program is:
#include <stdio.h>
int main(void)
{
volatile double oneplus = 2, epsilon = 1;
while (1 + epsilon/2 > 1) {
epsilon /= 2;
oneplus = 1 + epsilon;
}
epsilon = oneplus - 1;
printf("DBL_EPSILON is %g\n", epsilon);
return 0;
}

Explain why this program prints

DBL_EPSILON is 0

in lcc-win32.
Because its author tested it with MSVC. :)
(It also prints DBL_EPSILON is 0 with gcc -ansi -pedantic and with gcc -std=c99 -pedantic. The reason is that the left operand of <
is stored in a register which is wider than double, so epsilon gets
halved several other times.)
#include <stdio.h>
#include <stdio.h>
int main(void)
{
volatile double oneplus = 2, epsilon = 1;
while ((oneplus = 1 + epsilon/2) > 1) {
epsilon /= 2;
}
oneplus = 1 + epsilon;
epsilon = oneplus - 1;
printf("DBL_EPSILON is %g\n", epsilon);
return 0;
}
works, provided FLT_RADIX is a power of two.
 
R

Richard Tobin

Add: "For the qfloat type, it invades the user name space, since I
was too lazy to call it _QFLT_EPSILON."

I'm not convinced about this. Using a leading underscore on names
intended for the user (rather than the implementation) is not helpful
to the user who wants to use the extensions. We don't see Posix using
underscored identifiers for everything. A better plan is to provide a
switch to disable it. This works perfectly for generic C code.

It might be better to have a single #define of an underscored name -
perhaps _LCC_EXTENSIONS - to control all lcc's extensions, as that
allows the user to turn it on or off for individual include files.

-- Richard
 
A

Army1987

You have the same bug as last time. No standard-conforming
implementation may define QFLT_EPSILON in the standard header
<float.h>, as I pointed out to you earlier this week.

Jacon already described how to suppress this definition if required.[/QUOTE]

Couldn't simplily he call it _QFLT_EPSILON? The standard doesn't
forbid implementation-defined types.
 
S

Serve Lau

Richard Tobin said:
I'm not convinced about this. Using a leading underscore on names
intended for the user (rather than the implementation) is not helpful
to the user who wants to use the extensions. We don't see Posix using
underscored identifiers for everything. A better plan is to provide a
switch to disable it. This works perfectly for generic C code.

I agree. A good example is microsoft visualC++. They added keywords with
double underscores for .NET. But users complained so much about the ugliness
of the code that they switched to "normal" names in the next version
 
F

Flash Gordon

Richard Tobin wrote, On 30/06/07 16:26:
I'm not convinced about this. Using a leading underscore on names
intended for the user (rather than the implementation) is not helpful
to the user who wants to use the extensions. We don't see Posix using
underscored identifiers for everything.

Most Unix extensions are not in the C standard headers, rather they are
provided in additional headers. Jacob could have provided a qfloat.h
header, for example, without problem.
> A better plan is to provide a
switch to disable it. This works perfectly for generic C code.

I agree that a switch to disable it is a good thing.
It might be better to have a single #define of an underscored name -
perhaps _LCC_EXTENSIONS - to control all lcc's extensions, as that
allows the user to turn it on or off for individual include files.

Here you are suggesting using a leading underscore for a name intended
for the user ;-)
 
E

Eric Sosman

jacob said:
Following the discussion about the machine epsilon, I have modified the
text as follows. I thank all people that contributed. It was
interesting, and I surely learned stuff I did not consider before.
--------------------------------------------------------------
The machine epsilon
-------------------
The standard defines for each floating point representation (float,
double, long double) the difference between 1 and the least value
greater than 1 that is representable in the given floating point type.
In IEEE754 representation this number has an exponent value of the bias,
and a fraction of 1. [...]

It's been mentioned before, but what do you mean by "the bias?"
If you mean the offset added to the exponent's numerical value to
produce the encoded value, that's wrong. If you mean something
else, it would be as well to explain what you mean.
 
S

Serve Lau

Flash Gordon said:
Most Unix extensions are not in the C standard headers, rather they are
provided in additional headers. Jacob could have provided a qfloat.h
header, for example, without problem.


I agree that a switch to disable it is a good thing.


Here you are suggesting using a leading underscore for a name intended for
the user ;-)

The identifier is provided by the implementation, so theres no problem
 
J

jacob navia

Eric said:
jacob said:
Following the discussion about the machine epsilon, I have modified the
text as follows. I thank all people that contributed. It was
interesting, and I surely learned stuff I did not consider before.
--------------------------------------------------------------
The machine epsilon
-------------------
The standard defines for each floating point representation (float,
double, long double) the difference between 1 and the least value
greater than 1 that is representable in the given floating point type.
In IEEE754 representation this number has an exponent value of the
bias, and a fraction of 1. [...]

It's been mentioned before, but what do you mean by "the bias?"
If you mean the offset added to the exponent's numerical value to
produce the encoded value, that's wrong. If you mean something
else, it would be as well to explain what you mean.

You are right again. Actually, the bias is 1023, and the value is
971.

#include <stdio.h>
#include <float.h>
int main(void)
{
double d = DBL_EPSILON;
int *p = (int *)&d;

printf("%a\n",DBL_EPSILON);
printf("0x%x 0x%x\n",p[0],p[1]);
}
0x1.000000p-52
0x0 0x3cb00000
3cb == 971
971-1023 --> -52
2 ^-52 --> 2.2204460492503130808472633361816e-16 -->DBL_EPSILON.

Similar calculations can be done for the other types. I will correct
this.
 
J

jacob navia

Richard said:
jacob navia said:



You have the same bug as last time. No standard-conforming
implementation may define QFLT_EPSILON in the standard header
<float.h>, as I pointed out to you earlier this week.

I have told you thousand times that this can be disabled
by using -ansic.

All extensions are disabled with -ansic, except _stdcall
 
R

Richard Heathfield

jacob navia said:
I have told you thousand times that this can be disabled
by using -ansic.

You don't seem to understand my point, which is that you are describing
<float.h> as a *standard header*, and yet you *also* describe it as
containing QFLT_EPSILON. It can't *both* be a standard header *and*
contain QFLT_EPSILON at the same time. If it is a standard header, it
does not contain QFLT_EPSILON. If it contains QFLT_EPSILON, it is not a
standard header. Your claim that QFLT_EPSILON is in a standard header
is simply wrong, switch or no switch.
 
R

Richard Heathfield

Richard Tobin said:
You have the same bug as last time. No standard-conforming
implementation may define QFLT_EPSILON in the standard header
<float.h>, as I pointed out to you earlier this week.

Jacon already described how to suppress this definition if required.[/QUOTE]

Either it's a standard header (as he claims), or it isn't. If it's a
standard header, it cannot contain QFLT_EPSILON. If it contains
QFLT_EPSILON, it can't be a standard header.
 
C

CBFalconer

jacob said:
Richard Heathfield wrote:
.... snip ...


I have told you thousand times that this can be disabled
by using -ansic.

All extensions are disabled with -ansic, except _stdcall

What has this to do with the C language? I thought lcc-win32
discussions were to be placed on the comp.compilers.lcc newsgroup?
 
J

jacob navia

Richard said:
jacob navia said:


You don't seem to understand my point, which is that you are describing
<float.h> as a *standard header*, and yet you *also* describe it as
containing QFLT_EPSILON. It can't *both* be a standard header *and*
contain QFLT_EPSILON at the same time. If it is a standard header, it
does not contain QFLT_EPSILON. If it contains QFLT_EPSILON, it is not a
standard header. Your claim that QFLT_EPSILON is in a standard header
is simply wrong, switch or no switch.

The compiler you use has a file called
"math.h"

There, I can read

# define M_E 2.7182818284590452354 /* e */
# define M_LOG2E 1.4426950408889634074 /* log_2 e */
# define M_LOG10E 0.43429448190325182765 /* log_10 e */
# define M_LN2 0.69314718055994530942 /* log_e 2 */
# define M_LN10 2.30258509299404568402 /* log_e 10 */
# define M_PI 3.14159265358979323846 /* pi */
# define M_PI_2 1.57079632679489661923 /* pi/2 */
# define M_PI_4 0.78539816339744830962 /* pi/4 */
# define M_1_PI 0.31830988618379067154 /* 1/pi */
# define M_2_PI 0.63661977236758134308 /* 2/pi */
# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */

but that doesn't bother you since when you call that compiler
with the needed flags, those definitions do not appear.

When I do exactly the same you will argue without end.

The fact that my compiler is the only C compiler giving to the user
105 digits floating point precision is not important to you.

Polemic, polemic without end, but you did not contribute anything
to this discussion.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

CBFalconer said:
What has this to do with the C language? I thought lcc-win32
discussions were to be placed on the comp.compilers.lcc newsgroup?

The fact that QFLT_EPSILON is /not/ defined in a compiler's conforming mode
is not specific to lcc-win32.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Richard said:
Richard Tobin said:


Either it's a standard header (as he claims), or it isn't. If it's a
standard header, it cannot contain QFLT_EPSILON. If it contains
QFLT_EPSILON, it can't be a standard header.

The C99 rationale section 7.1.2 gives an example of how it can, and there is
nothing whatsoever in the standard that contradicts it.
 
K

Keith Thompson

jacob navia said:
Following the discussion about the machine epsilon, I have modified the
text as follows. I thank all people that contributed. It was
interesting, and I surely learned stuff I did not consider before.

It's good to see you responding well to criticism. This is a great
improvement over your recent "Jacob is always wrong" whining. Please
keep it up.
--------------------------------------------------------------
The machine epsilon
-------------------
The standard defines for each floating point representation (float,
double, long double) the difference between 1 and the least value
greater than 1 that is representable in the given floating point
type. In IEEE754 representation this number has an exponent value of
the bias, and a fraction of 1. In hexadecimal notation this would be
0x1p-52

Which representation does this apply to? There are several IEEE 754
representations (and I'd definitely put a space between IEEE and 754).

You should mention that the current name for that standard is IEC
60559; that's how the C standard refers to it. See C99 F.1p1.

You should also mention explicitly that the C standard does not
require IEC 60559 conformance; it merely provides optional support for
those implementations that do conform to it.

[...]
These definitions (except the qfloat part) are part of the C99 ANSI
standard. For the standard types (float, double and long double) they
should always exist in other compilers.

Why do you refer to the ISO C99 standard as "ANSI"?

[snip]
 
R

Richard Heathfield

jacob navia said:
The compiler you use has a file called
"math.h"

I use several implementations. Each of them is required to provide a
There, I can read

# define M_E 2.7182818284590452354 /* e */
# define M_LOG2E 1.4426950408889634074 /* log_2 e */
# define M_LOG10E 0.43429448190325182765 /* log_10 e */
# define M_LN2 0.69314718055994530942 /* log_e 2 */
# define M_LN10 2.30258509299404568402 /* log_e 10 */
# define M_PI 3.14159265358979323846 /* pi */
# define M_PI_2 1.57079632679489661923 /* pi/2 */
# define M_PI_4 0.78539816339744830962 /* pi/4 */
# define M_1_PI 0.31830988618379067154 /* 1/pi */
# define M_2_PI 0.63661977236758134308 /* 2/pi */
# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */

but that doesn't bother you since when you call that compiler
with the needed flags, those definitions do not appear.

If the implementation is not invoked with the needed flags, however,
then the above definitions in <math.h> render it a non-standard header.
It cannot both be a standard header *and* contain, say, M_PI. If it
contains M_PI, it is not a standard header. If it is a standard header,
it cannot contain M_PI.
When I do exactly the same you will argue without end.

Yes, because you're wrong.
The fact that my compiler is the only C compiler giving to the user
105 digits floating point precision is not important to you.

I have no idea whether that claim is true, and you're right that it
isn't the least bit important to me. I'm not talking about how much
floating point precision an implementation offers. I'm talking about
the incorrect claim that QFLT_EPSILON can be defined in a standard
header. It's simply wrong, Mr Navia.
Polemic, polemic without end, but you did not contribute anything
to this discussion.

I contributed a correction to your broken C tutorial. I even contributed
it twice, since you didn't seem to understand it the first time. Having
said that, you didn't understand it the second time either.

If you choose not to make the correction, that's up to you, but for as
long as it contains errors, your tutorial is still broken. Just how
broken it is depends on how many errors it contains. If your attitude
to error reports is that they do not represent a contribution, then
your tutorial is likely to contain many errors, and be very broken.
 

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,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top