Different behaviour linux vs Win32

Discussion in 'Perl Misc' started by Dazza T, Sep 10, 2006.

  1. Dazza T

    Dazza T Guest

    I have some code that is meant to take a 32-bit number [0-0xFFFFFFFF] and
    round it down to the next exact multiple of a given `step'. It uses the %
    modulo operator and assumes we are dealing with unsigned integers (yes, I
    know, but read on). If I run it on a Win32 ActiveState system, it always
    gives me the answer I expect. But when I run it on a linux system with a
    value greater than 0x8000000, it doesn't work.

    I think the problem is to do with `signed' vs `unsigned' integers and, OK, I
    can live with that. The % operator advertises different behaviour with
    negative numbers.

    *BUT* if I put a debugging print statement in the code, it starts working
    correctly again on the Linux system. Such behaviour really worries me.

    1) What's wrong with the code below and how should it be changed so it will
    work with all 32-bit unsigned integers [0-0xFFFFFFFF] on any operating
    system?

    2) Why does the intervening print statement change things?

    ===(code 1)===
    #!/usr/local/bin/perl
    use strict
    my ($base, $step);
    $step = 0x7f79;
    $base = 0xE195ED24;
    printf "BASE =%08X\n", $base;
    # Adjust it to be an exact multiple of the step so base mod step == 0
    printf "ADJST=%08X\n", ($base % $step);
    $base -= ($base % $step);
    printf "EXACT=%08X\n", $base;
    # check
    printf "CHECK=%08X\n", ($base % $step);
    ===(end code)===

    RESULTS:-

    1. Windows 2000 Pro; perl, v5.6.1 built for MSWin32-x86-multi-thread
    BASE =E195ED24
    ADJST=000054E3
    EXACT=E1959841
    CHECK=00000000 (expecting zero)

    2. perl, v5.6.0 built for i386-linux
    BASE =E195ED24
    ADJST=00003711
    EXACT=E195B613
    CHECK=00001DD2 (wrong!)

    OK, so the original number is interpreted here as a negative number and % is
    advertised
    as treating negative numbers differently from positive ones.

    BUT if we add a debugging print statement to the code, it works as we
    expect!

    ===(code 2)===
    #!/usr/local/bin/perl
    use strict
    my ($base, $step);
    $step = 0x7f79;
    $base = 0xE195ED24;
    printf "BASE =%08X\n", $base;
    # PUT A PRINT STATEMENT INBETWEEN...
    print "$base $step\n", ($base / $step), "\n", ($base % $step), "\n";
    # Adjust it to be an exact multiple of the step so base mod step == 0
    printf "ADJST=%08X\n", ($base % $step);
    $base -= ($base % $step);
    printf "EXACT=%08X\n", $base;
    # check
    printf "CHECK=%08X\n", ($base % $step);
    ===(end code)===

    3. perl, v5.6.0 built for i386-linux
    BASE =E195ED24
    3784699172 32633
    115977.665921
    21731
    ADJST=000054E3
    EXACT=E1959841
    CHECK=00000000

    Why is this?
    Dazza T, Sep 10, 2006
    #1
    1. Advertising

  2. On 2006-09-10 14:22, Dazza T <> wrote:
    > I have some code that is meant to take a 32-bit number [0-0xFFFFFFFF] and
    > round it down to the next exact multiple of a given `step'. It uses the %
    > modulo operator and assumes we are dealing with unsigned integers (yes, I
    > know, but read on). If I run it on a Win32 ActiveState system, it always
    > gives me the answer I expect. But when I run it on a linux system with a
    > value greater than 0x8000000, it doesn't work.
    >
    > I think the problem is to do with `signed' vs `unsigned' integers and, OK, I
    > can live with that. The % operator advertises different behaviour with
    > negative numbers.
    >
    >===(code 1)===
    > #!/usr/local/bin/perl
    > use strict
    > my ($base, $step);
    > $step = 0x7f79;
    > $base = 0xE195ED24;
    > printf "BASE =%08X\n", $base;
    > # Adjust it to be an exact multiple of the step so base mod step == 0
    > printf "ADJST=%08X\n", ($base % $step);
    > $base -= ($base % $step);
    > printf "EXACT=%08X\n", $base;
    > # check
    > printf "CHECK=%08X\n", ($base % $step);
    >===(end code)===
    >
    > RESULTS:-
    >
    > 1. Windows 2000 Pro; perl, v5.6.1 built for MSWin32-x86-multi-thread
    > BASE =E195ED24
    > ADJST=000054E3
    > EXACT=E1959841
    > CHECK=00000000 (expecting zero)
    >
    > 2. perl, v5.6.0 built for i386-linux
    > BASE =E195ED24
    > ADJST=00003711
    > EXACT=E195B613
    > CHECK=00001DD2 (wrong!)


    perl, v5.6.1 built for i386-linux
    BASE =E195ED24
    ADJST=000054E3
    EXACT=E1959841
    CHECK=00000000

    > 1) What's wrong with the code below and how should it be changed so it will
    > work with all 32-bit unsigned integers [0-0xFFFFFFFF] on any operating
    > system?


    The same result as with perl 5.6.1 under Windows. So it doesn't seem to
    be a difference between Linux and Windows, but between perl 5.6.0 and
    5.6.1. Probably a bug in 5.6.0 which was corrected in 5.6.1.

    BTW, these perl versions are 6 years old. Do yourself a favour and
    upgrade to a current version of perl (and to a current version of Linux,
    too).

    > *BUT* if I put a debugging print statement in the code, it starts working
    > correctly again on the Linux system. Such behaviour really worries me.
    >
    > 2) Why does the intervening print statement change things?
    >
    >===(code 2)===
    > #!/usr/local/bin/perl
    > use strict
    > my ($base, $step);
    > $step = 0x7f79;
    > $base = 0xE195ED24;
    > printf "BASE =%08X\n", $base;
    > # PUT A PRINT STATEMENT INBETWEEN...
    > print "$base $step\n", ($base / $step), "\n", ($base % $step), "\n";
    > # Adjust it to be an exact multiple of the step so base mod step == 0
    > printf "ADJST=%08X\n", ($base % $step);
    > $base -= ($base % $step);
    > printf "EXACT=%08X\n", $base;
    > # check
    > printf "CHECK=%08X\n", ($base % $step);
    >===(end code)===
    >
    > 3. perl, v5.6.0 built for i386-linux
    > BASE =E195ED24
    > 3784699172 32633
    > 115977.665921
    > 21731
    > ADJST=000054E3
    > EXACT=E1959841
    > CHECK=00000000
    >
    > Why is this?


    Perl scalars can be strings, floating point numbers, integral numbers
    and a few other things. Depending on how to use them they can be one or
    several of these types at once.

    If you use Devel::peek::Dump to look at $base, you can see that the
    print statement changes $base:

    | #!/usr/local/bin/perl
    | use Devel::peek;
    | use strict;
    | my ($base, $step);
    | $step = 0x7f79;
    | $base = 0xE195ED24;
    | printf "BASE =%08X\n", $base;
    | Dump ($base);
    | print "$base $step\n", ($base / $step), "\n", ($base % $step), "\n";
    | Dump ($base);
    | # Adjust it to be an exact multiple of the step so base mod step == 0
    | printf "ADJST=%08X\n", ($base % $step);
    | $base -= ($base % $step);
    | printf "EXACT=%08X\n", $base;
    | # check
    | printf "CHECK=%08X\n", ($base % $step);


    | BASE =E195ED24
    | SV = IV(0x80f6310) at 0x80f59e8
    | REFCNT = 1
    | FLAGS = (PADBUSY,PADMY,IOK,pIOK,IsUV)
    | UV = 3784699172

    Here $base is an unsigned integer (UV).

    | 3784699172 32633
    | 115977.665921
    | 21731
    | SV = PVNV(0x80eb470) at 0x80f59e8
    | REFCNT = 1
    | FLAGS = (PADBUSY,PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK,IsUV)
    | UV = 3784699172
    | NV = 3784699172
    | PV = 0x80ef570 "3784699172"\0
    | CUR = 10
    | LEN = 11

    But now $base is also a floating point number (NV) and a string (PV).
    This is because you used it in a floating point division and a string
    interpolation. My guess is that perl takes the NV in a % operation if
    there is one, so it gets the correct result. If there is no NV, it takes
    the UV, but unsigned % seems to be buggy in perl 5.6.0 (it does a signed
    % instead).

    | ADJST=000054E3
    | EXACT=E1959841
    | CHECK=00000000

    hp


    --
    _ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
    |_|_) | Sysadmin WSR | > ist?
    | | | | Was sonst wäre der Sinn des Erfindens?
    __/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
    Peter J. Holzer, Sep 10, 2006
    #2
    1. Advertising

  3. Dazza T

    -berlin.de Guest

    Dazza T <> wrote in comp.lang.perl.misc:

    > I have some code that is meant to take a 32-bit number [0-0xFFFFFFFF] and
    > round it down to the next exact multiple of a given `step'. It uses the %
    > modulo operator and assumes we are dealing with unsigned integers (yes, I
    > know, but read on). If I run it on a Win32 ActiveState system, it always
    > gives me the answer I expect. But when I run it on a linux system with a
    > value greater than 0x8000000, it doesn't work.


    [snippage]

    > 1. Windows 2000 Pro; perl, v5.6.1 built for MSWin32-x86-multi-thread


    > 2. perl, v5.6.0 built for i386-linux


    > 3. perl, v5.6.0 built for i386-linux


    > Why is this?


    I don't know. You may have found a bug in 5.6.0 or 5.6.1.

    These are ancient versions of Perl. Upgrade, and if the error persists,
    file a bug report. I can't reproduce it with 5.8.7 or 5.9.4.

    Anno
    -berlin.de, Sep 10, 2006
    #3
  4. Dazza T

    Dazza T Guest

    "Peter J. Holzer" <> wrote in message
    news:...
    > On 2006-09-10 14:22, Dazza T <> wrote:
    > > I have some code that is meant to take a 32-bit number [0-0xFFFFFFFF]

    and
    > > round it down to the next exact multiple of a given `step'. It uses the

    %
    > > modulo operator and assumes we are dealing with unsigned integers (yes,

    I
    > > know, but read on). If I run it on a Win32 ActiveState system, it always
    > > gives me the answer I expect. But when I run it on a linux system with a
    > > value greater than 0x8000000, it doesn't work.
    > >
    > > I think the problem is to do with `signed' vs `unsigned' integers and,

    OK, I
    > > can live with that. The % operator advertises different behaviour with
    > > negative numbers.
    > >

    [snipped]
    > The same result as with perl 5.6.1 under Windows. So it doesn't seem to
    > be a difference between Linux and Windows, but between perl 5.6.0 and
    > 5.6.1. Probably a bug in 5.6.0 which was corrected in 5.6.1.
    >
    > BTW, these perl versions are 6 years old. Do yourself a favour and
    > upgrade to a current version of perl (and to a current version of Linux,
    > too).
    >
    > > *BUT* if I put a debugging print statement in the code, it starts

    working
    > > correctly again on the Linux system. Such behaviour really worries me.
    > >
    > > 2) Why does the intervening print statement change things?
    > >

    [snipped]
    >
    > Perl scalars can be strings, floating point numbers, integral numbers
    > and a few other things. Depending on how to use them they can be one or
    > several of these types at once.
    >
    > If you use Devel::peek::Dump to look at $base, you can see that the
    > print statement changes $base:
    >

    [snipped]
    >
    > But now $base is also a floating point number (NV) and a string (PV).
    > This is because you used it in a floating point division and a string
    > interpolation. My guess is that perl takes the NV in a % operation if
    > there is one, so it gets the correct result. If there is no NV, it takes
    > the UV, but unsigned % seems to be buggy in perl 5.6.0 (it does a signed
    > % instead).
    >

    [snipped]
    >
    > hp
    >
    >
    > --
    > _ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
    > |_|_) | Sysadmin WSR | > ist?
    > | | | | Was sonst wäre der Sinn des Erfindens?
    > __/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd


    BTW, these perl versions are 6 years old. Do yourself a favour and
    upgrade to a current version of perl (and to a current version of Linux,
    too).

    -- Point taken and I'd love to upgrade but my web site provider gives me
    what he gives. That's why I keep the 5.6 version on my Win32 system.


    But now $base is also a floating point number (NV) and a string (PV).
    This is because you used it in a floating point division and a string
    interpolation. My guess is that perl takes the NV in a % operation if
    there is one, so it gets the correct result. If there is no NV, it takes
    the UV, but unsigned % seems to be buggy in perl 5.6.0 (it does a signed
    % instead).

    -- This would seem to be consistent. Thanks for the hints about
    Devel::peek::Dump. I can see a good workaround for this now.

    Dazza.
    Dazza T, Sep 10, 2006
    #4
    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. CharlesRiver
    Replies:
    0
    Views:
    396
    CharlesRiver
    Apr 3, 2006
  2. Andy Chambers
    Replies:
    1
    Views:
    374
    Daniel Dyer
    May 14, 2007
  3. colibri
    Replies:
    7
    Views:
    300
    Eric Sosman
    Sep 23, 2007
  4. __PaTeR
    Replies:
    7
    Views:
    466
    Barry Schwarz
    Jan 1, 2009
  5. Michele Dondi
    Replies:
    4
    Views:
    242
    A. Sinan Unur
    Oct 27, 2004
Loading...

Share This Page