Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > #define and preprocessor magic

Reply
Thread Tools

#define and preprocessor magic

 
 
BartC
Guest
Posts: n/a
 
      11-16-2012
"Barry Schwarz" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On Thu, 15 Nov 2012 12:16:49 -0800, Keith Thompson <(E-Mail Removed)>


>>As far as I can see, the last non-zero digit in the exact decimal
>>representation of a representable floating-point number is always
>>5 unless the number is an exact integer. (All such numbers are an
>>integer multiple of a power of 2.0.)
>>
>>You can see this using printf() *if* you use enough digits *and*
>>the printf() implementation prints exact values.

>
> 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.

--
Bartc

 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      11-16-2012
Barry Schwarz <(E-Mail Removed)> writes:
> On Thu, 15 Nov 2012 12:16:49 -0800, Keith Thompson <(E-Mail Removed)>
> wrote:
>>Barry Schwarz <(E-Mail Removed)> writes:
>>> On Thu, 15 Nov 2012 05:04:44 -0800 (PST), http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
>>>>On Tuesday, November 13, 2012 5:43:13 AM UTC-8, Ben Bacarisse wrote:
>>>>> Marcin Lukasik <(E-Mail Removed)> writes:
>>>>> > But does this mean that VALUE(2) stores 300.029999 or 300.03?
>>>>> Neither! It is stored as the closest floating point number to 300.03. Exactly
>>>>> what that is is probably not important to you, but you can work it out if you
>>>>> really need to know.
>>>>
>>>>It's likely to have "5" as the last digit...
>>>
>>> Not on any IEEE system where double is 8 bytes.

>>
>>Oh?
>>
>>As far as I can see, the last non-zero digit in the exact decimal
>>representation of a representable floating-point number is always
>>5 unless the number is an exact integer. (All such numbers are an
>>integer multiple of a power of 2.0.)
>>
>>You can see this using printf() *if* you use enough digits *and*
>>the printf() implementation prints exact values.

>
> 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.0299999999999158717400860041379928588867187500 0000
300.0299999999999727151589468121528625488281250000 0000
300.0300000000000295585778076201677322387695312500 0000

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.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Heikki Kallasjoki
Guest
Posts: n/a
 
      11-16-2012
On 2012-11-16, Keith Thompson <(E-Mail Removed)> wrote:
> Barry Schwarz <(E-Mail Removed)> writes:
>> 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.)

--
Heikki Kallasjoki
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      11-16-2012
"Keith Thompson" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Barry Schwarz <(E-Mail Removed)> writes:


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


> 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.)

--
Bartc

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-16-2012
"BartC" <(E-Mail Removed)> writes:

> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Barry Schwarz <(E-Mail Removed)> writes:

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

>
>> 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.


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.

--
Ben.
 
Reply With Quote
 
Fred J. Tydeman
Guest
Posts: n/a
 
      11-16-2012
On Fri, 16 Nov 2012 12:13:11 UTC, Ben Bacarisse <(E-Mail Removed)> wrote:

> 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 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.
 
Reply With Quote
 
Phil Carmody
Guest
Posts: n/a
 
      11-16-2012
"BartC" <(E-Mail Removed)> writes:
> "Barry Schwarz" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
> > On Thu, 15 Nov 2012 12:16:49 -0800, Keith Thompson <(E-Mail Removed)>

>
> >>As far as I can see, the last non-zero digit in the exact decimal
> >>representation of a representable floating-point number is always
> >>5 unless the number is an exact integer. (All such numbers are an
> >>integer multiple of a power of 2.0.)
> >>
> >>You can see this using printf() *if* you use enough digits *and*
> >>the printf() implementation prints exact values.

> >
> > 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.


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.0299999999999727151589468121528625488281250000 0

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

Phil
--
Regarding TSA regulations:
How are four small bottles of liquid different from one large bottle?
Because four bottles can hold the components of a binary liquid explosive,
whereas one big bottle can't. -- camperdave responding to MacAndrew on /.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-16-2012
"Fred J. Tydeman" <(E-Mail Removed)> writes:

> On Fri, 16 Nov 2012 12:13:11 UTC, Ben Bacarisse <(E-Mail Removed)> wrote:
>
>> 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.


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.

--
Ben.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-16-2012
"BartC" <(E-Mail Removed)> writes:
> "Keith Thompson" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> Barry Schwarz <(E-Mail Removed)> writes:

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

>
>> 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.)


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).

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      11-16-2012
"Phil Carmody" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> "BartC" <(E-Mail Removed)> 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.0299999999999727151589468121528625488281250000 0


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!

--
Bartc

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Preprocessor magic needed claus.tondering@gmail.com C++ 8 03-20-2006 10:52 AM
Preprocessor magic needed claus.tondering@gmail.com C Programming 8 03-20-2006 10:52 AM
Compiler error occurred when try to use a flexible template expression in preprocessor definesCompiler error occurred when try to use a flexible template expression in preprocessor defines snnn C++ 6 03-14-2005 04:09 PM
preprocessor, token concatenation, no valid preprocessor token Cronus C++ 1 07-14-2004 11:10 PM



Advertisments