pif_LongInt

by Popisfizzy
Double, triple, and quadruple-precision integers, both signed and unsigned.
ID:2700412
 
Resolved
Due to a typo and a missing return value for an overloaded operator, comparison operators would sometimes report incorrect results.
BYOND Version:514
Operating System:Windows 10 Home 64-bit
Web Browser:
Applies to:DM Language
Status: Resolved (b1.2.3.20210718)

This issue has been resolved.
Descriptive Problem Summary:
I'm getting wrong and inconsistent results when comparing integers, especially when the difference between them is only 1, but there is at least one case that fails regardless. Both the signed and unsigned integers are affected in various ways.

Numbered Steps to Reproduce Problem:
1. Download this project, extract, include THIS library, compile, and run.
2. Run the verb, choose a positive integer, and examine the incorrect results. The results are commented in the code. You can also find them in "Output Results.dm".
3. Try rerunning after setting the "diff" var to a higher value. Most of the results should now be correct, except for one.
4. Run again with a "diff" of 0 (equal). Now two of the results will be incorrect.

Note that I have not tested comparisons with negative integers, so there might be even more issues that what this has revealed. I have mostly just been working with the unsigned integers.

Sample output when the difference is 1:
/*
A int: 5 IS NOT less than or equal to 4
A uint: 5 IS less than or equal to 4

B int: 4 IS NOT less than or equal to 5
B uint: 4 IS less than or equal to 5

C int: 5 IS NOT less than 4
C uint: 5 IS less than 4

D int: 4 IS less than 5
D uint: 4 IS less than 5

E int: 5 IS NOT equal to 4
E uint: 5 IS NOT equal to 4

F int: 4 IS NOT equal to 5
F uint: 4 IS NOT equal to 5

G int: 5 IS NOT equal to 4
G uint: 5 IS NOT equal to 4

H int: 4 IS NOT equal to 5
H uint: 4 IS NOT equal to 5

I int: 4 IS NOT greater than 5
I uint: 4 IS NOT greater than 5

J int: 5 IS greater than 4
J uint: 5 IS NOT greater than 4

K int: 4 IS NOT greater than or equal to 5
K uint: 4 IS NOT greater than or equal to 5

L int: 5 IS greater than or equal to 4
L uint: 5 IS NOT greater than or equal to 4
*/


Sample output when the difference is 2:
/*
A int: 5 IS NOT less than or equal to 3
A uint: 5 IS NOT less than or equal to 3

B int: 3 IS NOT less than or equal to 5
B uint: 3 IS less than or equal to 5

C int: 5 IS NOT less than 3
C uint: 5 IS NOT less than 3

D int: 3 IS less than 5
D uint: 3 IS less than 5

E int: 5 IS NOT equal to 3
E uint: 5 IS NOT equal to 3

F int: 3 IS NOT equal to 5
F uint: 3 IS NOT equal to 5

G int: 5 IS NOT equal to 3
G uint: 5 IS NOT equal to 3

H int: 3 IS NOT equal to 5
H uint: 3 IS NOT equal to 5

I int: 3 IS NOT greater than 5
I uint: 3 IS NOT greater than 5

J int: 5 IS greater than 3
J uint: 5 IS greater than 3

K int: 3 IS NOT greater than or equal to 5
K uint: 3 IS NOT greater than or equal to 5

L int: 5 IS greater than or equal to 3
L uint: 5 IS greater than or equal to 3
*/


