diff --git a/examples/gno.land/p/demo/int256/absolute.gno b/examples/gno.land/p/demo/int256/absolute.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/absolute.gno rename to examples/gno.land/p/demo/int256/absolute.gnoA diff --git a/examples/gno.land/p/demo/int256/absolute_test.gno b/examples/gno.land/p/demo/int256/absolute_test.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/absolute_test.gno rename to examples/gno.land/p/demo/int256/absolute_test.gnoA diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno deleted file mode 100644 index 8926fe1d6de..00000000000 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ /dev/null @@ -1,202 +0,0 @@ -package int256 - -import "gno.land/p/demo/uint256" - -func (z *Int) Add(x, y *Int) *Int { - z.initiateAbs() - - if x.neg == y.neg { - // If both numbers have the same sign, add their absolute values - z.abs.Add(x.abs, y.abs) - z.neg = x.neg - } else { - switch x.abs.Cmp(y.abs) { - case 1: // x > y - z.abs.Sub(x.abs, y.abs) - z.neg = x.neg - case -1: // x < y - z.abs.Sub(y.abs, x.abs) - z.neg = y.neg - case 0: // x == y - z.abs = uint256.NewUint(0) - } - } - - return z -} - -// AddUint256 set z to the sum x + y, where y is a uint256, and returns z -func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { - if x.neg { - if x.abs.Gt(y) { - z.abs.Sub(x.abs, y) - z.neg = true - } else { - z.abs.Sub(y, x.abs) - z.neg = false - } - } else { - z.abs.Add(x.abs, y) - z.neg = false - } - return z -} - -// Sets z to the sum x + y, where z and x are uint256s and y is an int256. -func AddDelta(z, x *uint256.Uint, y *Int) { - if y.neg { - z.Sub(x, y.abs) - } else { - z.Add(x, y.abs) - } -} - -// Sets z to the sum x + y, where z and x are uint256s and y is an int256. -func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { - var overflow bool - if y.neg { - _, overflow = z.SubOverflow(x, y.abs) - } else { - _, overflow = z.AddOverflow(x, y.abs) - } - return overflow -} - -// Sub sets z to the difference x-y and returns z. -func (z *Int) Sub(x, y *Int) *Int { - z.initiateAbs() - - if x.neg != y.neg { - // If sign are different, add the absolute values - z.abs.Add(x.abs, y.abs) - z.neg = x.neg - } else { - switch x.abs.Cmp(y.abs) { - case 1: // x > y - z.abs.Sub(x.abs, y.abs) - z.neg = x.neg - case -1: // x < y - z.abs.Sub(y.abs, x.abs) - z.neg = !x.neg - case 0: // x == y - z.abs = uint256.NewUint(0) - } - } - - // Ensure zero is always positive - if z.abs.IsZero() { - z.neg = false - } - return z -} - -// SubUint256 set z to the difference x - y, where y is a uint256, and returns z -func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { - if x.neg { - z.abs.Add(x.abs, y) - z.neg = true - } else { - if x.abs.Lt(y) { - z.abs.Sub(y, x.abs) - z.neg = true - } else { - z.abs.Sub(x.abs, y) - z.neg = false - } - } - return z -} - -// Mul sets z to the product x*y and returns z. -func (z *Int) Mul(x, y *Int) *Int { - z.initiateAbs() - - z.abs = z.abs.Mul(x.abs, y.abs) - z.neg = x.neg != y.neg && !z.abs.IsZero() // 0 has no sign - return z -} - -// MulUint256 sets z to the product x*y, where y is a uint256, and returns z -func (z *Int) MulUint256(x *Int, y *uint256.Uint) *Int { - z.abs.Mul(x.abs, y) - if z.abs.IsZero() { - z.neg = false - } else { - z.neg = x.neg - } - return z -} - -// Div sets z to the quotient x/y for y != 0 and returns z. -func (z *Int) Div(x, y *Int) *Int { - z.initiateAbs() - - if y.abs.IsZero() { - panic("division by zero") - } - - z.abs.Div(x.abs, y.abs) - z.neg = (x.neg != y.neg) && !z.abs.IsZero() // 0 has no sign - - return z -} - -// DivUint256 sets z to the quotient x/y, where y is a uint256, and returns z -// If y == 0, z is set to 0 -func (z *Int) DivUint256(x *Int, y *uint256.Uint) *Int { - z.abs.Div(x.abs, y) - if z.abs.IsZero() { - z.neg = false - } else { - z.neg = x.neg - } - return z -} - -// Quo sets z to the quotient x/y for y != 0 and returns z. -// If y == 0, a division-by-zero run-time panic occurs. -// OBS: differs from mempooler int256, we need to panic manually if y == 0 -// Quo implements truncated division (like Go); see QuoRem for more details. -func (z *Int) Quo(x, y *Int) *Int { - if y.IsZero() { - panic("division by zero") - } - - z.initiateAbs() - - z.abs = z.abs.Div(x.abs, y.abs) - z.neg = !(z.abs.IsZero()) && x.neg != y.neg // 0 has no sign - return z -} - -// Rem sets z to the remainder x%y for y != 0 and returns z. -// If y == 0, a division-by-zero run-time panic occurs. -// OBS: differs from mempooler int256, we need to panic manually if y == 0 -// Rem implements truncated modulus (like Go); see QuoRem for more details. -func (z *Int) Rem(x, y *Int) *Int { - if y.IsZero() { - panic("division by zero") - } - - z.initiateAbs() - - z.abs.Mod(x.abs, y.abs) - z.neg = z.abs.Sign() > 0 && x.neg // 0 has no sign - return z -} - -// Mod sets z to the modulus x%y for y != 0 and returns z. -// If y == 0, z is set to 0 (OBS: differs from the big.Int) -func (z *Int) Mod(x, y *Int) *Int { - if x.neg { - z.abs.Div(x.abs, y.abs) - z.abs.Add(z.abs, one) - z.abs.Mul(z.abs, y.abs) - z.abs.Sub(z.abs, x.abs) - z.abs.Mod(z.abs, y.abs) - } else { - z.abs.Mod(x.abs, y.abs) - } - z.neg = false - return z -} diff --git a/examples/gno.land/p/demo/int256/arithmetic.gnoA b/examples/gno.land/p/demo/int256/arithmetic.gnoA new file mode 100644 index 00000000000..7230af65f8e --- /dev/null +++ b/examples/gno.land/p/demo/int256/arithmetic.gnoA @@ -0,0 +1,202 @@ +package int256 + +import "gno.land/p/demo/uint256" + +func (z *Int) Add(x, y *Int) *Int { + z.initiateAbs() + + if x.neg == y.neg { + // If both numbers have the same sign, add their absolute values + z.abs.Add(&x.abs, &y.abs) + z.neg = x.neg + } else { + switch x.abs.Cmp(y.abs) { + case 1: // x > y + z.abs.Sub(x.abs, y.abs) + z.neg = x.neg + case -1: // x < y + z.abs.Sub(y.abs, x.abs) + z.neg = y.neg + case 0: // x == y + z.abs = uint256.NewUint(0) + } + } + + return z +} + +// AddUint256 set z to the sum x + y, where y is a uint256, and returns z +// func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { +// if x.neg { +// if x.abs.Gt(y) { +// z.abs.Sub(x.abs, y) +// z.neg = true +// } else { +// z.abs.Sub(y, x.abs) +// z.neg = false +// } +// } else { +// z.abs.Add(x.abs, y) +// z.neg = false +// } +// return z +// } + +// // Sets z to the sum x + y, where z and x are uint256s and y is an int256. +// func AddDelta(z, x *uint256.Uint, y *Int) { +// if y.neg { +// z.Sub(x, y.abs) +// } else { +// z.Add(x, y.abs) +// } +// } + +// // Sets z to the sum x + y, where z and x are uint256s and y is an int256. +// func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { +// var overflow bool +// if y.neg { +// _, overflow = z.SubOverflow(x, y.abs) +// } else { +// _, overflow = z.AddOverflow(x, y.abs) +// } +// return overflow +// } + +// // Sub sets z to the difference x-y and returns z. +// func (z *Int) Sub(x, y *Int) *Int { +// z.initiateAbs() + +// if x.neg != y.neg { +// // If sign are different, add the absolute values +// z.abs.Add(x.abs, y.abs) +// z.neg = x.neg +// } else { +// switch x.abs.Cmp(y.abs) { +// case 1: // x > y +// z.abs.Sub(x.abs, y.abs) +// z.neg = x.neg +// case -1: // x < y +// z.abs.Sub(y.abs, x.abs) +// z.neg = !x.neg +// case 0: // x == y +// z.abs = uint256.NewUint(0) +// } +// } + +// // Ensure zero is always positive +// if z.abs.IsZero() { +// z.neg = false +// } +// return z +// } + +// // SubUint256 set z to the difference x - y, where y is a uint256, and returns z +// func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { +// if x.neg { +// z.abs.Add(x.abs, y) +// z.neg = true +// } else { +// if x.abs.Lt(y) { +// z.abs.Sub(y, x.abs) +// z.neg = true +// } else { +// z.abs.Sub(x.abs, y) +// z.neg = false +// } +// } +// return z +// } + +// // Mul sets z to the product x*y and returns z. +// func (z *Int) Mul(x, y *Int) *Int { +// z.initiateAbs() + +// z.abs = z.abs.Mul(x.abs, y.abs) +// z.neg = x.neg != y.neg && !z.abs.IsZero() // 0 has no sign +// return z +// } + +// // MulUint256 sets z to the product x*y, where y is a uint256, and returns z +// func (z *Int) MulUint256(x *Int, y *uint256.Uint) *Int { +// z.abs.Mul(x.abs, y) +// if z.abs.IsZero() { +// z.neg = false +// } else { +// z.neg = x.neg +// } +// return z +// } + +// // Div sets z to the quotient x/y for y != 0 and returns z. +// func (z *Int) Div(x, y *Int) *Int { +// z.initiateAbs() + +// if y.abs.IsZero() { +// panic("division by zero") +// } + +// z.abs.Div(x.abs, y.abs) +// z.neg = (x.neg != y.neg) && !z.abs.IsZero() // 0 has no sign + +// return z +// } + +// // DivUint256 sets z to the quotient x/y, where y is a uint256, and returns z +// // If y == 0, z is set to 0 +// func (z *Int) DivUint256(x *Int, y *uint256.Uint) *Int { +// z.abs.Div(x.abs, y) +// if z.abs.IsZero() { +// z.neg = false +// } else { +// z.neg = x.neg +// } +// return z +// } + +// // Quo sets z to the quotient x/y for y != 0 and returns z. +// // If y == 0, a division-by-zero run-time panic occurs. +// // OBS: differs from mempooler int256, we need to panic manually if y == 0 +// // Quo implements truncated division (like Go); see QuoRem for more details. +// func (z *Int) Quo(x, y *Int) *Int { +// if y.IsZero() { +// panic("division by zero") +// } + +// z.initiateAbs() + +// z.abs = z.abs.Div(x.abs, y.abs) +// z.neg = !(z.abs.IsZero()) && x.neg != y.neg // 0 has no sign +// return z +// } + +// // Rem sets z to the remainder x%y for y != 0 and returns z. +// // If y == 0, a division-by-zero run-time panic occurs. +// // OBS: differs from mempooler int256, we need to panic manually if y == 0 +// // Rem implements truncated modulus (like Go); see QuoRem for more details. +// func (z *Int) Rem(x, y *Int) *Int { +// if y.IsZero() { +// panic("division by zero") +// } + +// z.initiateAbs() + +// z.abs.Mod(x.abs, y.abs) +// z.neg = z.abs.Sign() > 0 && x.neg // 0 has no sign +// return z +// } + +// // Mod sets z to the modulus x%y for y != 0 and returns z. +// // If y == 0, z is set to 0 (OBS: differs from the big.Int) +// func (z *Int) Mod(x, y *Int) *Int { +// if x.neg { +// z.abs.Div(x.abs, y.abs) +// z.abs.Add(z.abs, one) +// z.abs.Mul(z.abs, y.abs) +// z.abs.Sub(z.abs, x.abs) +// z.abs.Mod(z.abs, y.abs) +// } else { +// z.abs.Mod(x.abs, y.abs) +// } +// z.neg = false +// return z +// } diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno deleted file mode 100644 index 4cfa306890a..00000000000 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ /dev/null @@ -1,571 +0,0 @@ -package int256 - -import ( - "testing" - - "gno.land/p/demo/uint256" -) - -func TestAdd(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "1"}, - {"1", "0", "1"}, - {"1", "1", "2"}, - {"1", "2", "3"}, - // NEGATIVE - {"-1", "1", "0"}, - {"1", "-1", "0"}, - {"3", "-3", "0"}, - {"-1", "-1", "-2"}, - {"-1", "-2", "-3"}, - {"-1", "3", "2"}, - {"3", "-1", "2"}, - // OVERFLOW - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Add(x, y) - - if got.Neq(want) { - t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestAddUint256(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "1"}, - {"1", "0", "1"}, - {"1", "1", "2"}, - {"1", "2", "3"}, - {"-1", "1", "0"}, - {"-1", "3", "2"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "1"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639934", "-1"}, - // OVERFLOW - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := uint256.FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.AddUint256(x, y) - - if got.Neq(want) { - t.Errorf("AddUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestAddDelta(t *testing.T) { - tests := []struct { - z, x, y, want string - }{ - {"0", "0", "0", "0"}, - {"0", "0", "1", "1"}, - {"0", "1", "0", "1"}, - {"0", "1", "1", "2"}, - {"1", "2", "3", "5"}, - {"5", "10", "-3", "7"}, - // underflow - {"1", "2", "-3", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - } - - for _, tc := range tests { - z, err := uint256.FromDecimal(tc.z) - if err != nil { - t.Error(err) - continue - } - - x, err := uint256.FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := uint256.FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - AddDelta(z, x, y) - - if z.Neq(want) { - t.Errorf("AddDelta(%s, %s, %s) = %v, want %v", tc.z, tc.x, tc.y, z.ToString(), want.ToString()) - } - } -} - -func TestAddDeltaOverflow(t *testing.T) { - tests := []struct { - z, x, y string - want bool - }{ - {"0", "0", "0", false}, - // underflow - {"1", "2", "-3", true}, - } - - for _, tc := range tests { - z, err := uint256.FromDecimal(tc.z) - if err != nil { - t.Error(err) - continue - } - - x, err := uint256.FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - result := AddDeltaOverflow(z, x, y) - if result != tc.want { - t.Errorf("AddDeltaOverflow(%s, %s, %s) = %v, want %v", tc.z, tc.x, tc.y, result, tc.want) - } - } -} - -func TestSub(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"1", "0", "1"}, - {"1", "1", "0"}, - {"-1", "1", "-2"}, - {"1", "-1", "2"}, - {"-1", "-1", "0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {x: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", y: "1", want: "0"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Sub(x, y) - - if got.Neq(want) { - t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestSubUint256(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "-1"}, - {"1", "0", "1"}, - {"1", "1", "0"}, - {"1", "2", "-1"}, - {"-1", "1", "-2"}, - {"-1", "3", "-4"}, - // underflow - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "-0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "-1"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "3", "-2"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := uint256.FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.SubUint256(x, y) - - if got.Neq(want) { - t.Errorf("SubUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestMul(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"5", "3", "15"}, - {"-5", "3", "-15"}, - {"5", "-3", "-15"}, - {"0", "3", "0"}, - {"3", "0", "0"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Mul(x, y) - - if got.Neq(want) { - t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestMulUint256(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "0"}, - {"1", "0", "0"}, - {"1", "1", "1"}, - {"1", "2", "2"}, - {"-1", "1", "-1"}, - {"-1", "3", "-3"}, - {"3", "4", "12"}, - {"-3", "4", "-12"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "-115792089237316195423570985008687907853269984665640564039457584007913129639932"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "115792089237316195423570985008687907853269984665640564039457584007913129639932"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := uint256.FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.MulUint256(x, y) - - if got.Neq(want) { - t.Errorf("MulUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestDiv(t *testing.T) { - tests := []struct { - x, y, expected string - }{ - {"1", "1", "1"}, - {"0", "1", "0"}, - {"-1", "1", "-1"}, - {"1", "-1", "-1"}, - {"-1", "-1", "1"}, - {"-6", "3", "-2"}, - {"10", "-2", "-5"}, - {"-10", "3", "-3"}, - {"7", "3", "2"}, - {"-7", "3", "-2"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // Max uint256 / 2 - } - - for _, tt := range tests { - t.Run(tt.x+"/"+tt.y, func(t *testing.T) { - x := MustFromDecimal(tt.x) - y := MustFromDecimal(tt.y) - result := Zero().Div(x, y) - if result.ToString() != tt.expected { - t.Errorf("Div(%s, %s) = %s, want %s", tt.x, tt.y, result.ToString(), tt.expected) - } - if result.abs.IsZero() && result.neg { - t.Errorf("Div(%s, %s) resulted in negative zero", tt.x, tt.y) - } - }) - } - - t.Run("Division by zero", func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Div(1, 0) did not panic") - } - }() - x := MustFromDecimal("1") - y := MustFromDecimal("0") - Zero().Div(x, y) - }) -} - -func TestDivUint256(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "0"}, - {"1", "0", "0"}, - {"1", "1", "1"}, - {"1", "2", "0"}, - {"-1", "1", "-1"}, - {"-1", "3", "0"}, - {"4", "3", "1"}, - {"25", "5", "5"}, - {"25", "4", "6"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819967"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := uint256.FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.DivUint256(x, y) - - if got.Neq(want) { - t.Errorf("DivUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestQuo(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "0"}, - {"0", "-1", "0"}, - {"10", "1", "10"}, - {"10", "-1", "-10"}, - {"-10", "1", "-10"}, - {"-10", "-1", "10"}, - {"10", "-3", "-3"}, - {"10", "3", "3"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Quo(x, y) - - if got.Neq(want) { - t.Errorf("Quo(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestRem(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "0"}, - {"0", "-1", "0"}, - {"10", "1", "0"}, - {"10", "-1", "0"}, - {"-10", "1", "0"}, - {"-10", "-1", "0"}, - {"10", "3", "1"}, - {"10", "-3", "1"}, - {"-10", "3", "-1"}, - {"-10", "-3", "-1"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Rem(x, y) - - if got.Neq(want) { - t.Errorf("Rem(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} - -func TestMod(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "1", "0"}, - {"0", "-1", "0"}, - {"10", "0", "0"}, - {"10", "1", "0"}, - {"10", "-1", "0"}, - {"-10", "0", "0"}, - {"-10", "1", "0"}, - {"-10", "-1", "0"}, - {"10", "3", "1"}, - {"10", "-3", "1"}, - {"-10", "3", "2"}, - {"-10", "-3", "2"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - y, err := FromDecimal(tc.y) - if err != nil { - t.Error(err) - continue - } - - want, err := FromDecimal(tc.want) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Mod(x, y) - - if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) - } - } -} diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gnoA b/examples/gno.land/p/demo/int256/arithmetic_test.gnoA new file mode 100644 index 00000000000..2e379800af3 --- /dev/null +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gnoA @@ -0,0 +1,571 @@ +package int256 + +import ( + "testing" + + "gno.land/p/demo/uint256" +) + +func TestAdd(t *testing.T) { + tests := []struct { + x, y, want string + }{ + {"0", "1", "1"}, + {"1", "0", "1"}, + {"1", "1", "2"}, + {"1", "2", "3"}, + // NEGATIVE + {"-1", "1", "0"}, + {"1", "-1", "0"}, + {"3", "-3", "0"}, + {"-1", "-1", "-2"}, + {"-1", "-2", "-3"}, + {"-1", "3", "2"}, + {"3", "-1", "2"}, + // OVERFLOW + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0"}, + } + + for _, tc := range tests { + x, err := FromDecimal(tc.x) + if err != nil { + t.Error(err) + continue + } + + y, err := FromDecimal(tc.y) + if err != nil { + t.Error(err) + continue + } + + want, err := FromDecimal(tc.want) + if err != nil { + t.Error(err) + continue + } + + got := New() + got.Add(x, y) + + if got.Neq(want) { + t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + } + } +} + +// func TestAddUint256(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "1"}, +// {"1", "0", "1"}, +// {"1", "1", "2"}, +// {"1", "2", "3"}, +// {"-1", "1", "0"}, +// {"-1", "3", "2"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "1"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639934", "-1"}, +// // OVERFLOW +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := uint256.FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.AddUint256(x, y) + +// if got.Neq(want) { +// t.Errorf("AddUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestAddDelta(t *testing.T) { +// tests := []struct { +// z, x, y, want string +// }{ +// {"0", "0", "0", "0"}, +// {"0", "0", "1", "1"}, +// {"0", "1", "0", "1"}, +// {"0", "1", "1", "2"}, +// {"1", "2", "3", "5"}, +// {"5", "10", "-3", "7"}, +// // underflow +// {"1", "2", "-3", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, +// } + +// for _, tc := range tests { +// z, err := uint256.FromDecimal(tc.z) +// if err != nil { +// t.Error(err) +// continue +// } + +// x, err := uint256.FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := uint256.FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// AddDelta(z, x, y) + +// if z.Neq(want) { +// t.Errorf("AddDelta(%s, %s, %s) = %v, want %v", tc.z, tc.x, tc.y, z.ToString(), want.ToString()) +// } +// } +// } + +// func TestAddDeltaOverflow(t *testing.T) { +// tests := []struct { +// z, x, y string +// want bool +// }{ +// {"0", "0", "0", false}, +// // underflow +// {"1", "2", "-3", true}, +// } + +// for _, tc := range tests { +// z, err := uint256.FromDecimal(tc.z) +// if err != nil { +// t.Error(err) +// continue +// } + +// x, err := uint256.FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// result := AddDeltaOverflow(z, x, y) +// if result != tc.want { +// t.Errorf("AddDeltaOverflow(%s, %s, %s) = %v, want %v", tc.z, tc.x, tc.y, result, tc.want) +// } +// } +// } + +// func TestSub(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"1", "0", "1"}, +// {"1", "1", "0"}, +// {"-1", "1", "-2"}, +// {"1", "-1", "2"}, +// {"-1", "-1", "0"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, +// {x: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", y: "1", want: "0"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.Sub(x, y) + +// if got.Neq(want) { +// t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestSubUint256(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "-1"}, +// {"1", "0", "1"}, +// {"1", "1", "0"}, +// {"1", "2", "-1"}, +// {"-1", "1", "-2"}, +// {"-1", "3", "-4"}, +// // underflow +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "-0"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "-1"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "3", "-2"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := uint256.FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.SubUint256(x, y) + +// if got.Neq(want) { +// t.Errorf("SubUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestMul(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"5", "3", "15"}, +// {"-5", "3", "-15"}, +// {"5", "-3", "-15"}, +// {"0", "3", "0"}, +// {"3", "0", "0"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.Mul(x, y) + +// if got.Neq(want) { +// t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestMulUint256(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "0"}, +// {"1", "0", "0"}, +// {"1", "1", "1"}, +// {"1", "2", "2"}, +// {"-1", "1", "-1"}, +// {"-1", "3", "-3"}, +// {"3", "4", "12"}, +// {"-3", "4", "-12"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "-115792089237316195423570985008687907853269984665640564039457584007913129639932"}, +// {"115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "115792089237316195423570985008687907853269984665640564039457584007913129639932"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := uint256.FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.MulUint256(x, y) + +// if got.Neq(want) { +// t.Errorf("MulUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestDiv(t *testing.T) { +// tests := []struct { +// x, y, expected string +// }{ +// {"1", "1", "1"}, +// {"0", "1", "0"}, +// {"-1", "1", "-1"}, +// {"1", "-1", "-1"}, +// {"-1", "-1", "1"}, +// {"-6", "3", "-2"}, +// {"10", "-2", "-5"}, +// {"-10", "3", "-3"}, +// {"7", "3", "2"}, +// {"-7", "3", "-2"}, +// {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // Max uint256 / 2 +// } + +// for _, tt := range tests { +// t.Run(tt.x+"/"+tt.y, func(t *testing.T) { +// x := MustFromDecimal(tt.x) +// y := MustFromDecimal(tt.y) +// result := Zero().Div(x, y) +// if result.ToString() != tt.expected { +// t.Errorf("Div(%s, %s) = %s, want %s", tt.x, tt.y, result.ToString(), tt.expected) +// } +// if result.abs.IsZero() && result.neg { +// t.Errorf("Div(%s, %s) resulted in negative zero", tt.x, tt.y) +// } +// }) +// } + +// t.Run("Division by zero", func(t *testing.T) { +// defer func() { +// if r := recover(); r == nil { +// t.Errorf("Div(1, 0) did not panic") +// } +// }() +// x := MustFromDecimal("1") +// y := MustFromDecimal("0") +// Zero().Div(x, y) +// }) +// } + +// func TestDivUint256(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "0"}, +// {"1", "0", "0"}, +// {"1", "1", "1"}, +// {"1", "2", "0"}, +// {"-1", "1", "-1"}, +// {"-1", "3", "0"}, +// {"4", "3", "1"}, +// {"25", "5", "5"}, +// {"25", "4", "6"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819967"}, +// {"115792089237316195423570985008687907853269984665640564039457584007913129639934", "2", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := uint256.FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.DivUint256(x, y) + +// if got.Neq(want) { +// t.Errorf("DivUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestQuo(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "0"}, +// {"0", "-1", "0"}, +// {"10", "1", "10"}, +// {"10", "-1", "-10"}, +// {"-10", "1", "-10"}, +// {"-10", "-1", "10"}, +// {"10", "-3", "-3"}, +// {"10", "3", "3"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.Quo(x, y) + +// if got.Neq(want) { +// t.Errorf("Quo(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestRem(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "0"}, +// {"0", "-1", "0"}, +// {"10", "1", "0"}, +// {"10", "-1", "0"}, +// {"-10", "1", "0"}, +// {"-10", "-1", "0"}, +// {"10", "3", "1"}, +// {"10", "-3", "1"}, +// {"-10", "3", "-1"}, +// {"-10", "-3", "-1"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.Rem(x, y) + +// if got.Neq(want) { +// t.Errorf("Rem(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } + +// func TestMod(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "1", "0"}, +// {"0", "-1", "0"}, +// {"10", "0", "0"}, +// {"10", "1", "0"}, +// {"10", "-1", "0"}, +// {"-10", "0", "0"}, +// {"-10", "1", "0"}, +// {"-10", "-1", "0"}, +// {"10", "3", "1"}, +// {"10", "-3", "1"}, +// {"-10", "3", "2"}, +// {"-10", "-3", "2"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// y, err := FromDecimal(tc.y) +// if err != nil { +// t.Error(err) +// continue +// } + +// want, err := FromDecimal(tc.want) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := New() +// got.Mod(x, y) + +// if got.Neq(want) { +// t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) +// } +// } +// } diff --git a/examples/gno.land/p/demo/int256/bitwise.gno b/examples/gno.land/p/demo/int256/bitwise.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/bitwise.gno rename to examples/gno.land/p/demo/int256/bitwise.gnoA diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/bitwise_test.gno rename to examples/gno.land/p/demo/int256/bitwise_test.gnoA diff --git a/examples/gno.land/p/demo/int256/cmp.gno b/examples/gno.land/p/demo/int256/cmp.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/cmp.gno rename to examples/gno.land/p/demo/int256/cmp.gnoA diff --git a/examples/gno.land/p/demo/int256/cmp_test.gno b/examples/gno.land/p/demo/int256/cmp_test.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/cmp_test.gno rename to examples/gno.land/p/demo/int256/cmp_test.gnoA diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/conversion.gno rename to examples/gno.land/p/demo/int256/conversion.gnoA diff --git a/examples/gno.land/p/demo/int256/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gnoA similarity index 100% rename from examples/gno.land/p/demo/int256/conversion_test.gno rename to examples/gno.land/p/demo/int256/conversion_test.gnoA diff --git a/examples/gno.land/p/demo/int256/doc.gno b/examples/gno.land/p/demo/int256/doc.gno new file mode 100644 index 00000000000..3a9fb2207ee --- /dev/null +++ b/examples/gno.land/p/demo/int256/doc.gno @@ -0,0 +1,2 @@ +// This package provides a 256-bit signed integer type, Int and associated functions. +package int256 \ No newline at end of file diff --git a/examples/gno.land/p/demo/int256/int256.gno b/examples/gno.land/p/demo/int256/int256.gno index caccd17d531..6c26322ee41 100644 --- a/examples/gno.land/p/demo/int256/int256.gno +++ b/examples/gno.land/p/demo/int256/int256.gno @@ -1,4 +1,3 @@ -// This package provides a 256-bit signed integer type, Int, and associated functions. package int256 import ( @@ -8,57 +7,78 @@ import ( var one = uint256.NewUint(1) type Int struct { - abs *uint256.Uint - neg bool + value uint256.Uint } -// Zero returns a new Int set to 0. +// New creates and returns a new Int initialized to zero. +func New() *Int { + return &Int{} +} + +// NewInt allocates and returns a new Int set to the value of the provided int64. +func NewInt(x int64) *Int { + return new(Int).SetInt64(x) +} + +// Zero returns a new Int initialized to 0. +// +// This function is useful for creating a starting point for calculations or +// when an explicit zero value is needed. func Zero() *Int { - return NewInt(0) + return &Int{} } -// One returns a new Int set to 1. +// One returns a new Int initialized to one. +// +// This function is convenient for operations that require a unit value, +// such as incrementing or serving as an identity element in multiplication. func One() *Int { - return NewInt(1) + z := &Int{} + z.value.SetUint64(1) + return z } -// Sign returns: +// Sign determines the sign of the Int. // -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 +// It returns -1 for negative numbers, 0 for zero, and +1 for positive numbers. func (z *Int) Sign() int { - z.initiateAbs() - - if z.abs.IsZero() { + if z.value.IsZero() { return 0 } - if z.neg { - return -1 - } - return 1 -} - -// New returns a new Int set to 0. -func New() *Int { - return &Int{ - abs: new(uint256.Uint), + // Right shift the value by 255 bits to check the sign bit. + // In two's complement representation, the most significant bit (MSB) is the sign bit. + // If the MSB is 0, the number is positive; if it is 1, the number is negative. + // + // Example: + // Original value: 1 0 1 0 ... 0 1 (256 bits) + // After Rsh 255: 0 0 0 0 ... 0 1 (1 bit) + // + // This approach is highly efficient as it avoids the need for comparisons + // or arithmetic operations on the full 256-bit number. Instead it reduces + // the problem to checking a single bit. + // + // Additionally, this method will work correctly for all values, + // including the minimum possible negative number (which in two's complement + // doesn't have a positive counterpart in the same bit range). + var temp uint256.Uint + temp.Rsh(&z.value, 255) + if temp.IsZero() { + return 1 } + return -1 } -// NewInt allocates and returns a new Int set to x. -func NewInt(x int64) *Int { - return New().SetInt64(x) -} - -// FromDecimal returns a new Int from a decimal string. -// Returns a new Int and an error if the string is not a valid decimal. +// FromDecimal creates a new Int from a decimal string representation. +// It handles both positive and negative values. +// +// This function is useful for parsing user input or reading numeric data +// from text-based formats. func FromDecimal(s string) (*Int, error) { return new(Int).SetString(s) } -// MustFromDecimal returns a new Int from a decimal string. -// Panics if the string is not a valid decimal. +// MustFromDecimal is similar to FromDecimal but panics if the input string +// is not a valid decimal representation. func MustFromDecimal(s string) *Int { z, err := FromDecimal(s) if err != nil { @@ -67,60 +87,92 @@ func MustFromDecimal(s string) *Int { return z } -// SetString sets s to the value of z and returns z and a boolean indicating success. +// SetString sets the Int to the value represented by the input string. +// This method supports decimal string representations of integers and handles +// both positive and negative values. +// +// For negative numbers, it uses the two's complement representation: +// 1. Convert the absolute value to binary +// 2. Invert all bits (NOT operation) +// 3. Add 1 to the result +// +// This process ensures correct representation and arithmetic for negative numbers. func (z *Int) SetString(s string) (*Int, error) { neg := false - // Remove max one leading + - if len(s) > 0 && s[0] == '+' { - neg = false + if len(s) > 0 && (s[0] == '+' || s[0] == '-') { + if s[0] == '-' { + neg = true + } + // remove the sign character from the string + // and take only the numeric part s = s[1:] } - if len(s) > 0 && s[0] == '-' { - neg = true - s = s[1:] - } - var ( - abs *uint256.Uint - err error - ) - abs, err = uint256.FromDecimal(s) + temp, err := uint256.FromDecimal(s) if err != nil { return nil, err } - return &Int{ - abs, - neg, - }, nil + // for negative numbers, apply two's complement + if neg { + // invert all bits (NOT operation) + temp.Not(temp) + // add one (two's complement) + temp.Add(temp, uint256.NewUint(1)) + // Example of two's complement for 8-bit number -5: + // + // Decimal: 5 + // Step 0 (binary): 0000 0101 + // Step 1 (NOT): 1111 1010 + // Step 2 (Add 1): 1111 1011 + // + // Result: 1111 1011 (binary representation of -5 in two's complement) + // + // This process scales to our 256-bit integers, allowing + // for correct representation and arithmetic of negative numbers. + } + + z.value.Set(temp) + return z, nil } -// FromUint256 is a convenience-constructor from uint256.Uint. -// Returns a new Int and whether overflow occurred. -// OBS: If u is `nil`, this method returns `nil, false` -func FromUint256(x *uint256.Uint) *Int { - if x == nil { - return nil +// SetInt64 sets the Int to the value of the provided int64. +// +// This method allows for easy conversion from standard Go integer types +// to Int, correctly handling both positive and negative values. +func (z *Int) SetInt64(v int64) *Int { + if v >= 0 { + z.value.SetUint64(uint64(v)) + } else { + z.value.SetUint64(uint64(-v)) + z.value.Not(&z.value) + z.value.Add(&z.value, one) } - z := Zero() + return z +} - z.SetUint256(x) +// SetUint64 sets the Int to the value of the provided uint64. +func (z *Int) SetUint64(v uint64) *Int { + z.value.SetUint64(v) return z } -// OBS, differs from original mempooler int256 -// NilToZero sets z to 0 and return it if it's nil, otherwise it returns z -func (z *Int) NilToZero() *Int { - if z == nil { - return NewInt(0) - } +// FromUint256 sets the Int to the value of the provided Uint256. +// +// This method allows for conversion from unsigned 256-bit integers +// to signed integers. +func (z *Int) FromUint256(v *uint256.Uint) *Int { + z.value.Set(v) return z } -// initiateAbs sets default value for `z` or `z.abs` value if is nil -// OBS: differs from mempooler int256. It checks not only `z.abs` but also `z` -func (z *Int) initiateAbs() { - if z == nil || z.abs == nil { - z.abs = new(uint256.Uint) +// NilToZero returns the Int if it's not nil, or a new zero-valued Int otherwise. +// +// This method is useful for safely handling potentially nil Int pointers, +// ensuring that operations always have a valid Int to work with. +func (z *Int) NilToZero() *Int { + if z == nil { + return Zero() } + return z } diff --git a/examples/gno.land/p/demo/int256/int256_test.gno b/examples/gno.land/p/demo/int256/int256_test.gno index 7c8181d1bec..662710cc3ea 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -1,7 +1,135 @@ -// ported from github.com/mempooler/int256 package int256 -import "testing" +import ( + "testing" + + "gno.land/p/demo/uint256" +) + +func TestZero(t *testing.T) { + z := Zero() + if z.Sign() != 0 { + t.Errorf("Zero() = %d, want %d", z.Sign(), 0) + } +} + +func TestNew(t *testing.T) { + z := New() + if z.Sign() != 0 { + t.Errorf("New() = %d, want %d", z.Sign(), 0) + } +} + +func TestNewInt(t *testing.T) { + testCases := []struct { + input int64 + expected int + }{ + {0, 0}, + {1, 1}, + {-1, -1}, + {9223372036854775807, 1}, // max int64 + {-9223372036854775808, -1}, // min int64 + } + + for _, tc := range testCases { + z := NewInt(tc.input) + if z.Sign() != tc.expected { + t.Errorf("NewInt(%d) = %d, want %d", tc.input, z.Sign(), tc.expected) + } + } +} + +func TestFromDecimal(t *testing.T) { + testCases := []struct { + input string + expected int + isError bool + }{ + {"0", 0, false}, + {"1", 1, false}, + {"-1", -1, false}, + {"123456789", 1, false}, + {"-123456789", -1, false}, + {"invalid", 0, true}, + } + + for _, tc := range testCases { + z, err := FromDecimal(tc.input) + if tc.isError { + if err == nil { + t.Errorf("FromDecimal(%s) expected error, but got nil", tc.input) + } + } else { + if err != nil { + t.Errorf("FromDecimal(%s) unexpected error: %v", tc.input, err) + } else if z.Sign() != tc.expected { + t.Errorf("FromDecimal(%s) sign is incorrect. Expected: %d, Actual: %d", tc.input, tc.expected, z.Sign()) + } + } + } +} + +func TestMustFromDecimal(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("MustFromDecimal(\"invalid\") expected panic, but got nil") + } + }() + + z := MustFromDecimal("123") + if z.Sign() != 1 { + t.Errorf("MustFromDecimal(\"123\") sign is incorrect. Expected: %d, Actual: %d", 1, z.Sign()) + } + + MustFromDecimal("invalid") +} + +func TestSetUint64(t *testing.T) { + testCases := []uint64{ + 0, + 1, + 18446744073709551615, // max uint64 + } + + for _, tc := range testCases { + z := New().SetUint64(tc) + if z.Sign() < 0 { + t.Errorf("SetUint64(%d) result is negative", tc) + } + if tc == 0 && z.Sign() != 0 { + t.Errorf("SetUint64(0) result is not zero") + } + if tc > 0 && z.Sign() != 1 { + t.Errorf("SetUint64(%d) result is not positive", tc) + } + } +} + +func TestFromUint256(t *testing.T) { + tests := []struct { + input *uint256.Uint + expected int + }{ + {uint256.NewUint(0), 0}, + {uint256.NewUint(1), 1}, + {uint256.NewUint(18446744073709551615), 1}, + } + + for _, tc := range tests { + z := New().FromUint256(tc.input) + if z.Sign() != tc.expected { + t.Errorf("FromUint256(%v) = %d, want %d", tc.input, z.Sign(), tc.expected) + } + } +} + +func TestNilToZero(t *testing.T) { + z := New().NilToZero() + if z.Sign() != 0 { + t.Errorf("NilToZero() = %d, want %d", z.Sign(), 0) + } +} func TestSign(t *testing.T) { tests := []struct {