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