in reply to Re^6: Largest integer in 64-bit perl
in thread Largest integer in 64-bit perl

You are talking about "weirdness", so what would be "normal" in your opinion.

I just find it weird that, on a platform where 64-bit positive integer values can be stored exactly, it is considered acceptable that all other integer values be rounded to 53 bits of precision.
I would find it quite acceptable if positive integer values greater than 64 bits were rounded to 64-bit (or greater) precision values, but cutting them back to 53-bit precision values seems a very poor alternative.
My gripe is not so much about how perl handles this configuration, but that this daft configuration is so widely used and accepted as valid. (I guess I should be grateful that the chosen default NV was the double precision one, and not the single precision float ;-)

Of course, people are free to accept whatever they like, and thankfully it's easy enough to find modules (or to use a sanely configured perl build) such that precision is not reduced to below-integer precision when the integer value overflows integer precision.

Cheers,
Rob

Replies are listed 'Best First'.
Re^8: Largest integer in 64-bit perl (UPDATED)
by LanX (Saint) on May 30, 2025 at 13:49 UTC
    > I just find it weird that, on a platform where 64-bit positive integer values can be stored exactly, it is considered acceptable that all other integer values be rounded to 53 bits of precision.

    I need to test again, but IMHO this depends on the number before the operation being a float or not.

    AFAIK is exponentiation ** using an approximation algorithm and hence always producing a float.

    So even if 2**53 (-1) should be a perfectly "whole number" it's stored as a float.

    But that's speculation, I'm thinking of writing simple test code using only basic operations.

    This could be translated to different dynamically typed languages to test their behavior.

    update

    I can't see how your wtf-example shows any rounding to 2**53.

    Your floats have 64 bits leaving 53 for the mantissa and ~0 == 2^64-1 , hence there is no way to represent a whole number ~0+1 loss free.

    Going up to 128bit floats will just replicate the situation on 32bit systems with 64bit floats.

    update

    OK I tried to nail down the weirdness, please note in the first example I'm constructing 2^53-1 and everything goes fine, even since ** will always produce a NV, summing them up will convert back to IV.

    lanx:$ perl -MDevel::Peek -E'$x+=2**$_ for 0..52;Dump ($x);Dump($x+1)' SV = IV(0x64c9edf22bb0) at 0x64c9edf22bc0 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 9007199254740991 SV = IV(0x64c9edf838d0) at 0x64c9edf838e0 REFCNT = 1 FLAGS = (PADTMP,IOK,pIOK) IV = 9007199254740992

    Now the same with 2^54-1, because the last element of the sum is the NV 2**53 which doesn't fit into the mantissa, we are stuck in NV even after adding an IV.

    lanx:$ perl -MDevel::Peek -E'$x+=2**$_ for 0..53;Dump ($x);Dump($x+1); +say "*** WTF *** " if $x == $x+1' SV = PVNV(0x5ea09827d340) at 0x5ea0982abd00 REFCNT = 1 FLAGS = (NOK,pNOK) IV = 9007199254740991 NV = 18014398509481984 PV = 0 SV = NV(0x5ea09830cb18) at 0x5ea09830cb30 REFCNT = 1 FLAGS = (PADTMP,NOK,pNOK) NV = 18014398509481984 *** WTF ***

    The real issue here is the ** operand, it should ideally produce an integer since 2 and 53 are integers and they fit into IV.

    But even special casing the X**Y algorithm for integer results isn't trivial.

    • 2**65 would still need to produce an NV
    • 4**0.5 would need to be IV 2

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      I can't see how your wtf-example shows any rounding to 2**53.

      The following examples imply rounding to 53 bits:
      D:\>perl -le "print 'wtf' unless ~0 < (~0) + 2048;" wtf D:\>perl -le "print 'wtf' unless ~0 < (~0) + 2049;" D:\>
      Cheers,
      Rob
        (see update further down)

        > The following examples imply rounding to 53 bits:

        Again, ~0 == 2^64-1 no 53 involved.

        You are out of any integer precision on "normal" 64bit systems, if you use the "Largest integer in 64-bit perl" (sic).

        DB<35> p log(~0)/log(2) 64 DB<36> printf "%x",~0 ffffffffffffffff DB<37> $x=0; $x=$x*2+1, printf "2**%d-1 : %x\n",$_,$x for 1..64 2**1-1 : 1 2**2-1 : 3 2**3-1 : 7 2**4-1 : f 2**5-1 : 1f 2**6-1 : 3f 2**7-1 : 7f 2**8-1 : ff 2**9-1 : 1ff 2**10-1 : 3ff 2**11-1 : 7ff 2**12-1 : fff 2**13-1 : 1fff 2**14-1 : 3fff 2**15-1 : 7fff 2**16-1 : ffff 2**17-1 : 1ffff 2**18-1 : 3ffff 2**19-1 : 7ffff 2**20-1 : fffff 2**21-1 : 1fffff 2**22-1 : 3fffff 2**23-1 : 7fffff 2**24-1 : ffffff 2**25-1 : 1ffffff 2**26-1 : 3ffffff 2**27-1 : 7ffffff 2**28-1 : fffffff 2**29-1 : 1fffffff 2**30-1 : 3fffffff 2**31-1 : 7fffffff 2**32-1 : ffffffff 2**33-1 : 1ffffffff 2**34-1 : 3ffffffff 2**35-1 : 7ffffffff 2**36-1 : fffffffff 2**37-1 : 1fffffffff 2**38-1 : 3fffffffff 2**39-1 : 7fffffffff 2**40-1 : ffffffffff 2**41-1 : 1ffffffffff 2**42-1 : 3ffffffffff 2**43-1 : 7ffffffffff 2**44-1 : fffffffffff 2**45-1 : 1fffffffffff 2**46-1 : 3fffffffffff 2**47-1 : 7fffffffffff 2**48-1 : ffffffffffff 2**49-1 : 1ffffffffffff 2**50-1 : 3ffffffffffff 2**51-1 : 7ffffffffffff 2**52-1 : fffffffffffff 2**53-1 : 1fffffffffffff 2**54-1 : 3fffffffffffff 2**55-1 : 7fffffffffffff 2**56-1 : ffffffffffffff 2**57-1 : 1ffffffffffffff 2**58-1 : 3ffffffffffffff 2**59-1 : 7ffffffffffffff 2**60-1 : fffffffffffffff 2**61-1 : 1fffffffffffffff 2**62-1 : 3fffffffffffffff 2**63-1 : 7fffffffffffffff 2**64-1 : ffffffffffffffff DB<38> Dump(~0), Dump($x), Dump($x+1) SV = IV(0x5ec1cb040bc8) at 0x5ec1cb040bd8 REFCNT = 1 FLAGS = (PADTMP,IOK,READONLY,PROTECT,pIOK,IsUV) UV = 18446744073709551615 SV = PVNV(0x5ec1ca86f980) at 0x5ec1caeeb210 REFCNT = 1 FLAGS = (IOK,pIOK,pNOK,IsUV) UV = 18446744073709551615 NV = 1.8446744073709552e+19 PV = 0x5ec1cb01d8b0 "18446744073709551615"\0 CUR = 20 LEN = 22 SV = NV(0x5ec1cb040c50) at 0x5ec1cb040c68 REFCNT = 1 FLAGS = (PADTMP,NOK,pNOK) # <--- Integer Fla +gs are gone NV = 1.8446744073709552e+19

        Nothing to do with 53 bits.

        update

        Since we are falling back on float precision with 53 bit mantissa , we'll get ~0 == ~0 + 2048 , because 2048 = 2**11 and 53+11==64 . That's what you mean with 53bit rounding?

        So your suggestion is that on 64bit engines we should use a higher float precision? Like the Quadruple-precision floating-point format?

        I think I'd rather follow Nerdvana's suggestion

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery