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

> 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.

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

Replies are listed 'Best First'.
Re^9: Largest integer in 64-bit perl (UPDATED)
by syphilis (Archbishop) on Jun 02, 2025 at 09:35 UTC
    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