#define and preprocessor magic

B

BartC

Barry Schwarz said:
What you say is obviously true in the mathematical sense.

But in the practical sense, that doesn't seem to matter when trying to
use the values. With %30.20f, my system shows
300.02999999999997000000 and that remains unchanged even after
subtracting 2.8E-14 which should have had some effect on that 7.
Multiplying by 100 produces 30002.99999999999600000000.

I get the same kind of results using gcc. But it seems to be cutting out at
some many decimals, no matter what precision is given in the format.

So for one number where I injected a known number of '1' bits in the
mantissa, it gives:

0.999999523162841800000

but the true value should be:

0.999999523162841796875

Why doesn't it print the right value?

In any case, it must be this latter value that calculations will be done
with, not the misleading value printed by printf(). So it has practical
consequences.
 
K

Keith Thompson

Barry Schwarz said:
What you say is obviously true in the mathematical sense.

But in the practical sense, that doesn't seem to matter when trying to
use the values. With %30.20f, my system shows
300.02999999999997000000 and that remains unchanged even after
subtracting 2.8E-14 which should have had some effect on that 7.
Multiplying by 100 produces 30002.99999999999600000000.

Both serve to show that you cannot depend on the last non-zero digit
being well-behaved once you exceed DECIMAL_DIG.

It shows that you can't depend on the last non-zero digit of the output
produced by printf.

On my system (Ubuntu), this program:

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

static void print_double(double x) {
int count = 0;
printf("%d.", (int)x);
x -= (int)x;
while (x) {
x *= 10.0;
printf("%d", (int)(x));
x -= (int)x;
count ++;
if (count >= 100) {
break;
}
}
}

int main(void) {
double x = 300.03;
printf("%.50f\n", nextafter(x, 0.0));
printf("%.50f\n", x);
printf("%.50f\n", nextafter(x, 1000.0));
putchar('\n');

print_double(nextafter(x, 0.0)); putchar('\n');
print_double(x); putchar('\n');
print_double(nextafter(x, 1000.0)); putchar('\n');
return 0;
}

produces this output:

300.02999999999991587174008600413799285888671875000000
300.02999999999997271515894681215286254882812500000000
300.03000000000002955857780762016773223876953125000000

300.02999999999991587174008600413799285888671875
300.029999999999972715158946812152862548828125
300.03000000000002955857780762016773223876953125

Apparently the authors of the glibc implementation of printf went
to some effort to have it produce output with excessive precision.

The 300.02999999999997000000 you're seeing is just an artifact
of your particular printf implementation. As you can see from the
(admittedly crude) print_double() function, the actual stored values,
when interpreted precisely as decimal, end in 5.
 
H

Heikki Kallasjoki

Barry Schwarz said:
But in the practical sense, that doesn't seem to matter when trying to
use the values. With %30.20f, my system shows
300.02999999999997000000 and that remains unchanged even after
subtracting 2.8E-14 which should have had some effect on that 7.
Multiplying by 100 produces 30002.99999999999600000000.

Both serve to show that you cannot depend on the last non-zero digit
being well-behaved once you exceed DECIMAL_DIG.

It shows that you can't depend on the last non-zero digit of the output
produced by printf. [...]
Apparently the authors of the glibc implementation of printf went
to some effort to have it produce output with excessive precision.

The 300.02999999999997000000 you're seeing is just an artifact
of your particular printf implementation. As you can see from the
(admittedly crude) print_double() function, the actual stored values,
when interpreted precisely as decimal, end in 5.

For the record, the (C11) standard has some words on what you can expect
from printf, under a "Recommended practice" heading:

For e, E, f, F, g, and G conversions, if the number of significant
decimal digits is at most DECIMAL_DIG, then the result should be
correctly rounded.283) If the number of significant decimal digits is
more than DECIMAL_DIG but the source value is exactly representable
with DECIMAL_DIG digits, then the result should be an exact
representation with trailing zeros. Otherwise, the source value is
bounded by two adjacent decimal strings L < U, both having DECIMAL_DIG
significant digits; the value of the resultant decimal string D should
satisfy L <= D <= U, with the extra stipulation that the error should
have a correct sign for the current rounding direction.
(N1570 7.21.6.1p13)

Assuming a DECIMAL_DIG of 17 (reasonable for a system where the widest
float type is an IEEE-754 double), "300.02999999999997" is an output
conforming with that recommended practice: it is between the adjacent
strings with that many significant digits ("300.02999999999997" and
"300.02999999999998"), and rounded in the correct direction. (As is, of
course, the exact value apparently produced by glibc.)

