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

I'm no expert in statically typed languages..

... how many of them support x^y with integers?

Those exponentiation algorithms are normally implemented for real numbers and produce a float.

The core problem we saw and most Perl experiments here is that 2**53 is a float whose error margin doesn't allow a consistent conversion to 64 bit integer anymore.

If your statically typed language doesn't support this out-of-the-box - and Perl is build on top of C - your statement is just comparing apples with oranges.

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

Replies are listed 'Best First'.
Re^5: Largest integer in 64-bit perl
by BillKSmith (Monsignor) on Jun 02, 2025 at 14:50 UTC
    I would expect any language that does not support an operation to not allow attempts to use it. Perl does not directly support 64-bit integer exponentiation. without strong typing, it has no way to know that we expect it. What it does do when we try to raise an integer to an integer power is exact if the result is less than 2**53, and almost always 'good enough" the rest of the time. Perhaps there should be an optional warning when it attempts to cast a result greater than 2**53 and less than 2**63 to an integer.
    Bill
      > without strong typing, it has no way to know that we expect it.

      I disagree, at least if the operands were integer and the result is between max-float-precision and max-integer-precision (2**53 and 2**64 in our case) you can assume an integer was wanted.

      Of course it's not trivial (if ever) to solve this generally for instance for $x=2**0.5 and $y=$x**2 since the square-root of 2 isn't rational.

      Or even $x=2/3 and 27**$x == 9 because $x isn't loss-free in binary floats.

      > Perhaps there should be an optional warning when it attempts to cast a result greater than 2**53 and less than 2**63 to an integer.

      I think this should be part of a (bigger) pragma to address this.

      for instance will Perl happily do this

      DB<25> p 27**(2/3) 9 DB<26> p 27**(2/3) == 9 DB<27> printf "%.15f", 27**(2/3) 8.999999999999998 DB<28>

      update

      And before the Perl bashing hits in, Python isn't that much better

      >>> 27**(2/3) 8.999999999999998 >>> 27**(2/3)==9 False >>>

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

        > I disagree, at least if the operands were integer and the result is between max-float-precision and max-integer-precision (2**53 and 2**64 in our case) you can assume an integer was wanted.

        Here a POV to force ** into producing an integer where it obviously should.

        Kind of over-engineered and under-tested.

        I first used Math::BigInt as backend but integer turned out to be easier.

        Since integer is core, it shouldn't be complicated to implement this right away,

        use v5.10; use warnings; use Config; use constant { MAX_FLOAT => eval($Config{nv_overflows_integers_at}."-1"), MAX_INT => ~0, BACKEND => "integer", }; sub power{ my ($base,$exp) = @_; my $float = $base ** $exp; return $float + 0 # Explicitely coerce to IV if possible if $float <= MAX_FLOAT; return $float # no integer possible if $float > MAX_INT or $base != int($base) or $exp != int($exp); if (BACKEND eq "BigInt") { use Math::BigInt; my $result = Math::BigInt->new($base)->bpow($exp); return hex($result->as_hex()) } elsif (BACKEND eq "integer") { use integer; return int($base ** $exp); } else { die "Unknown Backend: ". BACKEND; } } sub compare { my ($b,$e) = @_; say "=== comparing $b^$e"; my $old = $b**$e; my $new = power($b,$e); for my $val ($old,$new) { say "--- $val"; # use Devel::Peek; # use Data::Dump; # say "is integer" if $val == int($val); # ddx ($val); # Dump($val); say "$_: \t", $val+$_ for -1,1; } say "="; } compare(@$_) for [2,50],[2,63];

        perl /home/lanx/perl/pm/int_pow.pl === comparing 2^50 --- 1.12589990684262e+15 is integer -1: 1125899906842623 1: 1125899906842625 --- 1125899906842624 is integer -1: 1125899906842623 1: 1125899906842625 = === comparing 2^63 --- 9.22337203685478e+18 is integer -1: 9.22337203685478e+18 1: 9.22337203685478e+18 --- 9223372036854775808 is integer -1: 9223372036854775807 1: 9223372036854775809 =

        update

        since integer is only meant to operate with signed integers I'm not too confident this is reliable in the range between 2**63 and 2**64.

        More testing needed.

        update

        well, seems not to be a good idea to rely on integer , see integer pragma buggy? (ANSWERED)

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