Home > Net >  Need explanation for `~0` vs. `2**64` with and without `use integer`
Need explanation for `~0` vs. `2**64` with and without `use integer`

Time:09-17

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 without use 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 (like 2**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
  • Related