mismatch between Perl 5.6 and Perl 5.8 in printing high precisionvalues.

  • Thread starter vivekanand.naik
  • Start date
V

vivekanand.naik

printf("%.32g\n",0.99999999976716936);

Perl 5.6.1 output:
0.99999999976716936 --> GOOD

Perl 5.8.6 output:
0.99999999976716925 --> ERROR


Any reason for such mismatch ?
Please let me know how to avoid that or any alternative approach if
any.

Thanks
Vivek
 
R

RedGrittyBrick

printf("%.32g\n",0.99999999976716936);

Perl 5.6.1 output:
0.99999999976716936 --> GOOD

Perl 5.8.6 output:
0.99999999976716925 --> ERROR


Any reason for such mismatch ?
Please let me know how to avoid that or any alternative approach if
any.

print Math::BigFloat->new("0.99999999976716936")->bstr();
 
M

Mirco Wahab

printf("%.32g\n",0.99999999976716936);

Perl 5.6.1 output:
0.99999999976716936 --> GOOD

Perl 5.8.6 output:
0.99999999976716925 --> ERROR
Any reason for such mismatch ?
Please let me know how to avoid that or any alternative approach if
any.

This is in the interval from 1e-16 to 1e-15, which
is the accuracy of a IEEE 8 byte double in this
number range (52 bits for fraction). Seems to
be ok ==> 1 / (2^52).
The correct result (above) needs (imho) longer
than 8 byte doubles, like

perl -MMath::BigFloat -e'print Math::BigFloat->new("0.99999999976716936")->bstr()'


Regards

M.
 
S

sisyphus

printf("%.32g\n",0.99999999976716936);

Perl 5.6.1 output:
0.99999999976716936  --> GOOD

Perl 5.8.6 output:
0.99999999976716925  --> ERROR

Any reason for such mismatch ?

I believe it's a bug in perl 5.8 (which has been carried through to
perl 5.10):

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",0.99999999976716936);"
0.99999999976716925

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716936

Since 0.99999999976716936 == 9.9999999976716936e-1, I can think of no
good reason that that those 2 one-liners should produce different
output - and I believe the first one liner produces an incorrect
result.

I'll submit a bug report about this - unless someone can convince me
that it's *not* a bug (or unless someone else wants to submit the
report).

Cheers,
Rob
 
M

Mirco Wahab

sisyphus said:
I believe it's a bug in perl 5.8 (which has been carried through to
perl 5.10):
C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",0.99999999976716936);"
0.99999999976716925
C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716936

Since 0.99999999976716936 == 9.9999999976716936e-1, I can think of no
good reason that that those 2 one-liners should produce different
output - and I believe the first one liner produces an incorrect
result.

I'll submit a bug report about this - unless someone can convince me
that it's *not* a bug (or unless someone else wants to submit the
report).

Seems to be dependend on the underlying C library
implementation. Consider the following program round.c:
----- [round.c] -----
#include "stdio.h"
int main() {
printf("0.99999999976716936\n");
printf("%.32g | %.36f\n", 0.99999999976716936, 0.99999999976716936);
printf("%.32g | %.36f (%s)\n",9.9999999976716936e-1,9.9999999976716936e-1,"sisyphus");
return 0;
}
--------------------

Results:
=========
Linux/gcc: gcc-4.3 -o round round.c ; ./round

0.99999999976716936
0.99999999976716935634613037109375 | 0.999999999767169356346130371093750000
0.99999999976716935634613037109375 | 0.999999999767169356346130371093750000 (sisyphus)

WinXP/Visual-C++ 2005 & Visual C++6.0 (same results):

0.99999999976716936
0.99999999976716936 | 0.999999999767169360000000000000000000
0.99999999976716936 | 0.999999999767169360000000000000000000 (sisyphus)


WinXP/MinGW 3.4.2

0.99999999976716936
0.99999999976716936 | 0.999999999767169360000000000000000000
0.99999999976716936 | 0.999999999767169360000000000000000000 (sisyphus)


Regards

M.
 
S

szr

printf("%.32g\n",0.99999999976716936);

Perl 5.6.1 output:
0.99999999976716936 --> GOOD

