use integer != int()

S

suedecold

I should have left it alone but I decided to clean up
a script and replace a number of calls to "int()" in a
subroutine with "use integer".

I do not understand why I am getting different
results with the following code...

-------------------- begin script --------------------
use strict;

&method_a(730791);
&method_b(730791);

exit;

sub method_a {
my($g) = @_;
my $y;
$y = int((10000*$g + 14780)/3652425);
printf STDOUT "Method A = %d\n", $y;
}

sub method_b {
use integer;
my($g) = @_;
my $y;
$y = (10000*$g + 14780)/3652425;
printf STDOUT "Method B = %d\n", $y;
}
-------------------- end script --------------------

When I run it I get the following on my Win2K box:

C:\Perl\bin>buggy.pl
Method A = 2000
Method B = -351

I thought I understood "use integer" but maybe I
don't. Would someone care to explain the reason for the
different results? perl -v produces:

This is perl, v5.8.3 built for MSWin32-x86-multi-thread
(with 8 registered patches, see perl -V for more detail)

Copyright 1987-2003, Larry Wall

Binary build 809 provided by ActiveState Corp. http://www.ActiveState.com
ActiveState is a division of Sophos.
Built Feb 3 2004 00:28:51

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.

TIA,
JAPH wannabe
 
T

Tassilo v. Parseval

Also sprach suedecold:
I should have left it alone but I decided to clean up
a script and replace a number of calls to "int()" in a
subroutine with "use integer".

I do not understand why I am getting different
results with the following code...

-------------------- begin script --------------------
use strict;

&method_a(730791);
&method_b(730791);

exit;

sub method_a {
my($g) = @_;
my $y;
$y = int((10000*$g + 14780)/3652425);
printf STDOUT "Method A = %d\n", $y;
}

sub method_b {
use integer;
my($g) = @_;
my $y;
$y = (10000*$g + 14780)/3652425;
printf STDOUT "Method B = %d\n", $y;
}
-------------------- end script --------------------

When I run it I get the following on my Win2K box:

C:\Perl\bin>buggy.pl
Method A = 2000
Method B = -351

I thought I understood "use integer" but maybe I
don't. Would someone care to explain the reason for the
different results? perl -v produces:

When you 'use integer' you don't actually tell perl to truncate all
numbers. You tell it to use the machine's native integers. On most
machines, those would be 32bit integers. Such integers are too small to
store 730791*10000 and so the value wraps around and you get something
negative.

'int' on the other hand does something else. Perl will internally still
be using doubles if the values are too large to fit into an integer.
'int' only chops off the decimal part, but the value remains a double
and hence has a larger range than a 32bit int.

So regrettably, you make your scripts a little less portable when using
integer.pm since they now are more dependent on the width of your
integers.

Tassilo
 
A

Aaron W. West

It's overflowing the maximum value of an integer on your system. On 32-bit
machines, integers range from -2**31 to 2**31-1. (Exponentiation, however,
seems to switch to floating-point automatically when I compute 2**31.) When
I installed Cygwin Perl, it was compiled with 64-bit integer support, but
the version I have installed now (5.8.4), I compiled to use 32-bit ints.
Perl can emulate 64-bit integers on 32-bit machines, and if you had a
version compiled that way, the following calculation result should be
positive:

$ perl -e 'use integer; print 65536*32768'
-2147483648
$ /usr/bin/perl -e 'use integer; print 65536*32768'
2147483648

$ perl -v

This is perl, v5.8.4 built for cygwin
....

$ /usr/bin/perl -v

This is perl, v5.8.2 built for cygwin-thread-multi-64int
....

Modern computers (all pentiums) are just about as fast for floating-point
math, usually, so I think there's rarely any reason to bother with use
integer.

I really think in most cases if you feel the need to "use integer" you
should first ask if the small speed difference makes any difference to your
app/users, and secondly if you should switch to a compiled language for some
speed-critical portion of the application if so.

Nevertheless, I played with it for a bit...

$ time perl -e 'for(1..10000000) {$i++; $s+=$i}; '

real 0m4.062s
user 0m3.705s
sys 0m0.130s

$ time perl -e 'use integer; for(1..10000000) {$i++; $s+=$i}; '

real 0m3.898s
user 0m3.414s
sys 0m0.170s

It's slightly faster with "use integer" (by about 16 nanoseconds per
iteration on an Athlon XP 2400). But $s overflowed and became negative
(-2004260032 for the version with use integer, 50000005000000 without.)

$ time perl -e 'for $x (1..1000){ for $y (1..1000) {$s=$x*$y}}'

real 0m0.546s
user 0m0.380s
sys 0m0.140s

