Different behaviour linux vs Win32

D

Dazza T

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?
 
P

Peter J. Holzer

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
 
A

anno4000

Dazza T said:
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
 
D

Dazza T

Peter J. Holzer said:
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?
| | | (e-mail address removed) | 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.
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top