Perl 5.8.6 output:
0.99999999976716925 --> ERROR

I get:

$ perlall -e 'printf("%.32g\n",0.99999999976716936);'
<perl5.10.0> 0.99999999976716935997820764892019
<perl5.8.8 > 0.99999999976716935997820764892019
<perl5.8.2 > 0.9999999997671692453238279085781
<perl5.8.0 > 0.9999999997671692453238279085781
<perl5.6.1 > 0.99999999976716935634613037109375
 
S

szr

RedGrittyBrick said:
print Math::BigFloat->new("0.99999999976716936")->bstr();


The version of Math::BigFloat that shipped with 5.6.1, which the op
seems to need, doesn't seem to support ->bstr()

$ perlall -MMath::BigFloat -e 'print
Math::BigFloat->new("0.99999999976716936")->bstr(), "\n";'
<perl5.10.0> 0.99999999976716936
<perl5.8.8 > 0.99999999976716936
<perl5.8.2 > 0.99999999976716936
<perl5.8.0 > 0.99999999976716936
Can't locate object method "bstr" via package "Math::BigFloat" (perhaps
you forgot to load "Math::BigFloat"?) at -e line 1.
<perl5.6.1 >


Perhaps ->ffround(17) could be used instead?

$ perl5.6.1 -MMath::BigFloat -e 'print
Math::BigFloat->new("0.99999999976716936")->ffround(-17), "\n";'
+99999999976716936E-17

You could always update your Math::* modules if you must use 5.6.1,
else, it would better to just install a newer Perl :)
 
S

szr

sisyphus said:
I believe it's a bug in perl 5.8 (which has been carried through to
perl 5.10):

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",0.99999999976716936);"
0.99999999976716925

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716936

Since 0.99999999976716936 == 9.9999999976716936e-1, I can think of no
good reason that that those 2 one-liners should produce different
output - and I believe the first one liner produces an incorrect
result.

I'll submit a bug report about this - unless someone can convince me
that it's *not* a bug (or unless someone else wants to submit the
report).

Cheers,
Rob

Interesting, I get these values:

$ perlall -e 'printf("%.32g\n",99999999976716936e-1);'
<perl5.10.0> 9999999997671693.599609375
<perl5.8.8 > 9999999997671693.599609375
<perl5.8.2 > 9999999997671692
<perl5.8.0 > 9999999997671692
<perl5.6.1 > 9999999997671694
 
S

szr

sisyphus said:
I believe it's a bug in perl 5.8 (which has been carried through to
perl 5.10):

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",0.99999999976716936);"
0.99999999976716925

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716936

Since 0.99999999976716936 == 9.9999999976716936e-1, I can think of no
good reason that that those 2 one-liners should produce different
output - and I believe the first one liner produces an incorrect
result.

I'll submit a bug report about this - unless someone can convince me
that it's *not* a bug (or unless someone else wants to submit the
report).

Cheers,
Rob

Please disregard my previous reply, I made a dump typo.

This is what I get:

$ perlall -e 'printf("%.32g\n",9.9999999976716936e-1);'
<perl5.10.0> 0.99999999976716935997820764892019
<perl5.8.8 > 0.99999999976716935997820764892019
<perl5.8.2 > 0.99999999976716935634613037109375
<perl5.8.0 > 0.99999999976716935634613037109375
<perl5.6.1 > 0.99999999976716935634613037109375
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
sisyphus
Since 0.99999999976716936 =3D=3D 9.9999999976716936e-1

Why this would be so? At best, one is 0.99999999976716936, another is
9.9999999976716936/10. I know no axiom of FP arithmetic which would
make them equal...

(In principle, one could impose a condition on atof() that all strings
are first normalized IN DECIMAL to the e00 exponent, THEN translated
to binary. But given that, AFAIK, atof() is not documented to satisfy
ANY requirement, however reasonable, this is a pipe dream.)

[I have, on a backburner, some plans to make Perl use "the best"
string-to-FP-to-string conversions (so that a lot of verbiage can be
removed from perlnumber.pod). But my improve-perl plans do not get a
lot of timeslices recently.]