Sample output when the difference is 0:
/*
A int: 5 IS NOT less than or equal to 5
A uint: 5 IS less than or equal to 5

B int: 5 IS NOT less than or equal to 5
B uint: 5 IS less than or equal to 5

C int: 5 IS NOT less than 5
C uint: 5 IS NOT less than 5

D int: 5 IS NOT less than 5
D uint: 5 IS NOT less than 5

E int: 5 IS equal to 5
E uint: 5 IS equal to 5

F int: 5 IS equal to 5
F uint: 5 IS equal to 5

G int: 5 IS equal to 5
G uint: 5 IS equal to 5

H int: 5 IS equal to 5
H uint: 5 IS equal to 5

I int: 5 IS NOT greater than 5
I uint: 5 IS NOT greater than 5

J int: 5 IS NOT greater than 5
J uint: 5 IS NOT greater than 5

K int: 5 IS greater than or equal to 5
K uint: 5 IS greater than or equal to 5

L int: 5 IS greater than or equal to 5
L uint: 5 IS greater than or equal to 5
*/


Code (click to download):
mob/Login()
. = ..()
// For better readability:
winset(client, "outputwindow.output", "max-lines=0;font-family=Consolas;font-size=12")

client/verb
Test_Comparison_Bugs(x as num)

var
diff = 1

pif_LongInt
int_lesser = new /pif_LongInt/Signed32(x - diff)
int_greater = new /pif_LongInt/Signed32(x)

uint_lesser = new /pif_LongInt/Unsigned32(x - diff)
uint_greater = new /pif_LongInt/Unsigned32(x)

src << "Comparison Test Cases:"

if(int_greater <= int_lesser)
src << "A int: [int_greater.Print()] IS less than or equal to [int_lesser.Print()]"
else
// Correct when different, but wrong when the difference is 0.
src << "A int: [int_greater.Print()] IS NOT less than or equal to [int_lesser.Print()]"

if(uint_greater <= uint_lesser)
// Wrong answer!
src << "A uint: [uint_greater.Print()] IS less than or equal to [uint_lesser.Print()]"
else
src << "A uint: [uint_greater.Print()] IS NOT less than or equal to [uint_lesser.Print()]"


src << ""


if(int_lesser <= int_greater)
src << "B int: [int_lesser.Print()] IS less than or equal to [int_greater.Print()]"
else
// Wrong answer! This one is always wrong, whether the difference is 0, 1, or greater.
src << "B int: [int_lesser.Print()] IS NOT less than or equal to [int_greater.Print()]"

if(uint_lesser <= uint_greater)
// Correct.
src << "B uint: [uint_lesser.Print()] IS less than or equal to [uint_greater.Print()]"
else
src << "B uint: [uint_lesser.Print()] IS NOT less than or equal to [uint_greater.Print()]"


src << ""


if(int_greater < int_lesser)
src << "C int: [int_greater.Print()] IS less than [int_lesser.Print()]"
else
// Correct.
src << "C int: [int_greater.Print()] IS NOT less than [int_lesser.Print()]"

if(uint_greater < uint_lesser)
// Wrong answer!
src << "C uint: [uint_greater.Print()] IS less than [uint_lesser.Print()]"
else
src << "C uint: [uint_greater.Print()] IS NOT less than [uint_lesser.Print()]"


src << ""


if(int_lesser < int_greater)
// Correct.
src << "D int: [int_lesser.Print()] IS less than [int_greater.Print()]"
else
src << "D int: [int_lesser.Print()] IS NOT less than [int_greater.Print()]"

if(uint_lesser < uint_greater)
// Correct.
src << "D uint: [uint_lesser.Print()] IS less than [uint_greater.Print()]"
else
src << "D uint: [uint_lesser.Print()] IS NOT less than [uint_greater.Print()]"


src << ""


if(int_greater ~= int_lesser)
src << "E int: [int_greater.Print()] IS equal to [int_lesser.Print()]"
else
// Correct.
src << "E int: [int_greater.Print()] IS NOT equal to [int_lesser.Print()]"

if(uint_greater ~= uint_lesser)
src << "E uint: [uint_greater.Print()] IS equal to [uint_lesser.Print()]"
else
// Correct.
src << "E uint: [uint_greater.Print()] IS NOT equal to [uint_lesser.Print()]"


src << ""


