50+ bits of arithmetic in a 32-bit bag

M

mailbox

Our implementation of Perl under AIX
doesn't support 64-bit integer arithmetic;
so says "perl -V".

A search of these newsgroups turned up a
test of this fact as follows:

$two += 2;
$x = $two ** 63 + 25;
$y = $two ** 63 + 30;
if($x == $y) {print "64 bits not supported\n"}
else {print "64 bits supported\n"}

I found that it would give an affirmative
result if I used up to 55 instead of 63.
This suggests that a floating-point
format with a seven-byte fraction is
being invoked. Perhaps that's the native
floating-point of the AIX box?
At any rate, barring followups to the
contrary, I'll assume that I can treat
our Perl as having a 55-bit integer
arithmetic capability for accumulating
sums, at least. The code in question
doesn't have to be portable.
 
X

xhoster

Our implementation of Perl under AIX
doesn't support 64-bit integer arithmetic;
so says "perl -V".

A search of these newsgroups turned up a
test of this fact as follows:

$two += 2;
$x = $two ** 63 + 25;
$y = $two ** 63 + 30;
if($x == $y) {print "64 bits not supported\n"}
else {print "64 bits supported\n"}

I found that it would give an affirmative
result if I used up to 55 instead of 63.
This suggests that a floating-point
format with a seven-byte fraction is
being invoked. Perhaps that's the native
floating-point of the AIX box?
At any rate, barring followups to the
contrary, I'll assume that I can treat
our Perl as having a 55-bit integer
arithmetic capability for accumulating
sums, at least.

That is a poor assumption. Just because the $x and $y are not identical
does not mean that they are what they are supposed to be.

On my machine, your test also passes for 55, but a more rigorous test
does not:

$ perl -le '$foo=55; print((2**$foo+30)-(2**$foo+25))'
8

I'm pretty sure that 5 != 8, so 55 bits is right out. On my machine, 52 is
high as I would go.

$ perl -le '$foo=52; foreach (1..1e7) { my $y =
((2**$foo+$_+1)-(2**$foo+$_));
die $_ unless $y == 1}'


Xho
 
M

mailbox

On my machine, your test also passes for 55, but a more rigorous test
does not:

$ perl -le '$foo=55; print((2**$foo+30)-(2**$foo+25))'
8

I'm pretty sure that 5 != 8, so 55 bits is right out. On my machine, 52 is
high as I would go.

$ perl -le '$foo=52; foreach (1..1e7) { my $y =
((2**$foo+$_+1)-(2**$foo+$_));
die $_ unless $y == 1}'


Thanks for that improvement! It behaves the same on our machine as on
yours. Fortunately, 52 bits is still plenty of magnitude for our
purposes.
 
A

anno4000

That is a poor assumption. Just because the $x and $y are not identical
does not mean that they are what they are supposed to be.

On my machine, your test also passes for 55, but a more rigorous test
does not:

$ perl -le '$foo=55; print((2**$foo+30)-(2**$foo+25))'
8

I'm pretty sure that 5 != 8, so 55 bits is right out. On my machine, 52 is
high as I would go.

$ perl -le '$foo=52; foreach (1..1e7) { my $y =
((2**$foo+$_+1)-(2**$foo+$_));
die $_ unless $y == 1}'

That happens to coincide with the 53 bit mantissa in IEEE-something
floats. One bit is the sign bit, so 52 bits are safe.

Anno
 
U

Uri Guttman

m> Thanks for that improvement! It behaves the same on our machine as on
m> yours. Fortunately, 52 bits is still plenty of magnitude for our
m> purposes.

it would be hard to use a cpu today that doesn't use ieee float formats
(any perl vax users around? :). so that mantissa size for double floats
(64 bits) will be the same for almost any common box today.

and this one liner also shows the transition from integers to float:

perl -le "print '2**', \$_, ': ', 2**\$_, ' - 1 = ', 2**\$_ - 1 for 47 .. 52"

notice that the -1 stops working after 49 bits so that is the largest
integer you can store in a double. note that this is a decimal issue so
even if the mantissa is 53 bits, you can't operate with a 1 (decimal)
because it takes 4 bits to hold a decimal digit. this is why this shows
49 usable (in decimal) integer bits but the ieee format has 53 bits in
the mantissa.

uri
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
Uri Guttman
perl -le "print '2**', \$_, ': ', 2**\$_, ' - 1 = ', 2**\$_ - 1 for 47 .. 52"

Converting to version which has a better chance to work in the shells' maze:

perl -le 'print q(2**), $_, q:) ), 2**$_, q( - 1 = ), 2**$_ - 1 for 47 .. 52'
2**47: 140737488355328 - 1 = 140737488355327
2**48: 281474976710656 - 1 = 281474976710655
2**49: 562949953421312 - 1 = 562949953421311
2**50: 1.12589990684262e+15 - 1 = 1.12589990684262e+15
2**51: 2.25179981368525e+15 - 1 = 2.25179981368525e+15
2**52: 4.5035996273705e+15 - 1 = 4.5035996273705e+15
notice that the -1 stops working after 49 bits so that is the largest
integer you can store in a double.

Nope. 53 bits is OK.
note that this is a decimal issue so even if the mantissa is 53
bits, you can't operate with a 1 (decimal) because it takes 4 bits
to hold a decimal digit.

Nope, this is just a buggy Perl's convertion to string.

perl -le 'print q(2**), $_, q:) ), sprintf(q(%.0f), 2**$_), q( - 1 = ), sprintf(q(%.f), 2**$_ - 1) for 47 .. 55'
2**47: 140737488355328 - 1 = 140737488355327
2**48: 281474976710656 - 1 = 281474976710655
2**49: 562949953421312 - 1 = 562949953421311
2**50: 1125899906842624 - 1 = 1125899906842623
2**51: 2251799813685248 - 1 = 2251799813685247
2**52: 4503599627370496 - 1 = 4503599627370495
2**53: 9007199254740992 - 1 = 9007199254740991
2**54: 18014398509481984 - 1 = 18014398509481984
2**55: 36028797018963968 - 1 = 36028797018963968

Hope this helps,
Ilya
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,737
Latest member
Georgeengab

Latest Threads

Top