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
print Math::BigFloat->new("0.99999999976716936")->bstr();
--
RGB
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.
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
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.
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
--
szr
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 :-)
--
szr
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
--
szr
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
--
szr
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
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
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
You may want to consult
perl -V:d_Gconvert
It might help you understand what happens...
Yours,
Ilya
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
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
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
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
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
BM> Quoth Ted Zlatanov <t...@lifelogs.com>:
>> On Thu, 3 Apr 2008 01:08:59 +0100 Ben Morrow <b...@morrow.me.uk> wrote:
>>
BM> I think the stated position is 'perl provides no guarantees about
BM> anything to do with FP'.
>>
>> Position of who?
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.
>> There's Math::BigFloat and Math::BigRat which are at least moderately
>> useful.
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
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