I wrote some test program printing the values of ~0 and 2**64:
#!/usr/bin/perl
use warnings;
use strict;
#use integer;
print ~0, "\n";
print 2**64, "\n";
Without use integer the program outputs
118446744073709551615
1.184467440737096e 19
With use integer the program outputs:
-1
1.184467440737096e 19
The other odd thing is that even when using print int(2**64) the number is output in scientific format still, just as if int(...) wasn't there (Still ~0 without use integer is output in "integer format").
I can force integer output using printf("%u\n", ...), however.
(Perl being used in 5.18.2 of SLES12 SP5 on x86_64)
Questions:
So why is 2**64 a "float" with and without use integer, while ~0 never is?
And with use integer when ~0 is print as -1, it still satisfies the condition ~0 > 2**63 (when I'd expect -1 not to be greater than any positive value (like 2**63).
Update
There seems to be another odd effect seen in the Perl debugger:
2^64 is an odd integer, and 2^64-1 is -2.
DB<22> if (1) { use integer; print 2**64, "\n" }
1.84467440737096e 19
DB<23> if (1) { use integer; print 2**64 - 1, "\n" }
-2
DB<13> if (1) { use integer; printf '%x', 2**64-1, "\n" }
fffffffffffffffe
DB<14> if (1) { use integer; printf '%x', 2**64, "\n" }
ffffffffffffffff
DB<15> if (1) { no integer; printf '%x', 2**64, "\n" }
ffffffffffffffff
DB<16> if (1) { no integer; printf '%x', 2**63, "\n" }
8000000000000000
CodePudding user response:
Manual page perlop(1) explains in section "Integer Arithmetic" that use integer will cause a signed interpretation of integer results, so that will explain 118446744073709551615 vs. -1.
The other thing is that with 64-bit integers 2**64 actually is a 65-bit number than cannot be presented as integer.
So that's interpreted as floating-point number.
And maybe, most important:
~0 is not 2**64, but 2**64 - 1.
One only effect I cannot explain is why int floor(2**64 - 1) isn't output as integer number like ~0 or 0xffffffffffffffff are.
CodePudding user response:
So why is
2**64a "float" with and withoutuse integer
Exponentiation is calculated using floating point numbers and thus produces a float. I don't know why use integer doesn't force the result to be cast to a signed integer, but it doesn't. This is consistent with its documentation, which states that the pragma only affects the operands and results of:
- the arithmetic operators (
,-,*,/,%,=,-=,*=,/=,%=, and unary minus) - the comparison operators (
<,<=,>,>=,==,!=,<=>), and - the bitwise operators (
|,&,^,<<,>>,|=,&=,^=,<<=,>>=)
In fact, it specifically excludes **.
The power operator
**is also not affected, so that 2 ** .5 is always the square root of 2.
while
~0never is?
The machine only has operations for performing bitwise operations on integer types, and they return integer types. There's no point in converting the number to a float (and plenty of reasons not to on a build with 64-bit ints).
And with
use integerwhen~0is print as-1, it still satisfies the condition~0 > 2**63(when I'd expect-1not to be greater than any positive value (like2**63).
use integer causes many operators to cast values to IV, and < is such an operator. Casting 2**63 produces -9223372036854775808 on my machine.
$ perl -M5.010 -Minteger -e'say 0 2**63'
-9223372036854775808