Yours,
Ilya
 
S

sisyphus

[A complimentary Cc of this posting was sent to
sisyphus
Since 0.99999999976716936 =3D=3D 9.9999999976716936e-1

Why this would be so?  At best, one is 0.99999999976716936, another is
9.9999999976716936/10.  I know no axiom of FP arithmetic which would
make them equal...

Oh! ... ok. (I was thinking that perl should see the same mantissa in
both instances, and therefore store the same value.)

The other thing I note is that (with 52 bits of precision, plus the
implicit leading "1.") 0.99999999976716936 is represented in base 2
as:
1.1111111111111111111111111111111000000000000000000000e-1
And that converts back to 0.99999999976716936 (in base 10).

OTOH, 0.99999999976716925 is represented as:
1.1111111111111111111111111111110111111111111111111111e-1
And that converts back to 0.99999999976716925 (in base 10).

For my conversions, I'm using "round to nearest" mode - and I'm using
the mpfr C library (version 2.3.1) - which, according to its homepage
at http://www.mpfr.org/ provides "correct rounding" and "copies the
good ideas from the ANSI/IEEE-754 standard for double-precision
floating-point arithmetic (53-bit mantissa)". I've not yet had any
cause to take issue with those claims.

For me, (the recent versions of)perl are at odds with everything else
on my box in (apparently) insisting that 0.99999999976716936 has the
internal base 2 representation of:
1.1111111111111111111111111111110111111111111111111111e-1

Everything else uses an internal representation of
1.1111111111111111111111111111111000000000000000000000e-1.

Is that still not a perl bug ? (This FP stuff is just so damned
tricky, I never know what to think for sure :)

Cheers,
Rob
 
B

Ben Morrow

Quoth sisyphus said:
For me, (the recent versions of)perl are at odds with everything else
on my box in (apparently) insisting that 0.99999999976716936 has the
internal base 2 representation of:
1.1111111111111111111111111111110111111111111111111111e-1

Do you know how it gets to that? Is it not simply calling your atof?
Everything else uses an internal representation of
1.1111111111111111111111111111111000000000000000000000e-1.

Is that still not a perl bug ? (This FP stuff is just so damned
tricky, I never know what to think for sure :)

I think the stated position is 'perl provides no guarantees about
anything to do with FP'. If you wish to implement, test, and document
something more consistent, please feel free.... :)

Ben
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
sisyphus
For me, (the recent versions of)perl are at odds with everything else
on my box in (apparently) insisting that 0.99999999976716936 has the
internal base 2 representation of:
1.1111111111111111111111111111110111111111111111111111e-1

Everything else uses an internal representation of
1.1111111111111111111111111111111000000000000000000000e-1.

Is that still not a perl bug ? (This FP stuff is just so damned
tricky, I never know what to think for sure :)

You may want to consult

perl -V:d_Gconvert

It might help you understand what happens...

Yours,
Ilya
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was NOT [per weedlist] sent to
Ilya Zakharevich
You may want to consult

perl -V:d_Gconvert

It might help you understand what happens...

Oups, it is THE OTHER direction! In fact, I do not know what Perl
uses to parse FP numbers. Let me check.... In 5.8.8:

#define Atof my_atof

which, essentially, calls Perl_my_atof2(), which OMG! calls a
home-brewed implementation! Shame on us! No wonder it behaves
fishy; coding string-to-num conversion is not for weaklings...

But before ringing the bell, please consider what is the *right*
answer. E.g.,

0.99999999976716936 * 2**75
= 37778931854161068825399.29174657778843648

The integer part is essentially

0b111111111111111111111111111111110000000000000000000000000100000001010111001

Perl behaves as if it were

0b11111111111111111111111111111110111111111111111111111...

The rest as if it were

0b11111111111111111111111111111111000000000000000000000...

So indeed, Perl's implemenation is extremely buggy (as anything
written by people who do not LIVE WITH FP would be)...

Hope this helps,
Ilya
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
sisyphus
For me, (the recent versions of)perl are at odds with everything else
on my box in (apparently) insisting that 0.99999999976716936 has the
internal base 2 representation of:
1.1111111111111111111111111111110111111111111111111111e-1

