Re^3: Largest integer in 64-bit perl
by LanX (Saint) on May 27, 2025 at 12:36 UTC
|
> The difference is that Perl does this automatically!
Is a whole number at the extreme of a mantissa's precision really converted to 64 bit integer if incremented?
My
results from binary search indicated otherwise. This might also depend on the type of operation.
Plus might do, mult might stick with float.
| [reply] |
|
[Upd: This pertains to when using addition.] An int, yes. A float, no. Just like in C. Ints are promoted to floats, but floats aren't promoted to integers. You need to cast to int to get int behaviour. Just like in C.
use v5.14;
use warnings;
my $x = 2**53;
say sprintf "%d", $x;
say sprintf "%d", $x + 1;
say sprintf "%d", int( $x ) + 1;
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
int main( void ) {
double x = 9007199254740992;
printf( "%"PRIu64"\n", (uint64_t)( x ) );
printf( "%"PRIu64"\n", (uint64_t)( x + 1 ) );
printf( "%"PRIu64"\n", (uint64_t)( (uint64_t)x + 1 ) );
}
9007199254740992
9007199254740992
9007199254740993
Other differences between floats and ints is the existence of inifinity, NaN and -0.
| [reply] [d/l] [select] |
|
.... but floats aren't promoted to integers.
It can get a bit moot:
D:\>perl -MDevel::Peek -le "$x = (2 ** 53) - 1; Dump $x; $x++; Dump $x
+; $x++; Dump $x; $x++; Dump $x;"
SV = NV(0x28e88c5a2f8) at 0x28e88c5a310
REFCNT = 1
FLAGS = (NOK,pNOK)
NV = 9007199254740991
SV = PVNV(0x28e88c24e10) at 0x28e88c5a310
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 9007199254740992
NV = 9007199254740991
PV = 0
SV = PVNV(0x28e88c24e10) at 0x28e88c5a310
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 9007199254740993
NV = 9007199254740991
PV = 0
SV = PVNV(0x28e88c24e10) at 0x28e88c5a310
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 9007199254740994
NV = 9007199254740991
PV = 0
The fact that the flags change from (NOK,pNOK) to (IOK,pIOK) suggests to me that the NV has been promoted to an IV.
Or does the fact that both the IV and NV slots have been filled suggest that it's neither an IV nor an NV. Or maybe that suggests that it's both ? ... I don't know.
Anyway, I'm not looking for an argument. It's just one of those things that I find a little mysterious.
Other differences between floats and ints is the existence of inifinity, NaN and -0
One of my beefs with Math::BigInt is that it has a NaN and an inf:
D:\>perl -MMath::BigInt -le "$x = Math::BigInt->new(2.3); print $x; pr
+int ref($x);"
NaN
Math::BigInt
D:\>perl -MMath::BigInt -le "$x = Math::BigInt->new(1) / 0; print $x;
+print ref($x);"
inf
Math::BigInt
I don't regard it as all that important, but it probably shouldn't do that.
I couldn't quickly get it to provide a "-0", but I did get the following weirdness:
D:\>perl -MMath::BigInt -le "$x = Math::BigInt->new(1) / inf; print $x
+; print ref($x);"
0
Math::BigInt
D:\>perl -MMath::BigInt -le "$x = Math::BigInt->new(1) / -inf; print $
+x; print ref($x);"
-1
Math::BigInt
Cheers, Rob | [reply] [d/l] [select] |
|
|
|
Re^3: Largest integer in 64-bit perl
by karlgoethebier (Abbot) on May 29, 2025 at 09:52 UTC
|
”…weird lesson to take. You'll have "problems near 2**53" in those languages too!”
I'm not so sure about that. Or at least I don't see the problems:
use anyhow::{Context, Result};
use num::BigUint;
fn frob(n: u64) -> Result<BigUint> {
Ok((1..=n)
.into_iter()
.map(|i| BigUint::from(i))
.reduce(|a, b| a * b)
.context("fuba")?)
}
fn main() -> Result<()> {
println!("i8 {}", i8::MAX);
println!("i16 {}", i16::MAX);
println!("i32 {}", i32::MAX);
println!("i64 {}", i64::MAX);
println!("i128 {}", i128::MAX);
println!("u8 {}", u8::MAX);
println!("u16 {}", u16::MAX);
println!("u32 {}", u32::MAX);
println!("u64 {}", u64::MAX);
println!("u128 {}", u128::MAX);
println!("f32 {}", f32::MAX);
println!("f64 {}", f64::MAX);
println!("{}", frob(1000)?);
Ok(())
}
In any case, this seems to be a clearly defined matter in this case.
| [reply] [d/l] [select] |
|
The discussion in this thread is about the side effects of implicit typecasting/conversions of whole numbers to augment precision when operations may cause an overflow.
Perl does this by switching to double floats with E0 were the mantissa has 53 bits (opposed to integers with 32 or 64 bits, depending on the built).
Now from what I read on Wikipedia is Rust strictly typed.
Hence I really don't understand what your code is supposed to show.
Is there any implicit typecasting in your code?°
update
According to this tutorial: https://oylenshpeegul.gitlab.io/from-perl-to-rust/numbers.html this can't be, because coercion has to be made explicitly.
| [reply] [d/l] |
|
Perl does this by switching to double floats ...
Rather, perl switches to "NV" floats.
Of course, I'm nitpicking, but it's a nitpick that does have some significance.
On a perl whose ivsize=8, && whose nvtype is either 'long double' or '__float 128', I get:
D:\>perl -e "print 'wtf' unless ~0 < (~0) + 1;"
D:\>
But on a perl where ivsize=8 and nvtype is 'double' and you get:
D:\>perl -e "print 'wtf' unless ~0 < (~0) + 1;"
wtf
D:\>
Now that particular configuration (ivsize==8 and nvtype is 'double') is the only perl configuration that produces that nonsense - and yet it's the most commonly used configuration !!
If you use either an ivsize of 4, or an nvtype that is not double, then you can ignore that particular weirdness because it's not going to happen.
Note: That "nonsense" doesn't just happen with (~0) + 1. It happens for (~0) + $x for all $x in the range 1..2048.
That's mainly why I think of it as an insane configuration. (It's still a configuration that I regularly use ;-)
Cheers, Rob
| [reply] [d/l] [select] |
|
|
|
|
|
|
| [reply] |
|
| [reply] |
|
| [reply] |
|
| [reply] |
|
| [reply] |
|
with Alien;
with Utils; use Utils;
package Superiour is
type Acme is new Alien.Object with null record;
function Shred (Self : Object) return String;
end Superiour;
| [reply] [d/l] |
Re^3: Largest integer in 64-bit perl
by BillKSmith (Monsignor) on May 31, 2025 at 21:21 UTC
|
When I referred to "Application which require integers ...", I assumed that the reason that they required integers was that they needed mathematically exact results. Yes, the typed languages usually require you to explicitly specify an appropriate integer type. I still believe that my conclusion holds in this case.
| [reply] |
|
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.
| [reply] [d/l] |
|
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.
| [reply] |
|
|
|
| [reply] |
|
Here is a few examples of the same expression in strawberry perl 5.38.2 and in the gfortran packaged with it. I believe the fortran.
use strict;
use warnings;
use integer;
use feature 'say';
my $base = 3;
my $power = 33;
my $result = $base ** $power;
printf "%d\n", $result;
$power = 38;
$result = $base ** $power;
printf "%d\n", $result
program fort
integer*8 base, power
integer*8 result
base = 3
power = 33
result = base ** power +1;
print *, result
power = 38
result = base ** power +1;
print *, result
end program
RESULTS
C:\Users\Bill\forums\monks>perl power3.pl
5559060566555523
1350851717672992000
C:\Users\Bill\forums\monks>gfortran -o power3 power3.f90
C:\Users\Bill\forums\monks>power3.exe
5559060566555524
1350851717672992090
| [reply] [d/l] [select] |
|