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**64
a "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
~0
never 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 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 (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