Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: Determining the minimum representable increment/decrement possible?

by davido (Cardinal)
on Jun 15, 2016 at 15:52 UTC ( [id://1165741]=note: print w/replies, xml ) Need Help??


in reply to Determining the minimum representable increment/decrement possible?

This post is based on the following theory:

<theory>Since Perl's floating point precision is constrained by what can be stored in an NV, the minimal change to a floating point value that Perl should be able to accommodate would be obtained by twiddling the least significant bit in an NV.</theory>

Here's an example (which may be completely bogus) of what I'm getting at. Unfortunately my understanding of Perl's internal representation of a float within an NV is limited, so this approach is at best just intended to explore the possibility.

use strict; use warnings; my $fp = 1/2; # m/2^n may be represented perfectly in base 2. printf "%25.32g\n", $fp; my $p = pack 'F', $fp; my $b = unpack 'b*', $p; print "$b\n"; $b =~ s/(.)/$1 ? 0 : 1/e; print "$b\n"; my $np = pack 'b*', $b; my $nfp = unpack 'F', $np; printf "%25.32g\n", $nfp;

The output:

0.5 0000000000000000000000000000000000000000000000000000011111111100 1000000000000000000000000000000000000000000000000000011111111100 0.50000000000000011102230246251565

So it would appear that the least significant change that can be represented in an NV that was holding the decimal floating point value of 0.5 would be 0.00000000000000011102230246251565.

In my example, I started with a value that I knew could be represented precisely in native base-2 format, and essentially ended up with another number that can be stored precisely in native base-2. It just happens to be a number that is rather ugly in base 10.

Apologies if this is getting off into the wrong field of weeds, or if my example inadequately implements the theory I put forth, but the topic seemed interesting and I thought I'd post my exploration.


Dave

Replies are listed 'Best First'.
Re^2: Determining the minimum representable increment/decrement possible?
by ExReg (Priest) on Jun 15, 2016 at 17:52 UTC

    Following up on the excellent answer davido came up with, and using the code he gave, 1.9041105342991877e+258 gives the binary value 0100001110111101100010001110100001001000001011011111000110101110

    Going the other way, the binary string just obtained is displayed as 1.90411053429919e+258

    Increasing the least significant bytes to see when we see a change,

    0100001110111101100010001110100001001000001011011111000110101110 - sti +ll 1.90411053429919e+258 1100001110111101100010001110100001001000001011011111000110101110 - sti +ll 1.90411053429919e+258 1110001110111101100010001110100001001000001011011111000110101110 - sti +ll 1.90411053429919e+258 1111001110111101100010001110100001001000001011011111000110101110 - sti +ll 1.90411053429919e+258 1111101110111101100010001110100001001000001011011111000110101110 - sti +ll 1.90411053429919e+258 1111111110111101100010001110100001001000001011011111000110101110 - fin +ally 1.9041105342992e+258

    Why did we have to go in 6 bits from the end to see a change in the floating point representation?

    There are 53 bits in the mantissa, and if the last 6 don't show, that means that there are only 47 being used for the display in floating point. log(2^47)/log(10) gives us about 14 significant digits. This is what the answers above seem to indicate.

    I think that the answer is going to depend on how many digits the machine displays for a given IEEE754 value. For my machine, I need to change the value by roughly about 10^-14 from its original value to see a change.

    P.S. I hope I transcribed everything correctly here. As always, I have to use another machine to run the perl.

      Excuse me while I clear out my cranial flatus. I was not forcing the maximum precision. I was using the default. If I add the printf "%25.32" as dvido had I would have gotten slightly different results:

      0100001110111101100010001110100001001000001011011111000110101110 - 1.9 +041105342991886e+258 1100001110111101100010001110100001001000001011011111000110101110 - 1.9 +041105342991888e+258

      It would appear that in this case, 1.9041105342991887e+258 is not possible to store. Using all 53 bits of mantissa, I still get about 15.95 digits instead of the 14. Each case will be different and require converting to binary, twiddling the bits, and seeing what you get.

        It would appear that in this case, 1.9041105342991887e+258 is not possible to store.

        That is because 1.9041105342991887e+258 does not fit into m/2^n, and therefore cannot be represented precisely in base 2. You would need a couple more bits to push the rounding error further out, but that's just kicking the can down the road.

        In other words, the binary representation of this floating point value results in a non-terminating sequence, much as 1/3rd results in a non-terminating sequence in base 10.


        Dave

Re^2: Determining the minimum representable increment/decrement possible?
by anonymized user 468275 (Curate) on Jun 15, 2016 at 16:38 UTC
    But it still comes down to the definition of floating point. There are fifteen or sixteen decimal digits maximum in Perl's floating point implementation, so stagnation will occur at either the sixteenth or seventeenth significant digit, irrespective of the exponent. Having said that there is a limit to the absolute value of the exponent before Perl cries 'Inf'. Curiously, it will also cry Inf when approaching zero which seems a bit flaky to me, when it could just zero the thing.

    Update: Inf as in infinity. Ambiguity being a famous line from an old film, 'Carry on Cleo', where Caesar cries: 'Infamy, infamy, they've all go it in fer me'

    One world, one people

Re^2: Determining the minimum representable increment/decrement possible?
by BrowserUk (Patriarch) on Jun 15, 2016 at 19:18 UTC

    Is your perl compiled to use long doubles for NV?

    I ask because my perl is using normal doubles and I get different results to you:

    printf "% 25.32g\n", unpack 'F', pack 'b*', '1000000000000000000000000 +000000000000000000000000000011111111100';; 0.50000000000000011

    (In general I think you've hit on at least part of the solution to my quest; though it is complicated by the production of denormals; which I'm still trying to wrap my head around; so I ll get back to you once I've wrapped my brain around them.)


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice. Not understood.

      I think this is due to differences in the C library. You're using a Windows build, right? I think this has been unified in 5.22.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1165741]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-04-20 05:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found