use integer != int()

Discussion in 'Perl Misc' started by suedecold, Jun 26, 2004.

  1. suedecold

    suedecold Guest

    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
     
    suedecold, Jun 26, 2004
    #1
    1. Advertising

  2. 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
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
     
    Tassilo v. Parseval, Jun 26, 2004
    #2
    1. Advertising

  3. 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)

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

    "suedecold" <> wrote in message
    news:...
    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
     
    Aaron W. West, Jun 26, 2004
    #3
  4. suedecold

    suedecold Guest

    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
     
    suedecold, Jun 26, 2004
    #4
  5. [A complimentary Cc of this posting was sent to
    suedecold
    <>], who wrote in article <>:
    > 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
     
    Ilya Zakharevich, Jul 2, 2004
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Schnoffos
    Replies:
    2
    Views:
    1,236
    Martien Verbruggen
    Jun 27, 2003
  2. Hal Styli
    Replies:
    14
    Views:
    1,681
    Old Wolf
    Jan 20, 2004
  3. arun
    Replies:
    8
    Views:
    467
    Dave Thompson
    Jul 31, 2006
  4. aling
    Replies:
    8
    Views:
    980
    Jim Langston
    Oct 20, 2005
  5. Robben
    Replies:
    14
    Views:
    569
    Old Wolf
    Dec 27, 2005
Loading...

Share This Page