$ time perl -e 'use integer;for $x (1..1000){ for $y (1..1000) {$s=$x*$y}}'

real 0m0.512s
user 0m0.340s
sys 0m0.160s

$ time perl -e 'use integer;for $x (1..1000){ for $y (1..1000) {$s=$x*$y}}'

real 0m0.501s
user 0m0.310s
sys 0m0.120s

This time I avoided overflowing calculations. The difference is still very
small, .011 microseconds per iteration.

$ perl -e 'use Benchmark; timethese(10000000,
{"fmul" => sub { $x=3; $x=$x*$x*$x*$x*$x*$x*$x*$x*$x},
"imul" => sub {use integer; $x=3; $x=$x*$x*$x*$x*$x*$x*$x*$x*$x} });'
Benchmark: timing 10000000 iterations of fmul, imul...
fmul: 11 wallclock secs (10.56 usr + 0.00 sys = 10.56 CPU) @
947418.29/s
(n=10000000)
imul: 9 wallclock secs ( 7.56 usr + 0.00 sys = 7.56 CPU) @
1322576.38/s
(n=10000000)

Oh, and on ActiveState (I was using Cygwin perl compiled with 32-bit ints.)

$ c:/perl/bin/perl -e 'use Benchmark; timethese(10000000,
{"fmul" => sub { $x=3; $x=$x*$x*$x*$x*$x*$x*$x*$x*$x},
"imul" => sub {use integer; $x=3; $x=$x*$x*$x*$x*$x*$x*$x*$x*$x} });'
Benchmark: timing 10000000 iterations of fmul, imul...
fmul: 10 wallclock secs (10.09 usr + 0.01 sys = 10.10 CPU) @
989609.10/s
(n=10000000)
imul: 9 wallclock secs ( 8.07 usr + 0.00 sys = 8.07 CPU) @
1238850.35/s
(n=10000000)

------------------------------------------------------------------

I should have left it alone but I decided to clean up
a script and replace a number of calls to "int()" in a
subroutine with "use integer".

I do not understand why I am getting different
results with the following code...

-------------------- begin script --------------------
use strict;

&method_a(730791);
&method_b(730791);

exit;

sub method_a {
my($g) = @_;
my $y;
$y = int((10000*$g + 14780)/3652425);
printf STDOUT "Method A = %d\n", $y;
}

sub method_b {
use integer;
my($g) = @_;
my $y;
$y = (10000*$g + 14780)/3652425;
printf STDOUT "Method B = %d\n", $y;
}
-------------------- end script --------------------

When I run it I get the following on my Win2K box:

C:\Perl\bin>buggy.pl
Method A = 2000
Method B = -351

I thought I understood "use integer" but maybe I
don't. Would someone care to explain the reason for the
different results? perl -v produces:

This is perl, v5.8.3 built for MSWin32-x86-multi-thread
(with 8 registered patches, see perl -V for more detail)

Copyright 1987-2003, Larry Wall

Binary build 809 provided by ActiveState Corp. http://www.ActiveState.com
ActiveState is a division of Sophos.
Built Feb 3 2004 00:28:51

Perl may be copied only under the terms of either the Artistic License or
the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.com/, the Perl Home Page.

TIA,
JAPH wannabe
 
S

suedecold

Thanks for the help. I first thought it may have been
an overflow problem but my logic said it should have showed
its self in both subs. I was not aware that int() kept using
doubles.

The benchmarks were informative as well. Actually I
was not trying to optimize for speed but to stay "true" to
the original code given below (thank you Gary Katch, see
http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
for more information). It also made it less noisy. However,
I think I'll revert to something that works.

Thanks again for the help. Confidence, as dangerous as
it may be, has been restored.

suedecold


Calculate date from day number
------------------------------

All division is integer division, operator % is modulus.
Given day number g, calculate year, month, and day:

function d(g)
y = (10000*g + 14780)/3652425
ddd = g - (365*y + y/4 - y/100 + y/400)
if (ddd < 0) then
y = y - 1
ddd = g - (365*y + y/4 - y/100 + y/400)
endif
mi = (100*ddd + 52)/3060
mm = (mi + 2)%12 + 1
y = y + (mi + 2)/12
dd = ddd - (mi*306 + 5)/10 + 1
return y, mm, dd
 
I

Ilya Zakharevich

[A complimentary Cc of this posting was sent to
suedecold
Thanks for the help. I first thought it may have been
an overflow problem but my logic said it should have showed
its self in both subs. I was not aware that int() kept using
doubles.

It did not. But it does nowadays...

So if you have portablility in mind, check when this change was made.
I think I did it about 3 years ago. Can't find it on p5p archives,
though - so maybe it was not me - but it should be quite recent anyway...

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top