(If __STDC_IEC_559__ is defined, the standard requires "IEC 60559
binary-decimal conversions" (N1570 F.3p1), which might well provide more
strict restrictions, or at least make the above requirements mandatory;
I have not checked.)
 
B

BartC

The 300.02999999999997000000 you're seeing is just an artifact
of your particular printf implementation.

There shouldn't be any 'artifact', it should produce output to the number of
digits requested in the "%f" format, not have an arbitrary cut-off point.

As your example code showed, it can't be that difficult.

(I had been relying on printf() routines to stringify floating-point values
in my projects; now it looks like I'll have to use my own code for this.)
 
B

Ben Bacarisse

BartC said:
There shouldn't be any 'artifact', it should produce output to the number of
digits requested in the "%f" format, not have an arbitrary cut-off
point.

I don't see any reason to expect more precision. The difference between
the value printed and the actual value stored was less than 1/2 in the
least significant binary digit (in fact you got 58 binary digits). One
could argue that printf need do no more than that.

One thing to test would be to see if printf and scanf are inverses --
does the binary representation produced by printf generate exactly the
same number when read back in? I don't think there is any requirement
that it should, but it's a nice property to have, and is arguably more
important than being able to print an exactly decimal from any floating
point number.
As your example code showed, it can't be that difficult.

(I had been relying on printf() routines to stringify floating-point values
in my projects; now it looks like I'll have to use my own code for
this.)

See above -- the two properties (accurate round-trip serialising and
absolutely accurate output) are not exactly the same. However, if your
printf supports C99, you might find %a suitable. It's going to be much
more efficient and, when the round-trip is done on the same hardware, I
don't think it can fail to be exact.
 
F

Fred J. Tydeman

See above -- the two properties (accurate round-trip serialising and
absolutely accurate output) are not exactly the same. However, if your
printf supports C99, you might find %a suitable. It's going to be much
more efficient and, when the round-trip is done on the same hardware, I
don't think it can fail to be exact.

Sorry, but glibc has large errors when doing the round trip of internal
floating-point to character strings and back to internal floating-point
using %a of 80-bit long double on Intel x86/x87 systems.
---
Fred J. Tydeman Tydeman Consulting
(e-mail address removed) Testing, numerics, programming
+1 (775) 287-5904 Vice-chair of PL22.11 (ANSI "C")
Sample C99+FPCE tests: http://www.tybor.com
Savers sleep well, investors eat well, spenders work forever.
 
P

Phil Carmody

BartC said:
I get the same kind of results using gcc.

GCC probably doesn't provide the implementation of printf, it's
probably in whatever C library comes with your system.
But it seems to be cutting out at
some many decimals, no matter what precision is given in the format.

So for one number where I injected a known number of '1' bits in the
mantissa, it gives:

0.999999523162841800000

but the true value should be:

0.999999523162841796875

Why doesn't it print the right value?

Probably a c library issue. What does
printf("%30.45f\n", 300.03);
give you?

gcc 4.4 on my linux/powerpc gives
300.029999999999972715158946812152862548828125000

The exact value is

? 5278183578906132/2^44.
300.02999999999997271515894681215286254882812500000

So there's nothing intrinsically wrong with gcc in attempting to print such numbers.

Phil
 
B

Ben Bacarisse

Fred J. Tydeman said:
Sorry, but glibc has large errors when doing the round trip of internal
floating-point to character strings and back to internal floating-point
using %a of 80-bit long double on Intel x86/x87 systems.

Presumably you mean %La -- using %a for long double is, technically,
undefined.

Can you give an example (with the glibc version number) because a quick
test of my own (with glibc 2.13.1) does not find any round-trip errors.
Also, it's possible the problems are related to older hardware. I'm
using a 64-bit Intel architecture.
 
K

Keith Thompson

BartC said:
There shouldn't be any 'artifact', it should produce output to the number of
digits requested in the "%f" format, not have an arbitrary cut-off point.

As your example code showed, it can't be that difficult.

(I had been relying on printf() routines to stringify floating-point values
in my projects; now it looks like I'll have to use my own code for this.)

Your "should" is really a matter of opinion (not that there's
anything wrong with having an opinion). Both results are permitted
by the standard.

If you specify enough digits, sprintf() should give you enough
precision to let you use sscanf() or strtod() to recover the exact
value. I *think* the standard guarantees that, but I'm not certain.

But as someone else mentioned elsethread, "%a" should give you an
exact representation (though it's not very human-readable).
 
B

BartC

Phil Carmody said:
Probably a c library issue. What does
printf("%30.45f\n", 300.03);
give you?

gcc 4.4 on my linux/powerpc gives
300.029999999999972715158946812152862548828125000

The exact value is

? 5278183578906132/2^44.
300.02999999999997271515894681215286254882812500000

I get:

300.029999999999970000000000000000000000000000000

using (mingw) gcc 4.5.0 on Windows. I'd prefer to get what you did..

However DMC gives:

300.029999999999972710000000000000000000000000000

a few extra digits (but it seems incorrectly rounded down on the last
digit). And Pelles C gives:

300.029999999999953433870000000000000000000000000

which is not quite right. Finally, lcc-win32 gives:

300.030000000000000000000000000000000000000000000

which is either wildly inaccurate, or the only one that is spot on!
 
F

Fred K

"Phil Carmody" <[email protected]> wrote in message news:[email protected]... > "BartC" <[email protected]> writes: >> Why doesn't it print the right value? > > Probably a c library issue. What does > printf("%30.45f\n", 300.03); > give you? > > gcc 4.4 on my linux/powerpc gives > 300.029999999999972715158946812152862548828125000 > > The exact value is > > ? 5278183578906132/2^44. > 300.02999999999997271515894681215286254882812500000 I get: 300.029999999999970000000000000000000000000000000 using (mingw) gcc 4.5.0 on Windows. I'd prefer to get what you did.. HoweverDMC gives: 300.029999999999972710000000000000000000000000000 a few extra digits (but it seems incorrectly rounded down on the last digit). And PellesC gives: 300.029999999999953433870000000000000000000000000 which is not quite right. Finally, lcc-win32 gives: 300.030000000000000000000000000000000000000000000 which is either wildly inaccurate, or the only one that is spoton! -- Bartc


What does this get on those platforms (especially lcc-win32)?

printf("%30.45f\n", 300.02999999999997);
 
B

BartC

What does this get on those platforms (especially lcc-win32)?

printf("%30.45f\n", 300.02999999999997);

gcc:
300.029999999999970000000000000000000000000000000

lcc-win32:
300.030000000000000000000000000000000000000000000

DMC:
300.029999999999972710000000000000000000000000000

Pelles C:
300.030000000000046566120000000000000000000000000

So all the same as "300.03" except for the last.
 
N

Nick Keighley

It's likely to have "5" as the last digit...

why? I'm pretty sure this isn't so, but I'm interested in what made
you think that.
If by "every programmer", you mean somebody who might have any kind
of programming task thrown at them, then the knowledge is definitely
helpful,

not really. You can go a long way without much use of floating point.
"what every computer scientist needs to know" is not exactly a light
read. The essential lessons "many numbers (notably 0.1) cannot be
represented in binary FP systems" and "many FP operations loose
precision" "corollary don't test two FP numbers for equality" are most
of what you need to know.

I'd just add FP arithmetic (like cryptography) shouldn't be attempted
without the support of a mathematical safety net (ie. knowing what you
are doing).
in at least you'll know why your financial application is
possibly giving wrong answers, but there's not enough information
there to actually proactively fix the problem, so just another busted
program, but you get paid the same amount anyway, so who cares except
the user...

good grief.
 
H

hormelfree

why? I'm pretty sure this isn't so,

How sure are you? Oh, that's right, "pretty"...
but I'm interested in what made you think that.

Sheesh...
not really. You can go a long way without much use of floating point.

Sheesh...
"what every computer scientist needs to know" is not exactly a light read..

Sheesh...actually, it's about 8th-grade level math, but then I had to
get all the way to the 11th grade to flunk out of a math class...
The essential lessons "many numbers (notably 0.1) cannot be represented in
binary FP systems" and "many FP operations loose precision" "corollary don't > test two FP numbers for equality" are most of what you need to know.

As always, the most important thing to know is what you don't know...this
is a very large body of knowledge for many programmers...
I'd just add FP arithmetic (like cryptography) shouldn't be attempted without > the support of a mathematical safety net (ie. knowing what you are doing).

Knowing what you are doing is ALWAYS important, but how often does
THAT happen?
good grief.

Good grief indeed...I still remember the second time I used a computer
several decades ago. A friend of mine worked for one of the first companies
to make "home" computers, and as a prelude to me getting hired there, he
gave me an overview of their computers one night.

The computer had a "user-friendly" feature that allowed you to use it
as a calculator from the command line. So I typed in "2+2" and got the
answer "3.975" or some such nonsense. Neither one of us liberal arts
majors knew at the time why it gave such a strange answer, and obviously
neither did the idiot programmer who developed the feature (of course,
it wasn't really a "calculator" since actual calculators use binary-coded
decimal or similar).

Then a few years back I got a financial application for a trial run
and had to decide not to purchase when a calculation that should have
returned the value "100.00" actually returned "99.9999875" or some
such nonsense, so it was clear that 20 years of time hadn't made the
average working programmer any smarter...
 
G

glen herrmannsfeldt

(snip)
why? I'm pretty sure this isn't so, but I'm interested in what made
you think that.

When I binary fraction (power of two in the denominator) is written
as a decimal fraction (power of ten in the denominator) the numerator
has lots of fives as factors, and powers of five tend to end in "5".

Consider pow(2.,-n) (I almost wrote 2.**(-n) but then remembered...)

Going down in n, 0.5, 0.25, 0.125. 0.0625, 0.03125, 0.015625,
each one is the next higher power of five, with the decimal point
moved over one more position.

I have wondered why the usual US measurement system uses strange
multiples (12 inches per foot, 5280 feet/mile) but binary fractions
for less than an inch.

(Drill bits come in 1/16, 3/32, 1/8, 5/32, 3/16, 7/32, 1/4 inch.
Biggers sets in multiples of 1/64th inch. All nice binary fractions.

-- glen
 
E

Eric Sosman

why? I'm pretty sure this isn't so, but I'm interested in what made
you think that.

Consider a decimal fraction whose rightmost non-zero
digit is *not* five. Multiply that fraction by a suitable
power of ten so the rightmost non-zero is now in the tenth's
place. The product is

[integer] + {1,2,3,4,6,7,8,9}/10

Your mission, should you choose to accept it, is to represent
all eight possible fractions in binary, that is, as quotients
of the form N/2^K for positive integer N and K. Good luck, Nick,
and if you or any of your team experience numerical frustration,
the Secretary will disavow all knowledge.
 
R

ralph

(snip)


When I binary fraction (power of two in the denominator) is written
as a decimal fraction (power of ten in the denominator) the numerator
has lots of fives as factors, and powers of five tend to end in "5".

Consider pow(2.,-n) (I almost wrote 2.**(-n) but then remembered...)

Going down in n, 0.5, 0.25, 0.125. 0.0625, 0.03125, 0.015625,
each one is the next higher power of five, with the decimal point
moved over one more position.

I have wondered why the usual US measurement system uses strange
multiples (12 inches per foot, 5280 feet/mile) but binary fractions
for less than an inch.

(Drill bits come in 1/16, 3/32, 1/8, 5/32, 3/16, 7/32, 1/4 inch.
Biggers sets in multiples of 1/64th inch. All nice binary fractions.

You basically stubbled on your own answer.

It has only been recently (in terms of history) that measurements
could be made in hundreds and even tens.

For most of recorded history, machine shops had to create their own
tools. Imagine for a moment you needed to create your own scale
(ruler) and all you had was a few scales (very expensive) where one
often could only accurately determine an "inch" as equal to your
neighbor's "inch". How would you mark it off?

By halving. Easily done using compass and care, anything else is an
adventure. (Try trisecting an angle. or five-secting a span. <g>)

The key to the mile is not the feet/mile but yards to mile (1760).
That gives use 880 yards to a half section. 440 yards to the quarter,
.... . All easier to mark off using the simple tools of the time.

-ralph
 
B

BartC

It has only been recently (in terms of history) that measurements
could be made in hundreds and even tens.

For most of recorded history, machine shops had to create their own
tools. Imagine for a moment you needed to create your own scale
(ruler) and all you had was a few scales (very expensive) where one
often could only accurately determine an "inch" as equal to your
neighbor's "inch". How would you mark it off?

By halving. Easily done using compass and care, anything else is an
adventure. (Try trisecting an angle. or five-secting a span. <g>)

Dividing a straight line into N equal sections is trivial, although you
might need a setsquare in addition to ruler, compass and pencil. (However a
setsquare can be constructed by marking up some material using a ruler,
compass and pencil, so it's not essential.)
 
B

Ben Bacarisse

ralph said:
The key to the mile is not the feet/mile but yards to mile (1760).
That gives use 880 yards to a half section. 440 yards to the quarter,
... . All easier to mark off using the simple tools of the time.

Your point about small units being divided is a good one, but it's the
very fact that you can add any number of units easily that has given
rise to these crazy systems -- crazy because there's a factor of 11 in
there.

The key to the mile is actually the furlong -- it was defined by statute
to be eight furlongs, with a furlong being 40 poles. All sane(ish)
except that a pole is 16 1/2 feet. Yes, 16 1/2. It's that 16 1/2 gives
rise to the 11.
 

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,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top