if(int_lesser ~= int_greater)
src << "F int: [int_lesser.Print()] IS equal to [int_greater.Print()]"
else
// Correct.
src << "F int: [int_lesser.Print()] IS NOT equal to [int_greater.Print()]"

if(uint_lesser ~= uint_greater)
src << "F uint: [uint_lesser.Print()] IS equal to [uint_greater.Print()]"
else
// Correct.
src << "F uint: [uint_lesser.Print()] IS NOT equal to [uint_greater.Print()]"


src << ""


if(int_greater ~! int_lesser)
// Correct.
src << "G int: [int_greater.Print()] IS NOT equal to [int_lesser.Print()]"
else
src << "G int: [int_greater.Print()] IS equal to [int_lesser.Print()]"

if(uint_greater ~! uint_lesser)
// Correct.
src << "G uint: [uint_greater.Print()] IS NOT equal to [uint_lesser.Print()]"
else
src << "G uint: [uint_greater.Print()] IS equal to [uint_lesser.Print()]"


src << ""


if(int_lesser ~! int_greater)
// Correct.
src << "H int: [int_lesser.Print()] IS NOT equal to [int_greater.Print()]"
else
src << "H int: [int_lesser.Print()] IS equal to [int_greater.Print()]"

if(uint_lesser ~! uint_greater)
// Correct.
src << "H uint: [uint_lesser.Print()] IS NOT equal to [uint_greater.Print()]"
else
src << "H uint: [uint_lesser.Print()] IS equal to [uint_greater.Print()]"


src << ""


if(int_lesser > int_greater)
src << "I int: [int_lesser.Print()] IS greater than [int_greater.Print()]"
else
// Correct.
src << "I int: [int_lesser.Print()] IS NOT greater than [int_greater.Print()]"

if(uint_lesser > uint_greater)
src << "I uint: [uint_lesser.Print()] IS greater than [uint_greater.Print()]"
else
// Correct.
src << "I uint: [uint_lesser.Print()] IS NOT greater than [uint_greater.Print()]"


src << ""


if(int_greater > int_lesser)
// Correct.
src << "J int: [int_greater.Print()] IS greater than [int_lesser.Print()]"
else
src << "J int: [int_greater.Print()] IS NOT greater than [int_lesser.Print()]"

if(uint_greater > uint_lesser)
src << "J uint: [uint_greater.Print()] IS greater than [uint_lesser.Print()]"
else
// Wrong answer!
src << "J uint: [uint_greater.Print()] IS NOT greater than [uint_lesser.Print()]"


src << ""


if(int_lesser >= int_greater)
src << "K int: [int_lesser.Print()] IS greater than or equal to [int_greater.Print()]"
else
// Correct.
src << "K int: [int_lesser.Print()] IS NOT greater than or equal to [int_greater.Print()]"

if(uint_lesser >= uint_greater)
src << "K uint: [uint_lesser.Print()] IS greater than or equal to [uint_greater.Print()]"
else
// Correct.
src << "K uint: [uint_lesser.Print()] IS NOT greater than or equal to [uint_greater.Print()]"


src << ""


if(int_greater >= int_lesser)
// Correct.
src << "L int: [int_greater.Print()] IS greater than or equal to [int_lesser.Print()]"
else
src << "L int: [int_greater.Print()] IS NOT greater than or equal to [int_lesser.Print()]"

if(uint_greater >= uint_lesser)
src << "L uint: [uint_greater.Print()] IS greater than or equal to [uint_lesser.Print()]"
else
// Wrong answer!
src << "L uint: [uint_greater.Print()] IS NOT greater than or equal to [uint_lesser.Print()]"


src << "\n"


Workarounds:
Convert the integers to native numbers, make the comparison, then convert the result back into an integer.
Popisfizzy changed status to 'Verified'
Popisfizzy resolved issue with message:
Due to a typo and a missing return value for an overloaded operator, comparison operators would sometimes report incorrect results.