Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Signed Integers Subtraction #268

Merged
merged 7 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Description of the upcoming release here.
- [#262](https://github.com/FuelLabs/sway-libs/pull/262) Fixes incorrect ordering comparison for IFP64, IFP128 and IFP256.
- [#263](https://github.com/FuelLabs/sway-libs/pull/263) Fixes `I256`'s returned bits.
- [#263](https://github.com/FuelLabs/sway-libs/pull/263) Fixes `I128` and `I256`'s zero or "indent" value.
- [#268](https://github.com/FuelLabs/sway-libs/pull/268) Fixes subtraction involving negative numbers for `I8`, `I16`, `I32`, `I64`, `I128`, and `I256`.


#### Breaking

Expand Down
28 changes: 8 additions & 20 deletions libs/src/signed_integers/i128.sw
Original file line number Diff line number Diff line change
Expand Up @@ -377,33 +377,21 @@ impl core::ops::Subtract for I128 {
/// Subtract a I128 from a I128. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
if (self.underlying > Self::indent()
|| self.underlying == Self::indent())
&& (other.underlying > Self::indent()
|| other.underlying == Self::indent())
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if (self.underlying > Self::indent()
|| self.underlying == Self::indent())
&& other.underlying < Self::indent()
{
res = Self::from_uint(self.underlying - Self::indent() + other.underlying);
} else if self.underlying < Self::indent()
&& (other.underlying > Self::indent()
|| other.underlying == Self::indent())
{
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent()
&& other.underlying < Self::indent()
{
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - Self::indent());
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
24 changes: 8 additions & 16 deletions libs/src/signed_integers/i16.sw
Original file line number Diff line number Diff line change
Expand Up @@ -364,29 +364,21 @@ impl core::ops::Subtract for I16 {
/// Subtract a I16 from a I16. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
if self.underlying >= Self::indent()
&& other.underlying >= Self::indent()
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if self.underlying >= Self::indent()
&& other.underlying < Self::indent()
{
res = Self::from_uint(self.underlying - Self::indent() + other.underlying);
} else if self.underlying < Self::indent()
&& other.underlying >= Self::indent()
{
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent()
&& other.underlying < Self::indent()
{
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - Self::indent());
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
35 changes: 11 additions & 24 deletions libs/src/signed_integers/i256.sw
Original file line number Diff line number Diff line change
Expand Up @@ -354,34 +354,21 @@ impl core::ops::Subtract for I256 {
/// Subtract a I256 from a I256. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
let indent = Self::indent();

if (self.underlying > indent
|| self.underlying == indent)
&& (other.underlying > indent
|| other.underlying == indent)
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + indent);
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
let q = other.underlying - indent;
res = Self::from_uint(self.underlying - q);
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if (self.underlying > indent
|| self.underlying == indent)
&& other.underlying < indent
{
res = Self::from_uint(self.underlying - indent + other.underlying);
} else if self.underlying < indent
&& (other.underlying > indent
|| other.underlying == indent)
{
res = Self::from_uint(self.underlying - (other.underlying - indent));
} else if self.underlying < indent && other.underlying < indent {
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + indent);
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - indent);
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
24 changes: 8 additions & 16 deletions libs/src/signed_integers/i32.sw
Original file line number Diff line number Diff line change
Expand Up @@ -292,29 +292,21 @@ impl core::ops::Subtract for I32 {
/// Subtract a I32 from a I32. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
if self.underlying >= Self::indent()
&& other.underlying >= Self::indent()
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if self.underlying >= Self::indent()
&& other.underlying < Self::indent()
{
res = Self::from_uint(self.underlying - Self::indent() + other.underlying);
} else if self.underlying < Self::indent()
&& other.underlying >= Self::indent()
{
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent()
&& other.underlying < Self::indent()
{
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - Self::indent());
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
24 changes: 8 additions & 16 deletions libs/src/signed_integers/i64.sw
Original file line number Diff line number Diff line change
Expand Up @@ -293,29 +293,21 @@ impl core::ops::Subtract for I64 {
/// Subtract a I64 from a I64. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
if self.underlying >= Self::indent()
&& other.underlying >= Self::indent()
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if self.underlying >= Self::indent()
&& other.underlying < Self::indent()
{
res = Self::from_uint(self.underlying - Self::indent() + other.underlying);
} else if self.underlying < Self::indent()
&& other.underlying >= Self::indent()
{
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent()
&& other.underlying < Self::indent()
{
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - Self::indent());
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
24 changes: 8 additions & 16 deletions libs/src/signed_integers/i8.sw
Original file line number Diff line number Diff line change
Expand Up @@ -363,29 +363,21 @@ impl core::ops::Subtract for I8 {
/// Subtract a I8 from a I8. Panics of overflow.
fn subtract(self, other: Self) -> Self {
let mut res = Self::new();
if self.underlying >= Self::indent()
&& other.underlying >= Self::indent()
{
if self.underlying >= Self::indent() && other.underlying >= Self::indent() { // Both Positive
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
}
} else if self.underlying >= Self::indent()
&& other.underlying < Self::indent()
{
res = Self::from_uint(self.underlying - Self::indent() + other.underlying);
} else if self.underlying < Self::indent()
&& other.underlying >= Self::indent()
{
} else if self.underlying >= Self::indent() && other.underlying < Self::indent() { // Self Positive, Other Negative
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying >= Self::indent() { // Self Negative, Other Positive
res = Self::from_uint(self.underlying - (other.underlying - Self::indent()));
} else if self.underlying < Self::indent()
&& other.underlying < Self::indent()
{
if self.underlying < other.underlying {
res = Self::from_uint(other.underlying - self.underlying + Self::indent());
} else if self.underlying < Self::indent() && other.underlying < Self::indent() { // Both Negative
if self.underlying > other.underlying {
res = Self::from_uint(self.underlying - other.underlying + Self::indent());
} else {
res = Self::from_uint(self.underlying + other.underlying - Self::indent());
res = Self::from_uint((self.underlying + Self::indent()) - other.underlying);
}
}
res
Expand Down
29 changes: 29 additions & 0 deletions tests/src/signed_integers/signed_i128/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ fn main() -> bool {
res = I128::from(u128_10) / I128::from(u128_5);
assert(res == I128::from(u128_2));

// Subtraction tests
let pos1 = I128::from(U128::from((0, 1)));
let pos2 = I128::from(U128::from((0, 2)));
let neg1 = I128::neg_from(U128::from((0, 1)));
let neg2 = I128::neg_from(U128::from((0, 2)));

// Both positive:
let res1 = pos1 - pos2;
let res1_2 = pos2 - pos1;
assert(res1 == I128::neg_from(U128::from((0, 1))));

let res2 = pos2 - pos1;
assert(res2 == I128::from(U128::from((0, 1))));

// First positive
let res3 = pos1 - neg1;
assert(res3 == I128::from(U128::from((0, 2))));

// Second positive
let res4 = neg1 - pos1;
assert(res4 == I128::neg_from(U128::from((0, 2))));

// Both negative
let res5 = neg1 - neg2;
assert(res5 == I128::from(U128::from((0, 1))));

let res6 = neg2 - neg1;
assert(res6 == I128::neg_from(U128::from((0, 1))));

// OrqEq Tests
let one_1 = I128::from(U128::from((0, 1)));
let one_2 = I128::from(U128::from((0, 1)));
Expand Down
29 changes: 29 additions & 0 deletions tests/src/signed_integers/signed_i16/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ fn main() -> bool {
res = I16::from(10u16) / I16::from(5u16);
assert(res == I16::from(2u16));

// Subtraction tests
let pos1 = I16::from(1);
let pos2 = I16::from(2);
let neg1 = I16::neg_from(1);
let neg2 = I16::neg_from(2);

// Both positive:
let res1 = pos1 - pos2;
let res1_2 = pos2 - pos1;
assert(res1 == I16::neg_from(1));

let res2 = pos2 - pos1;
assert(res2 == I16::from(1));

// First positive
let res3 = pos1 - neg1;
assert(res3 == I16::from(2));

// Second positive
let res4 = neg1 - pos1;
assert(res4 == I16::neg_from(2));

// Both negative
let res5 = neg1 - neg2;
assert(res5 == I16::from(1));

let res6 = neg2 - neg1;
assert(res6 == I16::neg_from(1));

// OrqEq Tests
let one_1 = I16::from(1u16);
let one_2 = I16::from(1u16);
Expand Down
29 changes: 29 additions & 0 deletions tests/src/signed_integers/signed_i256/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,34 @@ fn main() -> bool {
res = i256_10 / i256_5;
assert(res == i256_2);

// Subtraction tests
let pos1 = I256::from(u256_one);
let pos2 = I256::from(u256_two);
let neg1 = I256::neg_from(u256_one);
let neg2 = I256::neg_from(u256_two);

// Both positive:
let res1 = pos1 - pos2;
assert(res1 == I256::neg_from(u256_one));

let res2 = pos2 - pos1;
assert(res2 == I256::from(u256_one));

// First positive
let res3 = pos1 - neg1;
assert(res3 == I256::from(u256_two));

// Second positive
let res4 = neg1 - pos1;
assert(res4 == I256::neg_from(u256_two));

// Both negative
let res5 = neg1 - neg2;
assert(res5 == I256::from(u256_one));

let res6 = neg2 - neg1;
assert(res6 == I256::neg_from(u256_one));

// OrqEq Tests
let one_1 = I256::from(u256_one);
let one_2 = I256::from(u256_one);
Expand Down Expand Up @@ -100,5 +128,6 @@ fn main() -> bool {
assert(one_1 >= neg_one_1);
assert(one_1 >= min_1);
assert(neg_one_1 >= min_1);

true
}
29 changes: 29 additions & 0 deletions tests/src/signed_integers/signed_i32/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ fn main() -> bool {
res = I32::from(10u32) / I32::from(5u32);
assert(res == I32::from(2u32));

// Subtraction Tests
let pos1 = I32::from(1);
let pos2 = I32::from(2);
let neg1 = I32::neg_from(1);
let neg2 = I32::neg_from(2);

// Both positive:
let res1 = pos1 - pos2;
let res1_2 = pos2 - pos1;
assert(res1 == I32::neg_from(1));

let res2 = pos2 - pos1;
assert(res2 == I32::from(1));

// First positive
let res3 = pos1 - neg1;
assert(res3 == I32::from(2));

// Second positive
let res4 = neg1 - pos1;
assert(res4 == I32::neg_from(2));

// Both negative
let res5 = neg1 - neg2;
assert(res5 == I32::from(1));

let res6 = neg2 - neg1;
assert(res6 == I32::neg_from(1));

// OrqEq Tests
let one_1 = I32::from(1u32);
let one_2 = I32::from(1u32);
Expand Down
Loading
Loading