Everything else uses an internal representation of
1.1111111111111111111111111111111000000000000000000000e-1.

Yet another thought (that's just alias for Perl's printf):

pprintff .31g 0.99999999976716936
0.999999999767169245324

pprintff .31g 99999999976716936/100000000000000000
0.999999999767169245324

pprintff .31g 99999999976716936
99999999976716928

So it looks like whoever wrote Perl's Atof() thought (in their greate
wiseness) that one is allowed to translate the mantissa in 3
operations: convert the "integer mantissa" to an FP value, then
convert the corresponding 1000...000 to an FP value, then divide.

(The numerics people would immediately note that doing 3 operations
increases the maximal possible error 3 times, which is not allowed.
The trickyness of string-to-FP conversion is that it cannot be done
using just the precision of the FP primitives; one needs to get a
higher precision that this...)

Hope this helps,
Ilya
 
T

Ted Zlatanov

BM> I think the stated position is 'perl provides no guarantees about
BM> anything to do with FP'.

Position of who?

There's Math::BigFloat and Math::BigRat which are at least moderately
useful.

Ted
 
B

Ben Morrow

Quoth Ted Zlatanov said:
BM> I think the stated position is 'perl provides no guarantees about
BM> anything to do with FP'.

Position of who?

Whom. :)

Of p5p, but note that I don't speak for 'them' in any way, so I may be
mis-stating the case.
There's Math::BigFloat and Math::BigRat which are at least moderately
useful.

There are; there are also the bigint and bignum pragmata which make them
more useful still. I was talking about perl's handling of real platform
floats (NVs).

Ben
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
sisyphus
Oh! ... ok. (I was thinking that perl should see the same mantissa in
both instances, and therefore store the same value.)

Note that in other posts I flipped my position in this question.
According to the semantic in perlnumber.pod, a decimal string should
be considered as the REAL (as opposite to FP!) number exactly
representable by this decimal. When needed for its operation, Perl
has the right to convert it to the closest exactly representable FP
number.

In particular, in Perl one must have

0.99999999976716936 == 9.9999999976716936e-1

[As far as Perl was using CRT library routines for string-to-FP
conversion, there were an excuse for some deviations from this
semantic. However, since nowadays uses its own routine, no such
deviation may be allowed.]

Yours,
Ilya
 
T

Ted Zlatanov

BM> I think the stated position is 'perl provides no guarantees about
BM> anything to do with FP'.
BM> Whom. :)

Eh, if I remembered those grammar rules I'd have no room in my brain for
what $| does :)

BM> Of p5p, but note that I don't speak for 'them' in any way, so I may be
BM> mis-stating the case.

I'm curious if there are, in fact, some guarantees. For example, "on a
full moon, under the willow tree, while softly singing the songs of
distant Earth, adding two floats will, sometimes, give you a float that
is roughly equal to their sum." You know, spice up the docs a bit.

BM> There are; there are also the bigint and bignum pragmata which make them
BM> more useful still. I was talking about perl's handling of real platform
BM> floats (NVs).

Right, but big* is a FP interface that's quite useful, and should at
least be mentioned when people complain about platform floats. Then
those same people can complain about big* performance and Intel/AMD can
sell them faster processors. Everybody wins.

Ted
 
S

sisyphus

.
.
Is it not simply calling your atof?

I don't think so - and I see, further down, that Ilya has reported it
calls a "home-brewed" implementation.

I tried out ActiveState's builds of perl 5.6.1, 5.8.8 and 5.10.0 - all
three of which use the same underlying C library (Visual Studio 6.0).

Again, with their 5.6 build I get:

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716936

Yet, with their builds of 5.8 and 5.10 I get:

C:\_32\pscrpt>perl -e "printf(\"%.32g\n\",9.9999999976716936e-1);"
0.99999999976716925

I think that rules out differences in the C library as the cause of
the discrepancy.

As regards atof() itself, the following C program outputs
0.99999999976716936:

int main( void )
{
double x;

x = atof("0.99999999976716936");
printf( "%.17f\n", x );

}

Cheers,
Rob
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top