develooper Front page | perl.perl5.porters | Postings from September 2016

[perl #115092] Rounding a floating point number

From:
Dan Collins via RT
Date:
September 27, 2016 16:14
Subject:
[perl #115092] Rounding a floating point number
Message ID:
rt-4.0.24-18498-1474992876-1844.115092-14-0@perl.org
This is the expected behavior of floats. We have a testcase here for which the closest 80-bit float is below the actual value, and the closest 64-bit float is above it. Since the testcase is a 'tipping point' for rounding, this results in slightly different behavior.

This is no different than any other platform difference in floating point. There are values that are exactly representable by 64 bit floats but not by 80 bit floats. Is it a bug that, for example (x/2)*2==x is true on 32 bit platforms but false on 64 bit platforms for certain values of x?

We can "fix" this by loading a bignum library by default, or by using the lowest common denominator - 64 bit double precision floats on all platforms? - but either of those options seems more disruptive. We already support using extended precision on platforms where it is available - is -Duselongdouble a bug?

perldoc perldata says, (in a paragraph with some unrelated discussion on hex fp literals):

    Notice that while most current platforms use the 64-bit IEEE 754 floating point, not all do. Another potential source of (low-order) differences are the floating point rounding modes, which can differ between CPUs, operating systems, and compilers, and which Perl doesn't control.

perldoc perlnumber says:

    Perl can internally represent numbers in 3 different ways: as native integers, as **native floating point numbers**, and as decimal strings. Decimal strings may have an exponential notation part, as in "12.34e-56" . Native here means "a format supported by the C compiler which was used to build perl".

    However, "native" floats have a most fundamental restriction: they may represent only those numbers which have a relatively "short" representation when converted to a binary fraction. For example, 0.9 cannot be represented by a native float, since the binary fraction for 0.9 is infinite:
      binary0.1110011001100...
    with the sequence 1100 repeating again and again. In addition to this limitation, the exponent of the binary number is also restricted when it is represented as a floating point number. On typical hardware, floating point values can store numbers with up to 53 binary digits, and with binary exponents between -1024 and 1024. In decimal representation this is close to 16 decimal digits and decimal exponents in the range of -304..304. The upshot of all this is that Perl cannot store a number like 12345678901234567 as a floating point number on such architectures without loss of information.

perldoc perlop says:

    Floating-point numbers are only approximations to what a mathematician would call real numbers. There are infinitely more reals than floats, so some corners must be cut. For example:
        printf "%.20g\n", 123456789123456789;
        #        produces 123456789123456784
    Testing for exact floating-point equality or inequality is not a good idea. Here's a (relatively expensive) work-around to compare whether two floating-point numbers are equal to a particular number of decimal places.

perldoc perlop and perlmodlib list some arbitrary precision libraries

I suggest that this ticket be closed rejected, as Perl's use of native floats is documented, as are the dangers of expecting a float to be exactly equal to the decimal value used to create it, and both core and CPAN provide options for those who need arbitrary-precision arithmetic.

-- 
Respectfully,
Dan Collins



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About