From e278c9e010e042a7778f785b006243fa20144e9d Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Wed, 25 Sep 2024 16:16:06 +0900 Subject: [PATCH 01/11] fix int256 --- .../int256/{absolute.gno => absolute.gnoA} | 0 .../{absolute_test.gno => absolute_test.gnoA} | 0 .../gno.land/p/demo/int256/arithmetic.gno | 202 ------- .../gno.land/p/demo/int256/arithmetic.gnoA | 202 +++++++ .../p/demo/int256/arithmetic_test.gno | 571 ------------------ .../p/demo/int256/arithmetic_test.gnoA | 571 ++++++++++++++++++ .../demo/int256/{bitwise.gno => bitwise.gnoA} | 0 .../{bitwise_test.gno => bitwise_test.gnoA} | 0 .../p/demo/int256/{cmp.gno => cmp.gnoA} | 0 .../int256/{cmp_test.gno => cmp_test.gnoA} | 0 .../{conversion.gno => conversion.gnoA} | 0 ...nversion_test.gno => conversion_test.gnoA} | 0 examples/gno.land/p/demo/int256/doc.gno | 2 + examples/gno.land/p/demo/int256/int256.gno | 190 +++--- .../gno.land/p/demo/int256/int256_test.gno | 132 +++- 15 files changed, 1026 insertions(+), 844 deletions(-) rename examples/gno.land/p/demo/int256/{absolute.gno => absolute.gnoA} (100%) rename examples/gno.land/p/demo/int256/{absolute_test.gno => absolute_test.gnoA} (100%) delete mode 100644 examples/gno.land/p/demo/int256/arithmetic.gno create mode 100644 examples/gno.land/p/demo/int256/arithmetic.gnoA delete mode 100644 examples/gno.land/p/demo/int256/arithmetic_test.gno create mode 100644 examples/gno.land/p/demo/int256/arithmetic_test.gnoA rename examples/gno.land/p/demo/int256/{bitwise.gno => bitwise.gnoA} (100%) rename examples/gno.land/p/demo/int256/{bitwise_test.gno => bitwise_test.gnoA} (100%) rename examples/gno.land/p/demo/int256/{cmp.gno => cmp.gnoA} (100%) rename examples/gno.land/p/demo/int256/{cmp_test.gno => cmp_test.gnoA} (100%) rename examples/gno.land/p/demo/int256/{conversion.gno => conversion.gnoA} (100%) rename examples/gno.land/p/demo/int256/{conversion_test.gno => conversion_test.gnoA} (100%) create mode 100644 examples/gno.land/p/demo/int256/doc.gno 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 { From 2a0000c1ff9c9d684a79ae412b11eacf0d01f366 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Wed, 25 Sep 2024 18:58:38 +0900 Subject: [PATCH 02/11] basic arithmetics --- examples/gno.land/p/demo/int256/absolute.gnoA | 24 +- .../gno.land/p/demo/int256/absolute_test.gnoA | 206 +++--- .../gno.land/p/demo/int256/arithmetic.gno | 437 ++++++++++++ .../gno.land/p/demo/int256/arithmetic.gnoA | 202 ------ .../p/demo/int256/arithmetic_test.gno | 672 ++++++++++++++++++ .../p/demo/int256/arithmetic_test.gnoA | 571 --------------- examples/gno.land/p/demo/int256/cmp.gno | 116 +++ examples/gno.land/p/demo/int256/cmp.gnoA | 86 --- .../gno.land/p/demo/int256/conversion.gno | 121 ++++ .../gno.land/p/demo/int256/conversion.gnoA | 87 --- .../p/demo/int256/conversion_test.gno | 228 ++++++ .../p/demo/int256/conversion_test.gnoA | 234 ------ examples/gno.land/p/demo/int256/doc.gno | 2 +- .../gno.land/p/demo/int256/int256_test.gno | 2 +- 14 files changed, 1691 insertions(+), 1297 deletions(-) create mode 100644 examples/gno.land/p/demo/int256/arithmetic.gno delete mode 100644 examples/gno.land/p/demo/int256/arithmetic.gnoA create mode 100644 examples/gno.land/p/demo/int256/arithmetic_test.gno delete mode 100644 examples/gno.land/p/demo/int256/arithmetic_test.gnoA create mode 100644 examples/gno.land/p/demo/int256/cmp.gno delete mode 100644 examples/gno.land/p/demo/int256/cmp.gnoA create mode 100644 examples/gno.land/p/demo/int256/conversion.gno delete mode 100644 examples/gno.land/p/demo/int256/conversion.gnoA create mode 100644 examples/gno.land/p/demo/int256/conversion_test.gno delete mode 100644 examples/gno.land/p/demo/int256/conversion_test.gnoA diff --git a/examples/gno.land/p/demo/int256/absolute.gnoA b/examples/gno.land/p/demo/int256/absolute.gnoA index 825dd60c62a..25c71b5ab20 100644 --- a/examples/gno.land/p/demo/int256/absolute.gnoA +++ b/examples/gno.land/p/demo/int256/absolute.gnoA @@ -1,18 +1,18 @@ package int256 -import "gno.land/p/demo/uint256" +// import "gno.land/p/demo/uint256" // Abs returns |z| -func (z *Int) Abs() *uint256.Uint { - return z.abs.Clone() -} +// func (z *Int) Abs() *uint256.Uint { +// return z.abs.Clone() +// } -// AbsGt returns true if |z| > x, where x is a uint256 -func (z *Int) AbsGt(x *uint256.Uint) bool { - return z.abs.Gt(x) -} +// // AbsGt returns true if |z| > x, where x is a uint256 +// func (z *Int) AbsGt(x *uint256.Uint) bool { +// return z.abs.Gt(x) +// } -// AbsLt returns true if |z| < x, where x is a uint256 -func (z *Int) AbsLt(x *uint256.Uint) bool { - return z.abs.Lt(x) -} +// // AbsLt returns true if |z| < x, where x is a uint256 +// func (z *Int) AbsLt(x *uint256.Uint) bool { +// return z.abs.Lt(x) +// } diff --git a/examples/gno.land/p/demo/int256/absolute_test.gnoA b/examples/gno.land/p/demo/int256/absolute_test.gnoA index 55f6e41d0c8..6e6a6297e9c 100644 --- a/examples/gno.land/p/demo/int256/absolute_test.gnoA +++ b/examples/gno.land/p/demo/int256/absolute_test.gnoA @@ -1,105 +1,105 @@ package int256 -import ( - "testing" - - "gno.land/p/demo/uint256" -) - -func TestAbs(t *testing.T) { - tests := []struct { - x, want string - }{ - {"0", "0"}, - {"1", "1"}, - {"-1", "1"}, - {"-2", "2"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - got := x.Abs() - - if got.ToString() != tc.want { - t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) - } - } -} - -func TestAbsGt(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "0", "false"}, - {"1", "0", "true"}, - {"-1", "0", "true"}, - {"-1", "1", "false"}, - {"-2", "1", "true"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "true"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "true"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, - } - - 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 - } - - got := x.AbsGt(y) - - if got != (tc.want == "true") { - t.Errorf("AbsGt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) - } - } -} - -func TestAbsLt(t *testing.T) { - tests := []struct { - x, y, want string - }{ - {"0", "0", "false"}, - {"1", "0", "false"}, - {"-1", "0", "false"}, - {"-1", "1", "false"}, - {"-2", "1", "false"}, - {"-5", "10", "true"}, - {"31330", "31337", "true"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "false"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "false"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, - } - - 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 - } - - got := x.AbsLt(y) - - if got != (tc.want == "true") { - t.Errorf("AbsLt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) - } - } -} +// import ( +// "testing" + +// "gno.land/p/demo/uint256" +// ) + +// func TestAbs(t *testing.T) { +// tests := []struct { +// x, want string +// }{ +// {"0", "0"}, +// {"1", "1"}, +// {"-1", "1"}, +// {"-2", "2"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, +// } + +// for _, tc := range tests { +// x, err := FromDecimal(tc.x) +// if err != nil { +// t.Error(err) +// continue +// } + +// got := x.Abs() + +// if got.ToString() != tc.want { +// t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) +// } +// } +// } + +// func TestAbsGt(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "0", "false"}, +// {"1", "0", "true"}, +// {"-1", "0", "true"}, +// {"-1", "1", "false"}, +// {"-2", "1", "true"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "true"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "true"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, +// } + +// 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 +// } + +// got := x.AbsGt(y) + +// if got != (tc.want == "true") { +// t.Errorf("AbsGt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) +// } +// } +// } + +// func TestAbsLt(t *testing.T) { +// tests := []struct { +// x, y, want string +// }{ +// {"0", "0", "false"}, +// {"1", "0", "false"}, +// {"-1", "0", "false"}, +// {"-1", "1", "false"}, +// {"-2", "1", "false"}, +// {"-5", "10", "true"}, +// {"31330", "31337", "true"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "false"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "false"}, +// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, +// } + +// 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 +// } + +// got := x.AbsLt(y) + +// if got != (tc.want == "true") { +// t.Errorf("AbsLt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) +// } +// } +// } diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno new file mode 100644 index 00000000000..0c535b1db2b --- /dev/null +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -0,0 +1,437 @@ +package int256 + +import "gno.land/p/demo/uint256" + +func (z *Int) Add(x, y *Int) *Int { + z.value.Add(&x.value, &y.value) + return z +} + +func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { + z.value.Add(&x.value, y) + return z +} + +func (z *Int) Sub(x, y *Int) *Int { + z.value.Sub(&x.value, &y.value) + return z +} + +func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { + z.value.Sub(&x.value, y) + return z +} + +func (z *Int) Mul(x, y *Int) *Int { + z.value.Mul(&x.value, &y.value) + return z +} + +/* ---------------------------------------------------------------------------- +// Division and modulus operations +// ---------------------------------------------------------------------------- +// +// This package provides three different division and modulus operations: +// - Div and Rem: Truncated division (T-division) +// - Quo and Mod: Floored division (F-division) +// - DivE and ModE: Euclidean division (E-division) +// +// * Truncated division (Div, Rem) is the most common implementation in modern processors +// and programming languages. It rounds quotients towards zero and the remainder +// always has the same sign as the dividend. +// +// * Floored division (Quo, Mod) always rounds quotients towards negative infinity. +// This ensures that the modulus is always non-negative for a positive divisor, +// which can be useful in certain algorithms. +// +// * Euclidean division (DivE, ModE) ensures that the remainder is always non-negative, +// regardless of the signs of the dividend and divisor. This has several mathematical +// advantages: +// 1. It satisfies the unique division with remainder theorem. +// 2. It preserves division and modulus properties for negative divisors. +// 3. It allows for optimizations in divisions by powers of two. +// [+] Currently, ModE and Mod are shared the same implementation. +// +// ## Performance considerations: +// - For most operations, the performance difference between these division types is negligible. +// - Euclidean division may require an extra comparison and potentially an addition, +// which could impact performance in extremely performance-critical scenarios. +// - For divisions by powers of two, Euclidean division can be optimized to use +// bitwise operations, potentially offering better performance. +// +// ## Usage guidelines: +// - Use Div and Rem for general-purpose division that matches most common expectations. +// - Use Quo and Mod when you need a non-negative remainder for positive divisors, +// or when implementing algorithms that assume floored division. +// - Use DivE and ModE when you need the mathematical properties of Euclidean division, +// or when working with algorithms that specifically require it. +// +// Note: When working with negative numbers, be aware of the differences in behavior +// between these division types, especially at the boundaries of integer ranges. +// +// ## References +// 1. Daan Leijen, “Division and Modulus for Computer Scientists” (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) +/* ---------------------------------------------------------------------------- */ + +// Div performs integer division z = x / y and returns z. +// If y == 0, it panics with a "division by zero" error. +// +// This function handles signed division using two's complement representation: +// 1. Determine the sign of the quotient based on the signs of x and y. +// 2. Perform unsigned division on the absolute values. +// 3. Adjust the result's sign if necessary. +// +// Example visualization for 8-bit integers (scaled down from 256-bit for simplicity): +// +// Let x = -6 (11111010 in two's complement) and y = 3 (00000011) +// +// Step 2: Determine signs +// +// x: negative (MSB is 1) +// y: positive (MSB is 0) +// +// Step 3: Calculate absolute values +// +// |x| = 6: 11111010 -> 00000110 +// NOT: 00000101 +// +1: 00000110 +// +// |y| = 3: 00000011 (already positive) +// +// Step 4: Unsigned division +// +// 6 / 3 = 2: 00000010 +// +// Step 5: Adjust sign (x and y have different signs) +// +// -2: 00000010 -> 11111110 +// NOT: 11111101 +// +1: 11111110 +// +// Note: This implementation rounds towards zero, as is standard in Go. +func (z *Int) Div(x, y *Int) *Int { + // Step 1: Check for division by zero + if y.value.IsZero() { + panic("division by zero") + } + + // Step 2: Determine the signs of x and y + xSign := x.Sign() + ySign := y.Sign() + + // Step 3: Calculate the absolute values of x and y + xAbs, xSign := abs(x) + yAbs, ySign := abs(y) + + // perform unsigned division on the absolute values + z.value.Div(&xAbs, &yAbs) + + // Step 5: Adjust the sign of the result + // if x and y have different signs, the result must be negative + if xSign != ySign { + // convert the positive result to negative using two's complement + setNegative(&z.value, &z.value) + } + + return z +} + +// Quo sets z to the quotient x/y for y != 0 and returns z. +// It implements truncated division (or T-division). +// +// The function performs the following steps: +// 1. Check for division by zero +// 2. Determine the signs of x and y +// 3. Calculate the absolute values of x and y +// 4. Perform unsigned division and get the remainder +// 5. Adjust the quotient for truncation towards zero +// 6. Adjust the sign of the result +// +// Example visualization for 8-bit integers (scaled down from 256-bit for simplicity): +// +// Let x = -7 (11111001 in two's complement) and y = 3 (00000011) +// +// Step 2: Determine signs +// +// x: negative (MSB is 1) +// y: positive (MSB is 0) +// +// Step 3: Calculate absolute values +// +// |x| = 7: 11111001 -> 00000111 +// NOT: 00000110 +// +1: 00000111 +// +// |y| = 3: 00000011 (already positive) +// +// Step 4: Unsigned division +// +// 7 / 3 = 2 remainder 1 +// q = 2: 00000010 +// r = 1: 00000001 +// +// Step 5: Adjust for truncation +// +// Signs are different and r != 0, so add 1 to q +// q = 3: 00000011 +// +// Step 6: Adjust sign (x and y have different signs) +// +// -3: 00000011 -> 11111101 +// NOT: 11111100 +// +1: 11111101 +// +// Final result: -3 (11111101 in two's complement) +// +// Note: This implementation ensures correct truncation towards zero for negative dividends. +func (z *Int) Quo(x, y *Int) *Int { + // Step 1: Check for division by zero + if y.value.IsZero() { + panic("division by zero") + } + + // Step 2: Determine the signs of x and y + xSign := x.Sign() + ySign := y.Sign() + + // Step 3: Calculate the absolute values of x and y + var xAbs, yAbs, q, r uint256.Uint + xAbs, xSign = abs(x) + yAbs, ySign = abs(y) + + // Step 4: Perform unsigned division and get the remainder + // q = xAbs / yAbs + // r = xAbs % yAbs + // + // Use Euclidean division to always yields a non-negative remainder, which is + // crucial for correct truncation towards zero in subsequent steps. + // By using this method here, we can easily adjust the quotient in _Step 5_ + // to achieve truncated division semantics. + q.DivMod(&xAbs, &yAbs, &r) + + // Step 5: Adjust the quotient for truncation towards zero. + // + // If x and y have different signs and there's a non-zero remainder, + // we need to round towards zero by adding 1 to the quotient magnitude. + if (xSign < 0) != (ySign < 0) && !r.IsZero() { + q.Add(&q, one) + } + + // Step 6: Adjust the sign of the result + if xSign != ySign { + setNegative(&q, &q) + } + + z.value.Set(&q) + return z +} + +// Rem sets z to the remainder x%y for y != 0 and returns z. +// +// The function performs the following steps: +// 1. Check for division by zero +// 2. Determine the signs of x and y +// 3. Calculate the absolute values of x and y +// 4. Perform unsigned division and get the remainder +// 5. Adjust the sign of the remainder +// +// Example visualization for 8-bit integers (scaled down from 256-bit for simplicity): +// +// Let x = -7 (11111001 in two's complement) and y = 3 (00000011) +// +// Step 2: Determine signs +// +// x: negative (MSB is 1) +// y: positive (MSB is 0) +// +// Step 3: Calculate absolute values +// +// |x| = 7: 11111001 -> 00000111 +// NOT: 00000110 +// +1: 00000111 +// +// |y| = 3: 00000011 (already positive) +// +// Step 4: Unsigned division +// +// 7 / 3 = 2 remainder 1 +// q = 2: 00000010 (not used in result) +// r = 1: 00000001 +// +// Step 5: Adjust sign of remainder (x is negative) +// +// -1: 00000001 -> 11111111 +// NOT: 11111110 +// +1: 11111111 +// +// Final result: -1 (11111111 in two's complement) +// +// Note: The sign of the remainder is always the same as the sign of the dividend (x). +func (z *Int) Rem(x, y *Int) *Int { + // Step 1: Check for division by zero + if y.value.IsZero() { + panic("division by zero") + } + + // Step 2: Determine the signs of x and y + xSign := x.Sign() + ySign := y.Sign() + + // Step 3: Calculate the absolute values of x and y + var xAbs, yAbs, q, r uint256.Uint + xAbs, xSign = abs(x) + yAbs, ySign = abs(y) + + // Step 4: Perform unsigned division and get the remainder + q.DivMod(&xAbs, &yAbs, &r) + + // Step 5: Adjust the sign of the remainder + if xSign < 0 { + if !r.IsZero() { + // convert positive remainder to negative + setNegative(&r, &r) + } + } + + z.value.Set(&r) + return z +} + +// Mod sets z to the modulus x%y for y != 0 and returns z. +// The result (z) has the same sign as the divisor y. +func (z *Int) Mod(x, y *Int) *Int { + return z.ModE(x, y) +} + +// DivE performs Euclidean division of x by y, setting z to the quotient and returning z. +// If y == 0, it panics with a "division by zero" error. +// +// Euclidean division satisfies the following properties: +// 1. The remainder is always non-negative: 0 <= x mod y < |y| +// 2. It follows the identity: x = y * (x div y) + (x mod y) +func (z *Int) DivE(x, y *Int) *Int { + if y.value.IsZero() { + panic("division by zero") + } + + z.Div(x, y) + + // Get the remainder using T-division + r := new(Int).Rem(x, y) + + // Adjust the quotient if necessary + if r.Sign() < 0 { + if y.Sign() > 0 { + return z.Sub(z, NewInt(1)) + } + return z.Add(z, NewInt(1)) + } + + return z +} + +// ModE computes the Euclidean modulus of x by y, setting z to the result and returning z. +// If y == 0, it panics with a "division by zero" error. +// +// The Euclidean modulus is always non-negative and satisfies: +// +// 0 <= x mod y < |y| +// +// Example visualization for 8-bit integers (scaled down from 256-bit for simplicity): +// +// Case 1: Let x = -7 (11111001 in two's complement) and y = 3 (00000011) +// +// Step 1: Compute remainder (using Rem) +// +// Result of Rem: -1 (11111111 in two's complement) +// +// Step 2: Adjust sign (result is negative, y is positive) +// +// -1 + 3 = 2 +// 11111111 + 00000011 = 00000010 +// +// Final result: 2 (00000010) +// +// Case 2: Let x = -7 (11111001 in two's complement) and y = -3 (11111101 in two's complement) +// +// Step 1: Compute remainder (using Rem) +// +// Result of Rem: -1 (11111111 in two's complement) +// +// Step 2: Adjust sign (result is negative, y is negative) +// +// No adjustment needed +// +// Final result: -1 (11111111 in two's complement) +// +// Note: This implementation ensures that the result always has the same sign as y, +// which is different from the Rem operation. +func (z *Int) ModE(x, y *Int) *Int { + if y.value.IsZero() { + panic("division by zero") + } + + // Perform T-division to get the remainder + z.Rem(x, y) + + // Adjust the remainder if necessary + if z.Sign() < 0 { + if y.Sign() > 0 { + return z.Add(z, y) + } + return z.Sub(z, y) + } + + return z +} + +func abs(x *Int) (uint256.Uint, int) { + sign := x.Sign() + var absVal uint256.Uint + absVal.Set(&x.value) + if sign < 0 { + setNegative(&absVal, &x.value) + sign = -1 + } else { + sign = 1 + } + return absVal, sign +} + +func setNegative(z, x *uint256.Uint) { + z.Set(x).Not(z).Add(z, one) +} + +// not implemented yet + +// 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 +// } + +// 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 +// } diff --git a/examples/gno.land/p/demo/int256/arithmetic.gnoA b/examples/gno.land/p/demo/int256/arithmetic.gnoA deleted file mode 100644 index 7230af65f8e..00000000000 --- a/examples/gno.land/p/demo/int256/arithmetic.gnoA +++ /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_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno new file mode 100644 index 00000000000..244bb22de32 --- /dev/null +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -0,0 +1,672 @@ +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"}, + // the maximum value of a positive number in int256 is less than the maximum value of a uint256 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Max int256 - 1) / 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) + } + }) + } + + 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", "1", "0"}, + {"10", "-1", "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()) + } + } +} + +func TestModPanic(t *testing.T) { + tests := []struct { + x, y string + }{ + {"10", "0"}, + {"10", "-0"}, + {"-10", "0"}, + {"-10", "-0"}, + } + + for _, tc := range tests { + defer func() { + if r := recover(); r == nil { + t.Errorf("Mod(%s, %s) did not panic", tc.x, tc.y) + } + }() + x, err := FromDecimal(tc.x) + if err != nil { + t.Error(err) + continue + } + + y, err := FromDecimal(tc.y) + if err != nil { + t.Error(err) + continue + } + + result := New().Mod(x, y) + t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, result.ToString(), "0") + } +} + +func TestDivE(t *testing.T) { + testCases := []struct { + x, y int64 + want int64 + }{ + {8, 3, 2}, + {8, -3, -2}, + {-8, 3, -3}, + {-8, -3, 3}, + {1, 2, 0}, + {1, -2, 0}, + {-1, 2, -1}, + {-1, -2, 1}, + {0, 1, 0}, + {0, -1, 0}, + } + + for _, tc := range testCases { + x := NewInt(tc.x) + y := NewInt(tc.y) + want := NewInt(tc.want) + got := new(Int).DivE(x, y) + if got.Cmp(want) != 0 { + t.Errorf("DivE(%v, %v) = %v, want %v", tc.x, tc.y, got, want) + } + } +} + +func TestDivEByZero(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("DivE did not panic on division by zero") + } + }() + + x := NewInt(1) + y := NewInt(0) + new(Int).DivE(x, y) +} + +func TestModEByZero(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("ModE did not panic on division by zero") + } + }() + + x := NewInt(1) + y := NewInt(0) + new(Int).ModE(x, y) +} + +func TestLargeNumbers(t *testing.T) { + x, _ := new(Int).SetString("123456789012345678901234567890") + y, _ := new(Int).SetString("987654321098765432109876543210") + + // Expected results (calculated separately) + expectedQ, _ := new(Int).SetString("0") + expectedR, _ := new(Int).SetString("123456789012345678901234567890") + + gotQ := new(Int).DivE(x, y) + gotR := new(Int).ModE(x, y) + + if gotQ.Cmp(expectedQ) != 0 { + t.Errorf("DivE with large numbers: got %v, want %v", gotQ, expectedQ) + } + + if gotR.Cmp(expectedR) != 0 { + t.Errorf("ModE with large numbers: got %v, want %v", gotR, expectedR) + } +} diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gnoA b/examples/gno.land/p/demo/int256/arithmetic_test.gnoA deleted file mode 100644 index 2e379800af3..00000000000 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gnoA +++ /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/cmp.gno b/examples/gno.land/p/demo/int256/cmp.gno new file mode 100644 index 00000000000..0df8462d22c --- /dev/null +++ b/examples/gno.land/p/demo/int256/cmp.gno @@ -0,0 +1,116 @@ +package int256 + +func (z *Int) Eq(x *Int) bool { + return z.value.Eq(&x.value) +} + +func (z *Int) Neq(x *Int) bool { + return !z.Eq(x) +} + +func (z *Int) Cmp(x *Int) int { + // Check if both numbers have the same sign + zSign := z.Sign() + xSign := x.Sign() + + if zSign != xSign { + // If signs are different, the comparison is straightforward + return zSign - xSign + } + + // If signs are the same, compare the absolute values + cmp := z.value.Cmp(&x.value) + + if zSign >= 0 { + // For positive numbers (including zero), the comparison result is correct + return cmp + } else { + // For negative numbers, invert the comparison result + return -cmp + } +} + +// // Eq returns true if z == x +// func (z *Int) Eq(x *Int) bool { +// return (z.neg == x.neg) && z.abs.Eq(x.abs) +// } + +// // Neq returns true if z != x +// func (z *Int) Neq(x *Int) bool { +// return !z.Eq(x) +// } + +// // Cmp compares x and y and returns: +// // +// // -1 if x < y +// // 0 if x == y +// // +1 if x > y +// func (z *Int) Cmp(x *Int) (r int) { +// // x cmp y == x cmp y +// // x cmp (-y) == x +// // (-x) cmp y == y +// // (-x) cmp (-y) == -(x cmp y) +// switch { +// case z == x: +// // nothing to do +// case z.neg == x.neg: +// r = z.abs.Cmp(x.abs) +// if z.neg { +// r = -r +// } +// case z.neg: +// r = -1 +// default: +// r = 1 +// } +// return +// } + +// // IsZero returns true if z == 0 +// func (z *Int) IsZero() bool { +// return z.abs.IsZero() +// } + +// // IsNeg returns true if z < 0 +// func (z *Int) IsNeg() bool { +// return z.neg +// } + +// // Lt returns true if z < x +// func (z *Int) Lt(x *Int) bool { +// if z.neg { +// if x.neg { +// return z.abs.Gt(x.abs) +// } else { +// return true +// } +// } else { +// if x.neg { +// return false +// } else { +// return z.abs.Lt(x.abs) +// } +// } +// } + +// // Gt returns true if z > x +// func (z *Int) Gt(x *Int) bool { +// if z.neg { +// if x.neg { +// return z.abs.Lt(x.abs) +// } else { +// return false +// } +// } else { +// if x.neg { +// return true +// } else { +// return z.abs.Gt(x.abs) +// } +// } +// } + +// // Clone creates a new Int identical to z +// func (z *Int) Clone() *Int { +// return &Int{z.abs.Clone(), z.neg} +// } diff --git a/examples/gno.land/p/demo/int256/cmp.gnoA b/examples/gno.land/p/demo/int256/cmp.gnoA deleted file mode 100644 index 426dfd76485..00000000000 --- a/examples/gno.land/p/demo/int256/cmp.gnoA +++ /dev/null @@ -1,86 +0,0 @@ -package int256 - -// Eq returns true if z == x -func (z *Int) Eq(x *Int) bool { - return (z.neg == x.neg) && z.abs.Eq(x.abs) -} - -// Neq returns true if z != x -func (z *Int) Neq(x *Int) bool { - return !z.Eq(x) -} - -// Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y -func (z *Int) Cmp(x *Int) (r int) { - // x cmp y == x cmp y - // x cmp (-y) == x - // (-x) cmp y == y - // (-x) cmp (-y) == -(x cmp y) - switch { - case z == x: - // nothing to do - case z.neg == x.neg: - r = z.abs.Cmp(x.abs) - if z.neg { - r = -r - } - case z.neg: - r = -1 - default: - r = 1 - } - return -} - -// IsZero returns true if z == 0 -func (z *Int) IsZero() bool { - return z.abs.IsZero() -} - -// IsNeg returns true if z < 0 -func (z *Int) IsNeg() bool { - return z.neg -} - -// Lt returns true if z < x -func (z *Int) Lt(x *Int) bool { - if z.neg { - if x.neg { - return z.abs.Gt(x.abs) - } else { - return true - } - } else { - if x.neg { - return false - } else { - return z.abs.Lt(x.abs) - } - } -} - -// Gt returns true if z > x -func (z *Int) Gt(x *Int) bool { - if z.neg { - if x.neg { - return z.abs.Lt(x.abs) - } else { - return false - } - } else { - if x.neg { - return true - } else { - return z.abs.Gt(x.abs) - } - } -} - -// Clone creates a new Int identical to z -func (z *Int) Clone() *Int { - return &Int{z.abs.Clone(), z.neg} -} diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gno new file mode 100644 index 00000000000..d91e239abbb --- /dev/null +++ b/examples/gno.land/p/demo/int256/conversion.gno @@ -0,0 +1,121 @@ +package int256 + +import "gno.land/p/demo/uint256" + +// // SetInt64 sets z to x and returns z. +// func (z *Int) SetInt64(x int64) *Int { +// z.initiateAbs() + +// neg := false +// if x < 0 { +// neg = true +// x = -x +// } +// if z.abs == nil { +// panic("abs is nil") +// } +// z.abs = z.abs.SetUint64(uint64(x)) +// z.neg = neg +// return z +// } + +// // SetUint64 sets z to x and returns z. +// func (z *Int) SetUint64(x uint64) *Int { +// z.initiateAbs() + +// if z.abs == nil { +// panic("abs is nil") +// } +// z.abs = z.abs.SetUint64(x) +// z.neg = false +// return z +// } + +// // Uint64 returns the lower 64-bits of z +// func (z *Int) Uint64() uint64 { +// return z.abs.Uint64() +// } + +// // Int64 returns the lower 64-bits of z +// func (z *Int) Int64() int64 { +// _abs := z.abs.Clone() + +// if z.neg { +// return -int64(_abs.Uint64()) +// } +// return int64(_abs.Uint64()) +// } + +// // Neg sets z to -x and returns z.) +// func (z *Int) Neg(x *Int) *Int { +// z.abs.Set(x.abs) +// if z.abs.IsZero() { +// z.neg = false +// } else { +// z.neg = !x.neg +// } +// return z +// } + +// // Set sets z to x and returns z. +// func (z *Int) Set(x *Int) *Int { +// z.abs.Set(x.abs) +// z.neg = x.neg +// return z +// } + +// // SetFromUint256 converts a uint256.Uint to Int and sets the value to z. +// func (z *Int) SetUint256(x *uint256.Uint) *Int { +// z.abs.Set(x) +// z.neg = false +// return z +// } + +// // OBS, differs from original mempooler int256 +// // ToString returns the decimal representation of z. +// func (z *Int) ToString() string { +// if z == nil { +// panic("int256: nil pointer to ToString()") +// } + +// t := z.abs.Dec() +// if z.neg { +// return "-" + t +// } + +// return t +// } + +// ToString returns a string representation of z in base 10. +// The string is prefixed with a minus sign if z is negative. +// +// TODO: fix +func (z *Int) ToString() string { + // Check if the number is zero + if z.value.IsZero() { + return "0" + } + + // Check if the number is negative + isNegative := z.Sign() < 0 + + // Create a copy of z.value to avoid modifying the original + var absValue uint256.Uint + if isNegative { + // For negative numbers, we need to compute the absolute value + // by performing two's complement negation + absValue.Sub(uint256.Zero(), &z.value) + } else { + absValue.Set(&z.value) + } + + // Convert the absolute value to a decimal string + str := absValue.ToString() + + // Add a minus sign for negative numbers + if isNegative { + return "-" + str + } + + return str +} diff --git a/examples/gno.land/p/demo/int256/conversion.gnoA b/examples/gno.land/p/demo/int256/conversion.gnoA deleted file mode 100644 index 9e264e7e46b..00000000000 --- a/examples/gno.land/p/demo/int256/conversion.gnoA +++ /dev/null @@ -1,87 +0,0 @@ -package int256 - -import "gno.land/p/demo/uint256" - -// SetInt64 sets z to x and returns z. -func (z *Int) SetInt64(x int64) *Int { - z.initiateAbs() - - neg := false - if x < 0 { - neg = true - x = -x - } - if z.abs == nil { - panic("abs is nil") - } - z.abs = z.abs.SetUint64(uint64(x)) - z.neg = neg - return z -} - -// SetUint64 sets z to x and returns z. -func (z *Int) SetUint64(x uint64) *Int { - z.initiateAbs() - - if z.abs == nil { - panic("abs is nil") - } - z.abs = z.abs.SetUint64(x) - z.neg = false - return z -} - -// Uint64 returns the lower 64-bits of z -func (z *Int) Uint64() uint64 { - return z.abs.Uint64() -} - -// Int64 returns the lower 64-bits of z -func (z *Int) Int64() int64 { - _abs := z.abs.Clone() - - if z.neg { - return -int64(_abs.Uint64()) - } - return int64(_abs.Uint64()) -} - -// Neg sets z to -x and returns z.) -func (z *Int) Neg(x *Int) *Int { - z.abs.Set(x.abs) - if z.abs.IsZero() { - z.neg = false - } else { - z.neg = !x.neg - } - return z -} - -// Set sets z to x and returns z. -func (z *Int) Set(x *Int) *Int { - z.abs.Set(x.abs) - z.neg = x.neg - return z -} - -// SetFromUint256 converts a uint256.Uint to Int and sets the value to z. -func (z *Int) SetUint256(x *uint256.Uint) *Int { - z.abs.Set(x) - z.neg = false - return z -} - -// OBS, differs from original mempooler int256 -// ToString returns the decimal representation of z. -func (z *Int) ToString() string { - if z == nil { - panic("int256: nil pointer to ToString()") - } - - t := z.abs.Dec() - if z.neg { - return "-" + t - } - - return t -} diff --git a/examples/gno.land/p/demo/int256/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gno new file mode 100644 index 00000000000..1b5617928e6 --- /dev/null +++ b/examples/gno.land/p/demo/int256/conversion_test.gno @@ -0,0 +1,228 @@ +package int256 + +// func TestSetInt64(t *testing.T) { +// tests := []struct { +// x int64 +// want string +// }{ +// {0, "0"}, +// {1, "1"}, +// {-1, "-1"}, +// {9223372036854775807, "9223372036854775807"}, +// {-9223372036854775808, "-9223372036854775808"}, +// } + +// for _, tc := range tests { +// var z Int +// z.SetInt64(tc.x) + +// got := z.ToString() +// if got != tc.want { +// t.Errorf("SetInt64(%d) = %s, want %s", tc.x, got, tc.want) +// } +// } +// } + +// func TestSetUint64(t *testing.T) { +// tests := []struct { +// x uint64 +// want string +// }{ +// {0, "0"}, +// {1, "1"}, +// } + +// for _, tc := range tests { +// var z Int +// z.SetUint64(tc.x) + +// got := z.ToString() +// if got != tc.want { +// t.Errorf("SetUint64(%d) = %s, want %s", tc.x, got, tc.want) +// } +// } +// } + +// func TestUint64(t *testing.T) { +// tests := []struct { +// x string +// want uint64 +// }{ +// {"0", 0}, +// {"1", 1}, +// {"9223372036854775807", 9223372036854775807}, +// {"9223372036854775808", 9223372036854775808}, +// {"18446744073709551615", 18446744073709551615}, +// {"18446744073709551616", 0}, +// {"18446744073709551617", 1}, +// {"-1", 1}, +// {"-18446744073709551615", 18446744073709551615}, +// {"-18446744073709551616", 0}, +// {"-18446744073709551617", 1}, +// } + +// for _, tc := range tests { +// z := MustFromDecimal(tc.x) + +// got := z.Uint64() +// if got != tc.want { +// t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) +// } +// } +// } + +// func TestInt64(t *testing.T) { +// tests := []struct { +// x string +// want int64 +// }{ +// {"0", 0}, +// {"1", 1}, +// {"9223372036854775807", 9223372036854775807}, +// {"18446744073709551616", 0}, +// {"18446744073709551617", 1}, +// {"-1", -1}, +// {"-9223372036854775808", -9223372036854775808}, +// } + +// for _, tc := range tests { +// z := MustFromDecimal(tc.x) + +// got := z.Int64() +// if got != tc.want { +// t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) +// } +// } +// } + +// func TestNeg(t *testing.T) { +// tests := []struct { +// x string +// want string +// }{ +// {"0", "0"}, +// {"1", "-1"}, +// {"-1", "1"}, +// {"9223372036854775807", "-9223372036854775807"}, +// {"-18446744073709551615", "18446744073709551615"}, +// } + +// for _, tc := range tests { +// z := MustFromDecimal(tc.x) +// z.Neg(z) + +// got := z.ToString() +// if got != tc.want { +// t.Errorf("Neg(%s) = %s, want %s", tc.x, got, tc.want) +// } +// } +// } + +// func TestSet(t *testing.T) { +// tests := []struct { +// x string +// want string +// }{ +// {"0", "0"}, +// {"1", "1"}, +// {"-1", "-1"}, +// {"9223372036854775807", "9223372036854775807"}, +// {"-18446744073709551615", "-18446744073709551615"}, +// } + +// for _, tc := range tests { +// z := MustFromDecimal(tc.x) +// z.Set(z) + +// got := z.ToString() +// if got != tc.want { +// t.Errorf("Set(%s) = %s, want %s", tc.x, got, tc.want) +// } +// } +// } + +// func TestSetUint256(t *testing.T) { +// tests := []struct { +// x string +// want string +// }{ +// {"0", "0"}, +// {"1", "1"}, +// {"9223372036854775807", "9223372036854775807"}, +// {"18446744073709551615", "18446744073709551615"}, +// } + +// for _, tc := range tests { +// got := New() + +// z := uint256.MustFromDecimal(tc.x) +// got.SetUint256(z) + +// if got.ToString() != tc.want { +// t.Errorf("SetUint256(%s) = %s, want %s", tc.x, got.ToString(), tc.want) +// } +// } +// } + +// func TestToString(t *testing.T) { +// tests := []struct { +// name string +// setup func() *Int +// expected string +// }{ +// { +// name: "Zero from subtraction", +// setup: func() *Int { +// minusThree := MustFromDecimal("-3") +// three := MustFromDecimal("3") +// return Zero().Add(minusThree, three) +// }, +// expected: "0", +// }, +// { +// name: "Zero from right shift", +// setup: func() *Int { +// return Zero().Rsh(One(), 1234) +// }, +// expected: "0", +// }, +// { +// name: "Positive number", +// setup: func() *Int { +// return MustFromDecimal("42") +// }, +// expected: "42", +// }, +// { +// name: "Negative number", +// setup: func() *Int { +// return MustFromDecimal("-42") +// }, +// expected: "-42", +// }, +// { +// name: "Large positive number", +// setup: func() *Int { +// return MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") +// }, +// expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935", +// }, +// { +// name: "Large negative number", +// setup: func() *Int { +// return MustFromDecimal("-115792089237316195423570985008687907853269984665640564039457584007913129639935") +// }, +// expected: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", +// }, +// } + +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// z := tt.setup() +// result := z.ToString() +// if result != tt.expected { +// t.Errorf("ToString() = %s, want %s", result, tt.expected) +// } +// }) +// } +// } diff --git a/examples/gno.land/p/demo/int256/conversion_test.gnoA b/examples/gno.land/p/demo/int256/conversion_test.gnoA deleted file mode 100644 index b085a77a15a..00000000000 --- a/examples/gno.land/p/demo/int256/conversion_test.gnoA +++ /dev/null @@ -1,234 +0,0 @@ -package int256 - -import ( - "testing" - - "gno.land/p/demo/uint256" -) - -func TestSetInt64(t *testing.T) { - tests := []struct { - x int64 - want string - }{ - {0, "0"}, - {1, "1"}, - {-1, "-1"}, - {9223372036854775807, "9223372036854775807"}, - {-9223372036854775808, "-9223372036854775808"}, - } - - for _, tc := range tests { - var z Int - z.SetInt64(tc.x) - - got := z.ToString() - if got != tc.want { - t.Errorf("SetInt64(%d) = %s, want %s", tc.x, got, tc.want) - } - } -} - -func TestSetUint64(t *testing.T) { - tests := []struct { - x uint64 - want string - }{ - {0, "0"}, - {1, "1"}, - } - - for _, tc := range tests { - var z Int - z.SetUint64(tc.x) - - got := z.ToString() - if got != tc.want { - t.Errorf("SetUint64(%d) = %s, want %s", tc.x, got, tc.want) - } - } -} - -func TestUint64(t *testing.T) { - tests := []struct { - x string - want uint64 - }{ - {"0", 0}, - {"1", 1}, - {"9223372036854775807", 9223372036854775807}, - {"9223372036854775808", 9223372036854775808}, - {"18446744073709551615", 18446744073709551615}, - {"18446744073709551616", 0}, - {"18446744073709551617", 1}, - {"-1", 1}, - {"-18446744073709551615", 18446744073709551615}, - {"-18446744073709551616", 0}, - {"-18446744073709551617", 1}, - } - - for _, tc := range tests { - z := MustFromDecimal(tc.x) - - got := z.Uint64() - if got != tc.want { - t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) - } - } -} - -func TestInt64(t *testing.T) { - tests := []struct { - x string - want int64 - }{ - {"0", 0}, - {"1", 1}, - {"9223372036854775807", 9223372036854775807}, - {"18446744073709551616", 0}, - {"18446744073709551617", 1}, - {"-1", -1}, - {"-9223372036854775808", -9223372036854775808}, - } - - for _, tc := range tests { - z := MustFromDecimal(tc.x) - - got := z.Int64() - if got != tc.want { - t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) - } - } -} - -func TestNeg(t *testing.T) { - tests := []struct { - x string - want string - }{ - {"0", "0"}, - {"1", "-1"}, - {"-1", "1"}, - {"9223372036854775807", "-9223372036854775807"}, - {"-18446744073709551615", "18446744073709551615"}, - } - - for _, tc := range tests { - z := MustFromDecimal(tc.x) - z.Neg(z) - - got := z.ToString() - if got != tc.want { - t.Errorf("Neg(%s) = %s, want %s", tc.x, got, tc.want) - } - } -} - -func TestSet(t *testing.T) { - tests := []struct { - x string - want string - }{ - {"0", "0"}, - {"1", "1"}, - {"-1", "-1"}, - {"9223372036854775807", "9223372036854775807"}, - {"-18446744073709551615", "-18446744073709551615"}, - } - - for _, tc := range tests { - z := MustFromDecimal(tc.x) - z.Set(z) - - got := z.ToString() - if got != tc.want { - t.Errorf("Set(%s) = %s, want %s", tc.x, got, tc.want) - } - } -} - -func TestSetUint256(t *testing.T) { - tests := []struct { - x string - want string - }{ - {"0", "0"}, - {"1", "1"}, - {"9223372036854775807", "9223372036854775807"}, - {"18446744073709551615", "18446744073709551615"}, - } - - for _, tc := range tests { - got := New() - - z := uint256.MustFromDecimal(tc.x) - got.SetUint256(z) - - if got.ToString() != tc.want { - t.Errorf("SetUint256(%s) = %s, want %s", tc.x, got.ToString(), tc.want) - } - } -} - -func TestToString(t *testing.T) { - tests := []struct { - name string - setup func() *Int - expected string - }{ - { - name: "Zero from subtraction", - setup: func() *Int { - minusThree := MustFromDecimal("-3") - three := MustFromDecimal("3") - return Zero().Add(minusThree, three) - }, - expected: "0", - }, - { - name: "Zero from right shift", - setup: func() *Int { - return Zero().Rsh(One(), 1234) - }, - expected: "0", - }, - { - name: "Positive number", - setup: func() *Int { - return MustFromDecimal("42") - }, - expected: "42", - }, - { - name: "Negative number", - setup: func() *Int { - return MustFromDecimal("-42") - }, - expected: "-42", - }, - { - name: "Large positive number", - setup: func() *Int { - return MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") - }, - expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - { - name: "Large negative number", - setup: func() *Int { - return MustFromDecimal("-115792089237316195423570985008687907853269984665640564039457584007913129639935") - }, - expected: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - z := tt.setup() - result := z.ToString() - if result != tt.expected { - t.Errorf("ToString() = %s, want %s", result, tt.expected) - } - }) - } -} diff --git a/examples/gno.land/p/demo/int256/doc.gno b/examples/gno.land/p/demo/int256/doc.gno index 3a9fb2207ee..70e1aabc8a4 100644 --- a/examples/gno.land/p/demo/int256/doc.gno +++ b/examples/gno.land/p/demo/int256/doc.gno @@ -1,2 +1,2 @@ // This package provides a 256-bit signed integer type, Int and associated functions. -package int256 \ No newline at end of file +package int256 diff --git a/examples/gno.land/p/demo/int256/int256_test.gno b/examples/gno.land/p/demo/int256/int256_test.gno index 662710cc3ea..91ac1f5e461 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -28,7 +28,7 @@ func TestNewInt(t *testing.T) { {0, 0}, {1, 1}, {-1, -1}, - {9223372036854775807, 1}, // max int64 + {9223372036854775807, 1}, // max int64 {-9223372036854775808, -1}, // min int64 } From 0c53f5a1ffcb7bfdd2a70c522c7ace759de3a800 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 26 Sep 2024 14:54:08 +0900 Subject: [PATCH 03/11] bitwise --- examples/gno.land/p/demo/int256/absolute.gnoA | 2 +- .../gno.land/p/demo/int256/absolute_test.gnoA | 62 +++--- .../gno.land/p/demo/int256/arithmetic.gno | 112 ++++------ examples/gno.land/p/demo/int256/bitwise.gno | 31 +++ examples/gno.land/p/demo/int256/bitwise.gnoA | 94 --------- .../gno.land/p/demo/int256/bitwise_test.gno | 135 ++++++++++++ .../gno.land/p/demo/int256/bitwise_test.gnoA | 199 ------------------ examples/gno.land/p/demo/int256/cmp.gno | 126 +++-------- .../int256/{cmp_test.gnoA => cmp_test.gno} | 36 ++-- examples/gno.land/p/demo/int256/int256.gno | 54 ++--- .../gno.land/p/demo/int256/int256_test.gno | 159 ++++++++++---- 11 files changed, 432 insertions(+), 578 deletions(-) create mode 100644 examples/gno.land/p/demo/int256/bitwise.gno delete mode 100644 examples/gno.land/p/demo/int256/bitwise.gnoA create mode 100644 examples/gno.land/p/demo/int256/bitwise_test.gno delete mode 100644 examples/gno.land/p/demo/int256/bitwise_test.gnoA rename examples/gno.land/p/demo/int256/{cmp_test.gnoA => cmp_test.gno} (81%) diff --git a/examples/gno.land/p/demo/int256/absolute.gnoA b/examples/gno.land/p/demo/int256/absolute.gnoA index 25c71b5ab20..989d0d53029 100644 --- a/examples/gno.land/p/demo/int256/absolute.gnoA +++ b/examples/gno.land/p/demo/int256/absolute.gnoA @@ -1,6 +1,6 @@ package int256 -// import "gno.land/p/demo/uint256" +import "gno.land/p/demo/uint256" // Abs returns |z| // func (z *Int) Abs() *uint256.Uint { diff --git a/examples/gno.land/p/demo/int256/absolute_test.gnoA b/examples/gno.land/p/demo/int256/absolute_test.gnoA index 6e6a6297e9c..5c5d3ae2908 100644 --- a/examples/gno.land/p/demo/int256/absolute_test.gnoA +++ b/examples/gno.land/p/demo/int256/absolute_test.gnoA @@ -1,36 +1,36 @@ package int256 -// import ( -// "testing" - -// "gno.land/p/demo/uint256" -// ) - -// func TestAbs(t *testing.T) { -// tests := []struct { -// x, want string -// }{ -// {"0", "0"}, -// {"1", "1"}, -// {"-1", "1"}, -// {"-2", "2"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, -// } - -// for _, tc := range tests { -// x, err := FromDecimal(tc.x) -// if err != nil { -// t.Error(err) -// continue -// } - -// got := x.Abs() - -// if got.ToString() != tc.want { -// t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) -// } -// } -// } +import ( + "testing" + + "gno.land/p/demo/uint256" +) + +func TestAbs(t *testing.T) { + tests := []struct { + x, want string + }{ + {"0", "0"}, + {"1", "1"}, + {"-1", "1"}, + {"-2", "2"}, + {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + } + + for _, tc := range tests { + x, err := FromDecimal(tc.x) + if err != nil { + t.Error(err) + continue + } + + got := x.Abs() + + if got.ToString() != tc.want { + t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) + } + } +} // func TestAbsGt(t *testing.T) { // tests := []struct { diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index 0c535b1db2b..3f8c709dc4d 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -1,6 +1,10 @@ package int256 -import "gno.land/p/demo/uint256" +import ( + "gno.land/p/demo/uint256" +) + +var divisionByZeroError = "division by zero" func (z *Int) Add(x, y *Int) *Int { z.value.Add(&x.value, &y.value) @@ -27,9 +31,9 @@ func (z *Int) Mul(x, y *Int) *Int { return z } -/* ---------------------------------------------------------------------------- -// Division and modulus operations -// ---------------------------------------------------------------------------- +/* +--------------------------------------------------------------------------+ +// |Division and modulus operations | +// +--------------------------------------------------------------------------+ // // This package provides three different division and modulus operations: // - Div and Rem: Truncated division (T-division) @@ -111,15 +115,11 @@ func (z *Int) Mul(x, y *Int) *Int { // Note: This implementation rounds towards zero, as is standard in Go. func (z *Int) Div(x, y *Int) *Int { // Step 1: Check for division by zero - if y.value.IsZero() { - panic("division by zero") + if y.IsZero() { + panic(divisionByZeroError) } - // Step 2: Determine the signs of x and y - xSign := x.Sign() - ySign := y.Sign() - - // Step 3: Calculate the absolute values of x and y + // Step 2, 3: Calculate the absolute values of x and y xAbs, xSign := abs(x) yAbs, ySign := abs(y) @@ -129,8 +129,7 @@ func (z *Int) Div(x, y *Int) *Int { // Step 5: Adjust the sign of the result // if x and y have different signs, the result must be negative if xSign != ySign { - // convert the positive result to negative using two's complement - setNegative(&z.value, &z.value) + z.value.Not(&z.value).Add(&z.value, uint1) } return z @@ -186,22 +185,21 @@ func (z *Int) Div(x, y *Int) *Int { // Note: This implementation ensures correct truncation towards zero for negative dividends. func (z *Int) Quo(x, y *Int) *Int { // Step 1: Check for division by zero - if y.value.IsZero() { - panic("division by zero") + if y.IsZero() { + panic(divisionByZeroError) } - // Step 2: Determine the signs of x and y - xSign := x.Sign() - ySign := y.Sign() - - // Step 3: Calculate the absolute values of x and y + // Step 2, 3: Calculate the absolute values of x and y var xAbs, yAbs, q, r uint256.Uint + var xSign, ySign int + xAbs, xSign = abs(x) yAbs, ySign = abs(y) // Step 4: Perform unsigned division and get the remainder - // q = xAbs / yAbs - // r = xAbs % yAbs + // + // q = xAbs / yAbs + // r = xAbs % yAbs // // Use Euclidean division to always yields a non-negative remainder, which is // crucial for correct truncation towards zero in subsequent steps. @@ -214,12 +212,12 @@ func (z *Int) Quo(x, y *Int) *Int { // If x and y have different signs and there's a non-zero remainder, // we need to round towards zero by adding 1 to the quotient magnitude. if (xSign < 0) != (ySign < 0) && !r.IsZero() { - q.Add(&q, one) + q.Add(&q, uint1) } // Step 6: Adjust the sign of the result if xSign != ySign { - setNegative(&q, &q) + q.Not(&q).Add(&q, uint1) } z.value.Set(&q) @@ -269,28 +267,23 @@ func (z *Int) Quo(x, y *Int) *Int { // Note: The sign of the remainder is always the same as the sign of the dividend (x). func (z *Int) Rem(x, y *Int) *Int { // Step 1: Check for division by zero - if y.value.IsZero() { - panic("division by zero") + if y.IsZero() { + panic(divisionByZeroError) } - // Step 2: Determine the signs of x and y - xSign := x.Sign() - ySign := y.Sign() - - // Step 3: Calculate the absolute values of x and y + // Step 2, 3 var xAbs, yAbs, q, r uint256.Uint + var xSign int + xAbs, xSign = abs(x) - yAbs, ySign = abs(y) + yAbs, _ = abs(y) // Step 4: Perform unsigned division and get the remainder q.DivMod(&xAbs, &yAbs, &r) // Step 5: Adjust the sign of the remainder - if xSign < 0 { - if !r.IsZero() { - // convert positive remainder to negative - setNegative(&r, &r) - } + if xSign < 0 && !r.IsZero() { + r.Not(&r).Add(&r, uint1) } z.value.Set(&r) @@ -310,8 +303,8 @@ func (z *Int) Mod(x, y *Int) *Int { // 1. The remainder is always non-negative: 0 <= x mod y < |y| // 2. It follows the identity: x = y * (x div y) + (x mod y) func (z *Int) DivE(x, y *Int) *Int { - if y.value.IsZero() { - panic("division by zero") + if y.IsZero() { + panic(divisionByZeroError) } z.Div(x, y) @@ -320,14 +313,10 @@ func (z *Int) DivE(x, y *Int) *Int { r := new(Int).Rem(x, y) // Adjust the quotient if necessary - if r.Sign() < 0 { - if y.Sign() > 0 { - return z.Sub(z, NewInt(1)) - } - return z.Add(z, NewInt(1)) - } + if r.Sign() >= 0 { return z } + if y.Sign() > 0 { return z.Sub(z, int1) } - return z + return z.Add(z, int1) } // ModE computes the Euclidean modulus of x by y, setting z to the result and returning z. @@ -367,39 +356,30 @@ func (z *Int) DivE(x, y *Int) *Int { // Note: This implementation ensures that the result always has the same sign as y, // which is different from the Rem operation. func (z *Int) ModE(x, y *Int) *Int { - if y.value.IsZero() { - panic("division by zero") + if y.IsZero() { + panic(divisionByZeroError) } // Perform T-division to get the remainder z.Rem(x, y) // Adjust the remainder if necessary - if z.Sign() < 0 { - if y.Sign() > 0 { - return z.Add(z, y) - } - return z.Sub(z, y) - } + if z.Sign() >= 0 { return z } + if y.Sign() > 0 { return z.Add(z, y) } - return z + return z.Sub(z, y) } func abs(x *Int) (uint256.Uint, int) { sign := x.Sign() - var absVal uint256.Uint - absVal.Set(&x.value) - if sign < 0 { - setNegative(&absVal, &x.value) - sign = -1 - } else { - sign = 1 + + if sign >= 0 { + return x.value, 1 } - return absVal, sign -} -func setNegative(z, x *uint256.Uint) { - z.Set(x).Not(z).Add(z, one) + var absVal uint256.Uint + absVal.Set(&x.value).Not(&absVal).Add(&absVal, uint1) + return absVal, -1 } // not implemented yet diff --git a/examples/gno.land/p/demo/int256/bitwise.gno b/examples/gno.land/p/demo/int256/bitwise.gno new file mode 100644 index 00000000000..70f13c172ea --- /dev/null +++ b/examples/gno.land/p/demo/int256/bitwise.gno @@ -0,0 +1,31 @@ +package int256 + +func (z *Int) Not(x *Int) *Int { + z.value.Not(&x.value) + return z +} + +func (z *Int) And(x, y *Int) *Int { + z.value.And(&x.value, &y.value) + return z +} + +func (z *Int) Or(x, y *Int) *Int { + z.value.Or(&x.value, &y.value) + return z +} + +func (z *Int) Xor(x, y *Int) *Int { + z.value.Xor(&x.value, &y.value) + return z +} + +func (z *Int) Rsh(x *Int, n uint) *Int { + z.value.Rsh(&x.value, n) + return z +} + +func (z *Int) Lsh(x *Int, n uint) *Int { + z.value.Lsh(&x.value, n) + return z +} diff --git a/examples/gno.land/p/demo/int256/bitwise.gnoA b/examples/gno.land/p/demo/int256/bitwise.gnoA deleted file mode 100644 index c0d0f65f78f..00000000000 --- a/examples/gno.land/p/demo/int256/bitwise.gnoA +++ /dev/null @@ -1,94 +0,0 @@ -package int256 - -import ( - "gno.land/p/demo/uint256" -) - -// Or sets z = x | y and returns z. -func (z *Int) Or(x, y *Int) *Int { - if x.neg == y.neg { - if x.neg { - // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1) - x1 := new(uint256.Uint).Sub(x.abs, one) - y1 := new(uint256.Uint).Sub(y.abs, one) - z.abs = z.abs.Add(z.abs.And(x1, y1), one) - z.neg = true // z cannot be zero if x and y are negative - return z - } - - // x | y == x | y - z.abs = z.abs.Or(x.abs, y.abs) - z.neg = false - return z - } - - // x.neg != y.neg - if x.neg { - x, y = y, x // | is symmetric - } - - // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1) - y1 := new(uint256.Uint).Sub(y.abs, one) - z.abs = z.abs.Add(z.abs.AndNot(y1, x.abs), one) - z.neg = true // z cannot be zero if one of x or y is negative - - return z -} - -// And sets z = x & y and returns z. -func (z *Int) And(x, y *Int) *Int { - if x.neg == y.neg { - if x.neg { - // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1) - x1 := new(uint256.Uint).Sub(x.abs, one) - y1 := new(uint256.Uint).Sub(y.abs, one) - z.abs = z.abs.Add(z.abs.Or(x1, y1), one) - z.neg = true // z cannot be zero if x and y are negative - return z - } - - // x & y == x & y - z.abs = z.abs.And(x.abs, y.abs) - z.neg = false - return z - } - - // x.neg != y.neg - // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1192-1202;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 - if x.neg { - x, y = y, x // & is symmetric - } - - // x & (-y) == x & ^(y-1) == x &^ (y-1) - y1 := new(uint256.Uint).Sub(y.abs, uint256.One()) - z.abs = z.abs.AndNot(x.abs, y1) - z.neg = false - return z -} - -// Rsh sets z = x >> n and returns z. -// OBS: Different from original implementation it was using math.Big -func (z *Int) Rsh(x *Int, n uint) *Int { - if !x.neg { - z.abs.Rsh(x.abs, n) - z.neg = x.neg - return z - } - - // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1118-1126;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 - t := NewInt(0).Sub(FromUint256(x.abs), NewInt(1)) - t = t.Rsh(t, n) - - _tmp := t.Add(t, NewInt(1)) - z.abs = _tmp.Abs() - z.neg = true - - return z -} - -// Lsh sets z = x << n and returns z. -func (z *Int) Lsh(x *Int, n uint) *Int { - z.abs.Lsh(x.abs, n) - z.neg = x.neg - return z -} diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gno new file mode 100644 index 00000000000..98de2895585 --- /dev/null +++ b/examples/gno.land/p/demo/int256/bitwise_test.gno @@ -0,0 +1,135 @@ +package int256 + +import ( + "testing" +) + +func TestBitwise_And(t *testing.T) { + tests := []struct { + x, y, want string + }{ + {"5", "1", "1"}, // 0101 & 0001 = 0001 + {"-1", "1", "1"}, // 1111 & 0001 = 0001 + {"-5", "3", "3"}, // 1111...1011 & 0000...0011 = 0000...0011 + } + + for _, tc := range tests { + x, _ := FromDecimal(tc.x) + y, _ := FromDecimal(tc.y) + want, _ := FromDecimal(tc.want) + + got := new(Int).And(x, y) + + if got.Neq(want) { + t.Errorf("And(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + } + } +} + +func TestBitwise_Or(t *testing.T) { + tests := []struct { + x, y, want string + }{ + {"5", "1", "5"}, // 0101 | 0001 = 0101 + {"-1", "1", "-1"}, // 1111 | 0001 = 1111 + {"-5", "3", "-5"}, // 1111...1011 | 0000...0011 = 1111...1011 + } + + for _, tc := range tests { + x, _ := FromDecimal(tc.x) + y, _ := FromDecimal(tc.y) + want, _ := FromDecimal(tc.want) + + got := new(Int).Or(x, y) + + if got.Neq(want) { + t.Errorf("Or(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + } + } +} + +func TestBitwise_Not(t *testing.T) { + tests := []struct { + x, want string + }{ + {"5", "-6"}, // 0101 -> 1111...1010 + {"-1", "0"}, // 1111...1111 -> 0000...0000 + } + + for _, tc := range tests { + x, _ := FromDecimal(tc.x) + want, _ := FromDecimal(tc.want) + + got := new(Int).Not(x) + + if got.Neq(want) { + t.Errorf("Not(%s) = %s, want %s", x.ToString(), got.ToString(), want.ToString()) + } + } +} + +func TestBitwise_Xor(t *testing.T) { + tests := []struct { + x, y, want string + }{ + {"5", "1", "4"}, // 0101 ^ 0001 = 0100 + {"-1", "1", "-2"}, // 1111...1111 ^ 0000...0001 = 1111...1110 + {"-5", "3", "-8"}, // 1111...1011 ^ 0000...0011 = 1111...1000 + } + + for _, tt := range tests { + x, _ := FromDecimal(tt.x) + y, _ := FromDecimal(tt.y) + want, _ := FromDecimal(tt.want) + + got := new(Int).Xor(x, y) + + if got.Neq(want) { + t.Errorf("Xor(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + } + } +} + +func TestBitwise_Rsh(t *testing.T) { + tests := []struct { + x string + n uint + want string + }{ + {"5", 1, "2"}, // 0101 >> 1 = 0010 + {"42", 3, "5"}, // 00101010 >> 3 = 00000101 + } + + for _, tt := range tests { + x, _ := FromDecimal(tt.x) + want, _ := FromDecimal(tt.want) + + got := new(Int).Rsh(x, tt.n) + + if got.Neq(want) { + t.Errorf("Rsh(%s, %d) = %s, want %s", x.ToString(), tt.n, got.ToString(), want.ToString()) + } + } +} + +func TestBitwise_Lsh(t *testing.T) { + tests := []struct { + x string + n uint + want string + }{ + {"5", 2, "20"}, // 0101 << 2 = 10100 + {"42", 5, "1344"}, // 00101010 << 5 = 10101000000 + } + + for _, tt := range tests { + x, _ := FromDecimal(tt.x) + want, _ := FromDecimal(tt.want) + + got := new(Int).Lsh(x, tt.n) + + if got.Neq(want) { + t.Errorf("Lsh(%s, %d) = %s, want %s", x.ToString(), tt.n, got.ToString(), want.ToString()) + } + } +} diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gnoA b/examples/gno.land/p/demo/int256/bitwise_test.gnoA deleted file mode 100644 index 8dc16cd17ac..00000000000 --- a/examples/gno.land/p/demo/int256/bitwise_test.gnoA +++ /dev/null @@ -1,199 +0,0 @@ -package int256 - -import ( - "testing" - - "gno.land/p/demo/uint256" -) - -func TestOr(t *testing.T) { - tests := []struct { - name string - x, y, want Int - }{ - { - name: "all zeroes", - x: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "all ones", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - }, - { - name: "mixed", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - }, - { - name: "one operand all ones", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 0xFFFFFFFFFFFFFFFF, 0x0000000000000000}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got := New() - got.Or(&tc.x, &tc.y) - - if got.Neq(&tc.want) { - t.Errorf("Or(%v, %v) = %v, want %v", tc.x, tc.y, got, tc.want) - } - }) - } -} - -func TestAnd(t *testing.T) { - tests := []struct { - name string - x, y, want Int - }{ - { - name: "all zeroes", - x: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "all ones", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - }, - { - name: "mixed", - x: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "mixed 2", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "mixed 3", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "one operand zero", - x: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0, 0, 0, 0}}, neg: false}, - }, - { - name: "one operand all ones", - x: Int{abs: &uint256.Uint{arr: [4]uint64{^uint64(0), ^uint64(0), ^uint64(0), ^uint64(0)}}, neg: false}, - y: Int{abs: &uint256.Uint{arr: [4]uint64{0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 0xFFFFFFFFFFFFFFFF, 0x0000000000000000}}, neg: false}, - want: Int{abs: &uint256.Uint{arr: [4]uint64{0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 0xFFFFFFFFFFFFFFFF, 0x0000000000000000}}, neg: false}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got := New() - got.And(&tc.x, &tc.y) - - if got.Neq(&tc.want) { - t.Errorf("And(%v, %v) = %v, want %v", tc.x, tc.y, got, tc.want) - } - }) - } -} - -func TestRsh(t *testing.T) { - tests := []struct { - x string - n uint - want string - }{ - {"1024", 0, "1024"}, - {"1024", 1, "512"}, - {"1024", 2, "256"}, - {"1024", 10, "1"}, - {"1024", 11, "0"}, - {"18446744073709551615", 0, "18446744073709551615"}, - {"18446744073709551615", 1, "9223372036854775807"}, - {"18446744073709551615", 62, "3"}, - {"18446744073709551615", 63, "1"}, - {"18446744073709551615", 64, "0"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 0, "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 1, "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 128, "340282366920938463463374607431768211455"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 255, "1"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 256, "0"}, - {"-1024", 0, "-1024"}, - {"-1024", 1, "-512"}, - {"-1024", 2, "-256"}, - {"-1024", 10, "-1"}, - {"-1024", 10, "-1"}, - {"-9223372036854775808", 0, "-9223372036854775808"}, - {"-9223372036854775808", 1, "-4611686018427387904"}, - {"-9223372036854775808", 62, "-2"}, - {"-9223372036854775808", 63, "-1"}, - {"-9223372036854775808", 64, "-1"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 0, "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 1, "-28948022309329048855892746252171976963317496166410141009864396001978282409984"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 253, "-4"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 254, "-2"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 255, "-1"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", 256, "-1"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Rsh(x, tc.n) - - if got.ToString() != tc.want { - t.Errorf("Rsh(%s, %d) = %v, want %v", tc.x, tc.n, got.ToString(), tc.want) - } - } -} - -func TestLsh(t *testing.T) { - tests := []struct { - x string - n uint - want string - }{ - {"1", 0, "1"}, - {"1", 1, "2"}, - {"1", 2, "4"}, - {"2", 0, "2"}, - {"2", 1, "4"}, - {"2", 2, "8"}, - {"-2", 0, "-2"}, - {"-4", 0, "-4"}, - {"-8", 0, "-8"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - got := New() - got.Lsh(x, tc.n) - - if got.ToString() != tc.want { - t.Errorf("Lsh(%s, %d) = %v, want %v", tc.x, tc.n, got.ToString(), tc.want) - } - } -} diff --git a/examples/gno.land/p/demo/int256/cmp.gno b/examples/gno.land/p/demo/int256/cmp.gno index 0df8462d22c..ee4e035638e 100644 --- a/examples/gno.land/p/demo/int256/cmp.gno +++ b/examples/gno.land/p/demo/int256/cmp.gno @@ -8,109 +8,53 @@ func (z *Int) Neq(x *Int) bool { return !z.Eq(x) } +// Cmp compares z and x and returns: +// +// - 1 if z > x +// - 0 if z == x +// - -1 if z < x func (z *Int) Cmp(x *Int) int { - // Check if both numbers have the same sign zSign := z.Sign() xSign := x.Sign() - if zSign != xSign { - // If signs are different, the comparison is straightforward - return zSign - xSign + if zSign == xSign { + return z.value.Cmp(&x.value) } - // If signs are the same, compare the absolute values - cmp := z.value.Cmp(&x.value) - - if zSign >= 0 { - // For positive numbers (including zero), the comparison result is correct - return cmp - } else { - // For negative numbers, invert the comparison result - return -cmp + if zSign == 0 { + return -xSign } -} -// // Eq returns true if z == x -// func (z *Int) Eq(x *Int) bool { -// return (z.neg == x.neg) && z.abs.Eq(x.abs) -// } + return zSign +} -// // Neq returns true if z != x -// func (z *Int) Neq(x *Int) bool { -// return !z.Eq(x) -// } +// IsZero returns true if z == 0 +func (z *Int) IsZero() bool { + return z.Sign() == 0 +} -// // Cmp compares x and y and returns: -// // -// // -1 if x < y -// // 0 if x == y -// // +1 if x > y -// func (z *Int) Cmp(x *Int) (r int) { -// // x cmp y == x cmp y -// // x cmp (-y) == x -// // (-x) cmp y == y -// // (-x) cmp (-y) == -(x cmp y) -// switch { -// case z == x: -// // nothing to do -// case z.neg == x.neg: -// r = z.abs.Cmp(x.abs) -// if z.neg { -// r = -r -// } -// case z.neg: -// r = -1 -// default: -// r = 1 -// } -// return -// } +// IsNeg returns true if z < 0 +func (z *Int) IsNeg() bool { + return z.Sign() < 0 +} -// // IsZero returns true if z == 0 -// func (z *Int) IsZero() bool { -// return z.abs.IsZero() -// } +func (z *Int) Lt(x *Int) bool { + return z.Cmp(x) < 0 +} -// // IsNeg returns true if z < 0 -// func (z *Int) IsNeg() bool { -// return z.neg -// } +func (z *Int) Gt(x *Int) bool { + return z.Cmp(x) > 0 +} -// // Lt returns true if z < x -// func (z *Int) Lt(x *Int) bool { -// if z.neg { -// if x.neg { -// return z.abs.Gt(x.abs) -// } else { -// return true -// } -// } else { -// if x.neg { -// return false -// } else { -// return z.abs.Lt(x.abs) -// } -// } -// } +func (z *Int) Le(x *Int) bool { + return z.Cmp(x) <= 0 +} -// // Gt returns true if z > x -// func (z *Int) Gt(x *Int) bool { -// if z.neg { -// if x.neg { -// return z.abs.Lt(x.abs) -// } else { -// return false -// } -// } else { -// if x.neg { -// return true -// } else { -// return z.abs.Gt(x.abs) -// } -// } -// } +func (z *Int) Ge(x *Int) bool { + return z.Cmp(x) >= 0 +} -// // Clone creates a new Int identical to z -// func (z *Int) Clone() *Int { -// return &Int{z.abs.Clone(), z.neg} -// } +// Clone creates a new Int identical to z +func (z *Int) Clone() *Int { + return New().FromUint256(&z.value) +} diff --git a/examples/gno.land/p/demo/int256/cmp_test.gnoA b/examples/gno.land/p/demo/int256/cmp_test.gno similarity index 81% rename from examples/gno.land/p/demo/int256/cmp_test.gnoA rename to examples/gno.land/p/demo/int256/cmp_test.gno index 81b9231babe..c646c7a7ea9 100644 --- a/examples/gno.land/p/demo/int256/cmp_test.gnoA +++ b/examples/gno.land/p/demo/int256/cmp_test.gno @@ -85,7 +85,7 @@ func TestCmp(t *testing.T) { {"-1", "0", -1}, {"0", "-1", 1}, {"1", "1", 0}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", 1}, + // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", 1}, } for _, tc := range tests { @@ -140,7 +140,7 @@ func TestIsNeg(t *testing.T) { want bool }{ {"0", false}, - {"-0", true}, // TODO: should this be false? + {"-0", false}, {"1", false}, {"-1", true}, {"10", false}, @@ -173,7 +173,7 @@ func TestLt(t *testing.T) { {"0", "-1", false}, {"1", "1", false}, {"-1", "-1", false}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", false}, + // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", false}, } for _, tc := range tests { @@ -208,7 +208,7 @@ func TestGt(t *testing.T) { {"0", "-1", true}, {"1", "1", false}, {"-1", "-1", false}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, + // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, } for _, tc := range tests { @@ -232,21 +232,19 @@ func TestGt(t *testing.T) { } func TestClone(t *testing.T) { - tests := []struct { - x string - }{ - {"0"}, - {"-0"}, - {"1"}, - {"-1"}, - {"10"}, - {"-10"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + tests := []string{ + "0", + "-0", + "1", + "-1", + "10", + "-10", + "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "-115792089237316195423570985008687907853269984665640564039457584007913129639935", } - for _, tc := range tests { - x, err := FromDecimal(tc.x) + for _, xStr := range tests { + x, err := FromDecimal(xStr) if err != nil { t.Error(err) continue @@ -254,8 +252,8 @@ func TestClone(t *testing.T) { y := x.Clone() - if x.Cmp(y) != 0 { - t.Errorf("Clone(%s) = %v, want %v", tc.x, y, x) + if x.Neq(y) { + t.Errorf("cloned value is not equal to original value") } } } diff --git a/examples/gno.land/p/demo/int256/int256.gno b/examples/gno.land/p/demo/int256/int256.gno index 6c26322ee41..008ff5233f1 100644 --- a/examples/gno.land/p/demo/int256/int256.gno +++ b/examples/gno.land/p/demo/int256/int256.gno @@ -1,10 +1,15 @@ package int256 import ( + "errors" + "gno.land/p/demo/uint256" ) -var one = uint256.NewUint(1) +var ( + int1 = NewInt(1) + uint1 = uint256.NewUint(1) +) type Int struct { value uint256.Uint @@ -33,9 +38,7 @@ func Zero() *Int { // 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 { - z := &Int{} - z.value.SetUint64(1) - return z + return new(Int).SetInt64(1) } // Sign determines the sign of the Int. @@ -90,46 +93,26 @@ func MustFromDecimal(s string) *Int { // 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 - 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 + if len(s) == 0 { + return nil, errors.New("cannot set int256 from empty string") + } + + // Check for negative sign + neg := s[0] == '-' + if neg || s[0] == '+' { s = s[1:] } + // Convert string to uint256 temp, err := uint256.FromDecimal(s) if err != nil { return nil, err } - // for negative numbers, apply two's complement + // If negative, negate the uint256 value 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. + temp.Neg(temp) } z.value.Set(temp) @@ -145,8 +128,7 @@ func (z *Int) SetInt64(v int64) *Int { z.value.SetUint64(uint64(v)) } else { z.value.SetUint64(uint64(-v)) - z.value.Not(&z.value) - z.value.Add(&z.value, one) + z.value.Not(&z.value).Add(&z.value, uint1) } 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 91ac1f5e461..48a4c3c7ea9 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -6,17 +6,28 @@ import ( "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 TestInitializers(t *testing.T) { + tests := []struct { + name string + fn func() *Int + wantSign int + wantStr string + }{ + {"Zero", Zero, 0, "0"}, + {"New", New, 0, "0"}, + {"One", One, 1, "1"}, } -} -func TestNew(t *testing.T) { - z := New() - if z.Sign() != 0 { - t.Errorf("New() = %d, want %d", z.Sign(), 0) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := tt.fn() + if z.Sign() != tt.wantSign { + t.Errorf("%s() = %d, want %d", tt.name, z.Sign(), tt.wantSign) + } + if z.ToString() != tt.wantStr { + t.Errorf("%s() = %s, want %s", tt.name, z.ToString(), tt.wantStr) + } + }) } } @@ -41,7 +52,7 @@ func TestNewInt(t *testing.T) { } func TestFromDecimal(t *testing.T) { - testCases := []struct { + tests := []struct { input string expected int isError bool @@ -54,54 +65,68 @@ func TestFromDecimal(t *testing.T) { {"invalid", 0, true}, } - for _, tc := range testCases { - z, err := FromDecimal(tc.input) - if tc.isError { + for _, tt := range tests { + z, err := FromDecimal(tt.input) + if tt.isError { if err == nil { - t.Errorf("FromDecimal(%s) expected error, but got nil", tc.input) + t.Errorf("FromDecimal(%s) expected error, but got nil", tt.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()) + t.Errorf("FromDecimal(%s) unexpected error: %v", tt.input, err) + } else if z.Sign() != tt.expected { + t.Errorf("FromDecimal(%s) sign is incorrect. Expected: %d, Actual: %d", tt.input, tt.expected, z.Sign()) } } } } func TestMustFromDecimal(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("MustFromDecimal(\"invalid\") expected panic, but got nil") + tests := []struct { + input string + expected int + shouldPanic bool + }{ + {"0", 0, false}, + {"1", 1, false}, + {"-1", -1, false}, + {"123", 1, false}, + {"invalid", 0, true}, + } + + for _, tt := range tests { + if tt.shouldPanic { + defer func() { + if r := recover(); r == nil { + t.Errorf("MustFromDecimal(%q) expected panic, but got nil", tt.input) + } + }() } - }() - z := MustFromDecimal("123") - if z.Sign() != 1 { - t.Errorf("MustFromDecimal(\"123\") sign is incorrect. Expected: %d, Actual: %d", 1, z.Sign()) + z := MustFromDecimal(tt.input) + if !tt.shouldPanic && z.Sign() != tt.expected { + t.Errorf("MustFromDecimal(%q) sign is incorrect. Expected: %d, Actual: %d", tt.input, tt.expected, z.Sign()) + } } - - MustFromDecimal("invalid") } func TestSetUint64(t *testing.T) { - testCases := []uint64{ + tests := []uint64{ 0, 1, 18446744073709551615, // max uint64 } - for _, tc := range testCases { - z := New().SetUint64(tc) + for _, tt := range tests { + z := New().SetUint64(tt) if z.Sign() < 0 { - t.Errorf("SetUint64(%d) result is negative", tc) + t.Errorf("SetUint64(%d) result is negative", tt) } - if tc == 0 && z.Sign() != 0 { + if tt == 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) + if tt > 0 && z.Sign() != 1 { + t.Errorf("SetUint64(%d) result is not positive", tt) } } } @@ -116,10 +141,10 @@ func TestFromUint256(t *testing.T) { {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) + for _, tt := range tests { + z := New().FromUint256(tt.input) + if z.Sign() != tt.expected { + t.Errorf("FromUint256(%v) = %d, want %d", tt.input, z.Sign(), tt.expected) } } } @@ -141,11 +166,63 @@ func TestSign(t *testing.T) { {"-1", -1}, } - for _, tc := range tests { - z := MustFromDecimal(tc.x) + for _, tt := range tests { + z := MustFromDecimal(tt.x) got := z.Sign() - if got != tc.want { - t.Errorf("Sign(%s) = %d, want %d", tc.x, got, tc.want) + if got != tt.want { + t.Errorf("Sign(%s) = %d, want %d", tt.x, got, tt.want) + } + } +} + +func TestSetInt64(t *testing.T) { + tests := []struct { + v int64 + expect int + }{ + {0, 0}, + {1, 1}, + {-1, -1}, + {9223372036854775807, 1}, // overflow (max int64) + {-9223372036854775808, -1}, // underflow (min int64) + } + + for _, tt := range tests { + z := New().SetInt64(tt.v) + if z.Sign() != tt.expect { + t.Errorf("SetInt64(%d) = %d, want %d", tt.v, z.Sign(), tt.expect) + } + } +} + +func TestSetAndToString(t *testing.T) { + tests := []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 _, tt := range tests { + z, err := New().SetString(tt.input) + if tt.isError { + if err == nil { + t.Errorf("SetString(%s) expected error, but got nil", tt.input) + } + } else { + if err != nil { + t.Errorf("SetString(%s) unexpected error: %v", tt.input, err) + } else if z.Sign() != tt.expected { + t.Errorf("SetString(%s) sign is incorrect. Expected: %d, Actual: %d", tt.input, tt.expected, z.Sign()) + } else if z.ToString() != tt.input { + t.Errorf("SetString(%s) string representation is incorrect. Expected: %s, Actual: %s", tt.input, tt.input, z.ToString()) + } } } } From cf807aee7cf51b8163968267b721cb4f13a2230f Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 26 Sep 2024 16:39:12 +0900 Subject: [PATCH 04/11] finishing arithmetic --- examples/gno.land/p/demo/int256/absolute.gnoA | 18 -- .../gno.land/p/demo/int256/absolute_test.gnoA | 105 ------- .../gno.land/p/demo/int256/arithmetic.gno | 115 ++++--- .../p/demo/int256/arithmetic_test.gno | 282 +++++++----------- .../gno.land/p/demo/int256/bitwise_test.gno | 18 +- examples/gno.land/p/demo/int256/int256.gno | 3 +- .../gno.land/p/demo/int256/int256_test.gno | 6 +- 7 files changed, 176 insertions(+), 371 deletions(-) delete mode 100644 examples/gno.land/p/demo/int256/absolute.gnoA delete mode 100644 examples/gno.land/p/demo/int256/absolute_test.gnoA diff --git a/examples/gno.land/p/demo/int256/absolute.gnoA b/examples/gno.land/p/demo/int256/absolute.gnoA deleted file mode 100644 index 989d0d53029..00000000000 --- a/examples/gno.land/p/demo/int256/absolute.gnoA +++ /dev/null @@ -1,18 +0,0 @@ -package int256 - -import "gno.land/p/demo/uint256" - -// Abs returns |z| -// func (z *Int) Abs() *uint256.Uint { -// return z.abs.Clone() -// } - -// // AbsGt returns true if |z| > x, where x is a uint256 -// func (z *Int) AbsGt(x *uint256.Uint) bool { -// return z.abs.Gt(x) -// } - -// // AbsLt returns true if |z| < x, where x is a uint256 -// func (z *Int) AbsLt(x *uint256.Uint) bool { -// return z.abs.Lt(x) -// } diff --git a/examples/gno.land/p/demo/int256/absolute_test.gnoA b/examples/gno.land/p/demo/int256/absolute_test.gnoA deleted file mode 100644 index 5c5d3ae2908..00000000000 --- a/examples/gno.land/p/demo/int256/absolute_test.gnoA +++ /dev/null @@ -1,105 +0,0 @@ -package int256 - -import ( - "testing" - - "gno.land/p/demo/uint256" -) - -func TestAbs(t *testing.T) { - tests := []struct { - x, want string - }{ - {"0", "0"}, - {"1", "1"}, - {"-1", "1"}, - {"-2", "2"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - } - - for _, tc := range tests { - x, err := FromDecimal(tc.x) - if err != nil { - t.Error(err) - continue - } - - got := x.Abs() - - if got.ToString() != tc.want { - t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) - } - } -} - -// func TestAbsGt(t *testing.T) { -// tests := []struct { -// x, y, want string -// }{ -// {"0", "0", "false"}, -// {"1", "0", "true"}, -// {"-1", "0", "true"}, -// {"-1", "1", "false"}, -// {"-2", "1", "true"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "true"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "true"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, -// } - -// 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 -// } - -// got := x.AbsGt(y) - -// if got != (tc.want == "true") { -// t.Errorf("AbsGt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) -// } -// } -// } - -// func TestAbsLt(t *testing.T) { -// tests := []struct { -// x, y, want string -// }{ -// {"0", "0", "false"}, -// {"1", "0", "false"}, -// {"-1", "0", "false"}, -// {"-1", "1", "false"}, -// {"-2", "1", "false"}, -// {"-5", "10", "true"}, -// {"31330", "31337", "true"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "false"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "false"}, -// {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "false"}, -// } - -// 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 -// } - -// got := x.AbsLt(y) - -// if got != (tc.want == "true") { -// t.Errorf("AbsLt(%s, %s) = %v, want %v", tc.x, tc.y, got, tc.want) -// } -// } -// } diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index 3f8c709dc4d..97607f6c8ed 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -31,6 +31,14 @@ func (z *Int) Mul(x, y *Int) *Int { return z } +func (z *Int) Abs() *uint256.Uint { + var absValue uint256.Uint + if z.Sign() >= 0 { + return absValue.Set(&z.value) + } + return absValue.Sub(uint0, &z.value) +} + /* +--------------------------------------------------------------------------+ // |Division and modulus operations | // +--------------------------------------------------------------------------+ @@ -120,16 +128,16 @@ func (z *Int) Div(x, y *Int) *Int { } // Step 2, 3: Calculate the absolute values of x and y - xAbs, xSign := abs(x) - yAbs, ySign := abs(y) + xAbs, xSign := x.Abs(), x.Sign() + yAbs, ySign := y.Abs(), y.Sign() // perform unsigned division on the absolute values - z.value.Div(&xAbs, &yAbs) + z.value.Div(xAbs, yAbs) // Step 5: Adjust the sign of the result // if x and y have different signs, the result must be negative if xSign != ySign { - z.value.Not(&z.value).Add(&z.value, uint1) + z.value.Neg(&z.value) } return z @@ -190,11 +198,8 @@ func (z *Int) Quo(x, y *Int) *Int { } // Step 2, 3: Calculate the absolute values of x and y - var xAbs, yAbs, q, r uint256.Uint - var xSign, ySign int - - xAbs, xSign = abs(x) - yAbs, ySign = abs(y) + xAbs, xSign := x.Abs(), x.Sign() + yAbs, ySign := y.Abs(), y.Sign() // Step 4: Perform unsigned division and get the remainder // @@ -205,7 +210,8 @@ func (z *Int) Quo(x, y *Int) *Int { // crucial for correct truncation towards zero in subsequent steps. // By using this method here, we can easily adjust the quotient in _Step 5_ // to achieve truncated division semantics. - q.DivMod(&xAbs, &yAbs, &r) + var q, r uint256.Uint + q.DivMod(xAbs, yAbs, &r) // Step 5: Adjust the quotient for truncation towards zero. // @@ -217,7 +223,7 @@ func (z *Int) Quo(x, y *Int) *Int { // Step 6: Adjust the sign of the result if xSign != ySign { - q.Not(&q).Add(&q, uint1) + q.Neg(&q) } z.value.Set(&q) @@ -272,18 +278,16 @@ func (z *Int) Rem(x, y *Int) *Int { } // Step 2, 3 - var xAbs, yAbs, q, r uint256.Uint - var xSign int - - xAbs, xSign = abs(x) - yAbs, _ = abs(y) + xAbs, xSign := x.Abs(), x.Sign() + yAbs := y.Abs() // Step 4: Perform unsigned division and get the remainder - q.DivMod(&xAbs, &yAbs, &r) + var q, r uint256.Uint + q.DivMod(xAbs, yAbs, &r) // Step 5: Adjust the sign of the remainder - if xSign < 0 && !r.IsZero() { - r.Not(&r).Add(&r, uint1) + if xSign < 0 { + r.Neg(&r) } z.value.Set(&r) @@ -313,8 +317,12 @@ func (z *Int) DivE(x, y *Int) *Int { r := new(Int).Rem(x, y) // Adjust the quotient if necessary - if r.Sign() >= 0 { return z } - if y.Sign() > 0 { return z.Sub(z, int1) } + if r.Sign() >= 0 { + return z + } + if y.Sign() > 0 { + return z.Sub(z, int1) + } return z.Add(z, int1) } @@ -364,54 +372,35 @@ func (z *Int) ModE(x, y *Int) *Int { z.Rem(x, y) // Adjust the remainder if necessary - if z.Sign() >= 0 { return z } - if y.Sign() > 0 { return z.Add(z, y) } + if z.Sign() >= 0 { + return z + } + if y.Sign() > 0 { + return z.Add(z, y) + } return z.Sub(z, y) } -func abs(x *Int) (uint256.Uint, int) { - sign := x.Sign() - - if sign >= 0 { - return x.value, 1 +// 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.Sign() >= 0 { + z.Add(x, &y.value) + } else { + z.Sub(x, y.Abs()) } - - var absVal uint256.Uint - absVal.Set(&x.value).Not(&absVal).Add(&absVal, uint1) - return absVal, -1 } -// not implemented yet - -// 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 -// } - // 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) -// } -// } +func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { + var overflow bool + if y.Sign() >= 0 { + _, overflow = z.AddOverflow(x, &y.value) + } else { + var absY uint256.Uint + absY.Sub(uint0, &y.value) // absY = -y.value + _, overflow = z.SubOverflow(x, &absY) + } -// 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 -// } + return overflow +} diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index 244bb22de32..0dde69f9594 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -98,88 +98,88 @@ func TestAddUint256(t *testing.T) { } } -// 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 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 { @@ -306,50 +306,6 @@ func TestMul(t *testing.T) { } } -// 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 @@ -365,7 +321,8 @@ func TestDiv(t *testing.T) { {"7", "3", "2"}, {"-7", "3", "-2"}, // the maximum value of a positive number in int256 is less than the maximum value of a uint256 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Max int256 - 1) / 2 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Max int256 - 1) / 2 + {"-57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "-28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Min int256 + 1) / 2 } for _, tt := range tests { @@ -391,51 +348,6 @@ func TestDiv(t *testing.T) { }) } -// 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 @@ -670,3 +582,29 @@ func TestLargeNumbers(t *testing.T) { t.Errorf("ModE with large numbers: got %v, want %v", gotR, expectedR) } } + +func TestAbs(t *testing.T) { + tests := []struct { + x, want string + }{ + {"0", "0"}, + {"1", "1"}, + {"-1", "1"}, + {"-2", "2"}, + {"-100000000000", "100000000000"}, + } + + for _, tc := range tests { + x, err := FromDecimal(tc.x) + if err != nil { + t.Error(err) + continue + } + + got := x.Abs() + + if got.ToString() != tc.want { + t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) + } + } +} diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gno index 98de2895585..6e3d4a92a9b 100644 --- a/examples/gno.land/p/demo/int256/bitwise_test.gno +++ b/examples/gno.land/p/demo/int256/bitwise_test.gno @@ -30,7 +30,7 @@ func TestBitwise_Or(t *testing.T) { tests := []struct { x, y, want string }{ - {"5", "1", "5"}, // 0101 | 0001 = 0101 + {"5", "1", "5"}, // 0101 | 0001 = 0101 {"-1", "1", "-1"}, // 1111 | 0001 = 1111 {"-5", "3", "-5"}, // 1111...1011 | 0000...0011 = 1111...1011 } @@ -72,7 +72,7 @@ func TestBitwise_Xor(t *testing.T) { tests := []struct { x, y, want string }{ - {"5", "1", "4"}, // 0101 ^ 0001 = 0100 + {"5", "1", "4"}, // 0101 ^ 0001 = 0100 {"-1", "1", "-2"}, // 1111...1111 ^ 0000...0001 = 1111...1110 {"-5", "3", "-8"}, // 1111...1011 ^ 0000...0011 = 1111...1000 } @@ -92,11 +92,11 @@ func TestBitwise_Xor(t *testing.T) { func TestBitwise_Rsh(t *testing.T) { tests := []struct { - x string - n uint + x string + n uint want string }{ - {"5", 1, "2"}, // 0101 >> 1 = 0010 + {"5", 1, "2"}, // 0101 >> 1 = 0010 {"42", 3, "5"}, // 00101010 >> 3 = 00000101 } @@ -114,11 +114,11 @@ func TestBitwise_Rsh(t *testing.T) { func TestBitwise_Lsh(t *testing.T) { tests := []struct { - x string - n uint - want string + x string + n uint + want string }{ - {"5", 2, "20"}, // 0101 << 2 = 10100 + {"5", 2, "20"}, // 0101 << 2 = 10100 {"42", 5, "1344"}, // 00101010 << 5 = 10101000000 } diff --git a/examples/gno.land/p/demo/int256/int256.gno b/examples/gno.land/p/demo/int256/int256.gno index 008ff5233f1..bbb8bc30611 100644 --- a/examples/gno.land/p/demo/int256/int256.gno +++ b/examples/gno.land/p/demo/int256/int256.gno @@ -7,7 +7,8 @@ import ( ) var ( - int1 = NewInt(1) + int1 = NewInt(1) + uint0 = uint256.NewUint(0) uint1 = uint256.NewUint(1) ) diff --git a/examples/gno.land/p/demo/int256/int256_test.gno b/examples/gno.land/p/demo/int256/int256_test.gno index 48a4c3c7ea9..c027f1b7a5b 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -83,8 +83,8 @@ func TestFromDecimal(t *testing.T) { func TestMustFromDecimal(t *testing.T) { tests := []struct { - input string - expected int + input string + expected int shouldPanic bool }{ {"0", 0, false}, @@ -183,7 +183,7 @@ func TestSetInt64(t *testing.T) { {0, 0}, {1, 1}, {-1, -1}, - {9223372036854775807, 1}, // overflow (max int64) + {9223372036854775807, 1}, // overflow (max int64) {-9223372036854775808, -1}, // underflow (min int64) } From 4c18879c2e6b746722a7c3e3db3dd7c36da48a8a Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Thu, 26 Sep 2024 18:01:36 +0900 Subject: [PATCH 05/11] conversion --- examples/gno.land/p/demo/int256/LICENSE | 21 - examples/gno.land/p/demo/int256/README.md | 6 - examples/gno.land/p/demo/int256/cmp.gno | 5 +- .../gno.land/p/demo/int256/conversion.gno | 185 ++++---- .../p/demo/int256/conversion_test.gno | 445 +++++++++--------- examples/gno.land/p/demo/int256/doc.gno | 23 +- examples/gno.land/p/demo/int256/int256.gno | 48 +- .../gno.land/p/demo/int256/int256_test.gno | 33 +- 8 files changed, 344 insertions(+), 422 deletions(-) delete mode 100644 examples/gno.land/p/demo/int256/LICENSE delete mode 100644 examples/gno.land/p/demo/int256/README.md diff --git a/examples/gno.land/p/demo/int256/LICENSE b/examples/gno.land/p/demo/int256/LICENSE deleted file mode 100644 index fc7e78a4875..00000000000 --- a/examples/gno.land/p/demo/int256/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Trịnh Đức Bảo Linh(Kevin) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/examples/gno.land/p/demo/int256/README.md b/examples/gno.land/p/demo/int256/README.md deleted file mode 100644 index be467471199..00000000000 --- a/examples/gno.land/p/demo/int256/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Fixed size signed 256-bit math library - -1. This is a library specialized at replacing the big.Int library for math based on signed 256-bit types. -2. It uses [uint256](https://github.com/gnolang/gno/tree/master/examples/gno.land/p/demo/uint256) as the underlying type. - -ported from [mempooler/int256](https://github.com/mempooler/int256) diff --git a/examples/gno.land/p/demo/int256/cmp.gno b/examples/gno.land/p/demo/int256/cmp.gno index ee4e035638e..c91a25568e9 100644 --- a/examples/gno.land/p/demo/int256/cmp.gno +++ b/examples/gno.land/p/demo/int256/cmp.gno @@ -14,8 +14,7 @@ func (z *Int) Neq(x *Int) bool { // - 0 if z == x // - -1 if z < x func (z *Int) Cmp(x *Int) int { - zSign := z.Sign() - xSign := x.Sign() + zSign, xSign := z.Sign(), x.Sign() if zSign == xSign { return z.value.Cmp(&x.value) @@ -30,7 +29,7 @@ func (z *Int) Cmp(x *Int) int { // IsZero returns true if z == 0 func (z *Int) IsZero() bool { - return z.Sign() == 0 + return z.value.IsZero() } // IsNeg returns true if z < 0 diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gno index d91e239abbb..7da74ea2c2e 100644 --- a/examples/gno.land/p/demo/int256/conversion.gno +++ b/examples/gno.land/p/demo/int256/conversion.gno @@ -1,121 +1,108 @@ package int256 -import "gno.land/p/demo/uint256" +import ( + "math" -// // SetInt64 sets z to x and returns z. -// func (z *Int) SetInt64(x int64) *Int { -// z.initiateAbs() + "gno.land/p/demo/uint256" +) -// neg := false -// if x < 0 { -// neg = true -// x = -x -// } -// if z.abs == nil { -// panic("abs is nil") -// } -// z.abs = z.abs.SetUint64(uint64(x)) -// z.neg = neg -// return z -// } - -// // SetUint64 sets z to x and returns z. -// func (z *Int) SetUint64(x uint64) *Int { -// z.initiateAbs() - -// if z.abs == nil { -// panic("abs is nil") -// } -// z.abs = z.abs.SetUint64(x) -// z.neg = false -// return z -// } - -// // Uint64 returns the lower 64-bits of z -// func (z *Int) Uint64() uint64 { -// return z.abs.Uint64() -// } - -// // Int64 returns the lower 64-bits of z -// func (z *Int) Int64() int64 { -// _abs := z.abs.Clone() - -// if z.neg { -// return -int64(_abs.Uint64()) -// } -// return int64(_abs.Uint64()) -// } +// 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)).Neg(&z.value) + } + return z +} -// // Neg sets z to -x and returns z.) -// func (z *Int) Neg(x *Int) *Int { -// z.abs.Set(x.abs) -// if z.abs.IsZero() { -// z.neg = false -// } else { -// z.neg = !x.neg -// } -// return z -// } +// SetUint64 sets the Int to the value of the provided uint64. +func (z *Int) SetUint64(v uint64) *Int { + z.value.SetUint64(v) + return z +} -// // Set sets z to x and returns z. -// func (z *Int) Set(x *Int) *Int { -// z.abs.Set(x.abs) -// z.neg = x.neg -// return z -// } +// Uint64 returns the lower 64-bits of z +func (z *Int) Uint64() uint64 { + if z.Sign() < 0 { + panic("cannot convert negative int256 to uint64") + } + if z.value.Gt(uint256.NewUint(0).SetUint64(math.MaxUint64)) { + panic("overflow: int256 does not fit in uint64 type") + } + return z.value.Uint64() +} -// // SetFromUint256 converts a uint256.Uint to Int and sets the value to z. -// func (z *Int) SetUint256(x *uint256.Uint) *Int { -// z.abs.Set(x) -// z.neg = false -// return z -// } +// Int64 returns the lower 64-bits of z +func (z *Int) Int64() int64 { + if z.Sign() >= 0 { + if z.value.BitLen() > 64 { + panic("overflow: int256 does not fit in int64 type") + } + return int64(z.value.Uint64()) + } else { + var temp uint256.Uint + temp.Sub(uint256.NewUint(0), &z.value) // temp = -z.value + if temp.BitLen() > 64 { + panic("overflow: int256 does not fit in int64 type") + } + return -int64(temp.Uint64()) + } +} -// // OBS, differs from original mempooler int256 -// // ToString returns the decimal representation of z. -// func (z *Int) ToString() string { -// if z == nil { -// panic("int256: nil pointer to ToString()") -// } +// Neg sets z to -x and returns z.) +func (z *Int) Neg(x *Int) *Int { + if x.IsZero() { + z.value.Clear() + } else { + z.value.Neg(&x.value) + } + return z +} -// t := z.abs.Dec() -// if z.neg { -// return "-" + t -// } +// Set sets z to x and returns z. +func (z *Int) Set(x *Int) *Int { + z.value.Set(&x.value) + return z +} -// return t -// } +// SetFromUint256 converts a uint256.Uint to Int and sets the value to z. +func (z *Int) SetUint256(x *uint256.Uint) *Int { + z.value.Set(x) + return z +} // ToString returns a string representation of z in base 10. // The string is prefixed with a minus sign if z is negative. -// -// TODO: fix func (z *Int) ToString() string { - // Check if the number is zero if z.value.IsZero() { return "0" } - - // Check if the number is negative - isNegative := z.Sign() < 0 - - // Create a copy of z.value to avoid modifying the original - var absValue uint256.Uint - if isNegative { - // For negative numbers, we need to compute the absolute value - // by performing two's complement negation - absValue.Sub(uint256.Zero(), &z.value) + sign := z.Sign() + var temp uint256.Uint + if sign >= 0 { + temp.Set(&z.value) } else { - absValue.Set(&z.value) + // temp = -z.value + temp.Sub(uint256.NewUint(0), &z.value) } - - // Convert the absolute value to a decimal string - str := absValue.ToString() - - // Add a minus sign for negative numbers - if isNegative { - return "-" + str + s := temp.Dec() + if sign < 0 { + return "-" + s } + return s +} - return str +// 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/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gno index 1b5617928e6..5b8c5fe456a 100644 --- a/examples/gno.land/p/demo/int256/conversion_test.gno +++ b/examples/gno.land/p/demo/int256/conversion_test.gno @@ -1,228 +1,221 @@ package int256 -// func TestSetInt64(t *testing.T) { -// tests := []struct { -// x int64 -// want string -// }{ -// {0, "0"}, -// {1, "1"}, -// {-1, "-1"}, -// {9223372036854775807, "9223372036854775807"}, -// {-9223372036854775808, "-9223372036854775808"}, -// } - -// for _, tc := range tests { -// var z Int -// z.SetInt64(tc.x) - -// got := z.ToString() -// if got != tc.want { -// t.Errorf("SetInt64(%d) = %s, want %s", tc.x, got, tc.want) -// } -// } -// } - -// func TestSetUint64(t *testing.T) { -// tests := []struct { -// x uint64 -// want string -// }{ -// {0, "0"}, -// {1, "1"}, -// } - -// for _, tc := range tests { -// var z Int -// z.SetUint64(tc.x) - -// got := z.ToString() -// if got != tc.want { -// t.Errorf("SetUint64(%d) = %s, want %s", tc.x, got, tc.want) -// } -// } -// } - -// func TestUint64(t *testing.T) { -// tests := []struct { -// x string -// want uint64 -// }{ -// {"0", 0}, -// {"1", 1}, -// {"9223372036854775807", 9223372036854775807}, -// {"9223372036854775808", 9223372036854775808}, -// {"18446744073709551615", 18446744073709551615}, -// {"18446744073709551616", 0}, -// {"18446744073709551617", 1}, -// {"-1", 1}, -// {"-18446744073709551615", 18446744073709551615}, -// {"-18446744073709551616", 0}, -// {"-18446744073709551617", 1}, -// } - -// for _, tc := range tests { -// z := MustFromDecimal(tc.x) - -// got := z.Uint64() -// if got != tc.want { -// t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) -// } -// } -// } - -// func TestInt64(t *testing.T) { -// tests := []struct { -// x string -// want int64 -// }{ -// {"0", 0}, -// {"1", 1}, -// {"9223372036854775807", 9223372036854775807}, -// {"18446744073709551616", 0}, -// {"18446744073709551617", 1}, -// {"-1", -1}, -// {"-9223372036854775808", -9223372036854775808}, -// } - -// for _, tc := range tests { -// z := MustFromDecimal(tc.x) - -// got := z.Int64() -// if got != tc.want { -// t.Errorf("Uint64(%s) = %d, want %d", tc.x, got, tc.want) -// } -// } -// } - -// func TestNeg(t *testing.T) { -// tests := []struct { -// x string -// want string -// }{ -// {"0", "0"}, -// {"1", "-1"}, -// {"-1", "1"}, -// {"9223372036854775807", "-9223372036854775807"}, -// {"-18446744073709551615", "18446744073709551615"}, -// } - -// for _, tc := range tests { -// z := MustFromDecimal(tc.x) -// z.Neg(z) - -// got := z.ToString() -// if got != tc.want { -// t.Errorf("Neg(%s) = %s, want %s", tc.x, got, tc.want) -// } -// } -// } - -// func TestSet(t *testing.T) { -// tests := []struct { -// x string -// want string -// }{ -// {"0", "0"}, -// {"1", "1"}, -// {"-1", "-1"}, -// {"9223372036854775807", "9223372036854775807"}, -// {"-18446744073709551615", "-18446744073709551615"}, -// } - -// for _, tc := range tests { -// z := MustFromDecimal(tc.x) -// z.Set(z) - -// got := z.ToString() -// if got != tc.want { -// t.Errorf("Set(%s) = %s, want %s", tc.x, got, tc.want) -// } -// } -// } - -// func TestSetUint256(t *testing.T) { -// tests := []struct { -// x string -// want string -// }{ -// {"0", "0"}, -// {"1", "1"}, -// {"9223372036854775807", "9223372036854775807"}, -// {"18446744073709551615", "18446744073709551615"}, -// } - -// for _, tc := range tests { -// got := New() - -// z := uint256.MustFromDecimal(tc.x) -// got.SetUint256(z) - -// if got.ToString() != tc.want { -// t.Errorf("SetUint256(%s) = %s, want %s", tc.x, got.ToString(), tc.want) -// } -// } -// } - -// func TestToString(t *testing.T) { -// tests := []struct { -// name string -// setup func() *Int -// expected string -// }{ -// { -// name: "Zero from subtraction", -// setup: func() *Int { -// minusThree := MustFromDecimal("-3") -// three := MustFromDecimal("3") -// return Zero().Add(minusThree, three) -// }, -// expected: "0", -// }, -// { -// name: "Zero from right shift", -// setup: func() *Int { -// return Zero().Rsh(One(), 1234) -// }, -// expected: "0", -// }, -// { -// name: "Positive number", -// setup: func() *Int { -// return MustFromDecimal("42") -// }, -// expected: "42", -// }, -// { -// name: "Negative number", -// setup: func() *Int { -// return MustFromDecimal("-42") -// }, -// expected: "-42", -// }, -// { -// name: "Large positive number", -// setup: func() *Int { -// return MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") -// }, -// expected: "115792089237316195423570985008687907853269984665640564039457584007913129639935", -// }, -// { -// name: "Large negative number", -// setup: func() *Int { -// return MustFromDecimal("-115792089237316195423570985008687907853269984665640564039457584007913129639935") -// }, -// expected: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", -// }, -// } - -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// z := tt.setup() -// result := z.ToString() -// if result != tt.expected { -// t.Errorf("ToString() = %s, want %s", result, tt.expected) -// } -// }) -// } -// } +import ( + "testing" + + "gno.land/p/demo/uint256" +) + +func TestSetInt64(t *testing.T) { + tests := []struct { + v int64 + expect int + }{ + {0, 0}, + {1, 1}, + {-1, -1}, + {9223372036854775807, 1}, // overflow (max int64) + {-9223372036854775808, -1}, // underflow (min int64) + } + + for _, tt := range tests { + z := New().SetInt64(tt.v) + if z.Sign() != tt.expect { + t.Errorf("SetInt64(%d) = %d, want %d", tt.v, z.Sign(), tt.expect) + } + } +} + +func TestUint64(t *testing.T) { + tests := []struct { + x string + want uint64 + }{ + {"0", 0}, + {"1", 1}, + {"9223372036854775807", 9223372036854775807}, + {"9223372036854775808", 9223372036854775808}, + {"18446744073709551615", 18446744073709551615}, + } + + for _, tt := range tests { + z := MustFromDecimal(tt.x) + + got := z.Uint64() + if got != tt.want { + t.Errorf("Uint64(%s) = %d, want %d", tt.x, got, tt.want) + } + } +} + +func TestUint64_Panic(t *testing.T) { + tests := []struct { + x string + }{ + {"-1"}, + {"18446744073709551616"}, + {"18446744073709551617"}, + } + + for _, tt := range tests { + defer func() { + if r := recover(); r == nil { + t.Errorf("Uint64(%s) did not panic", tt.x) + } + }() + + z := MustFromDecimal(tt.x) + z.Uint64() + } +} + +func TestInt64(t *testing.T) { + tests := []struct { + x string + want int64 + }{ + {"0", 0}, + {"1", 1}, + {"9223372036854775807", 9223372036854775807}, + {"-1", -1}, + {"-9223372036854775808", -9223372036854775808}, + } + + for _, tt := range tests { + z := MustFromDecimal(tt.x) + + got := z.Int64() + if got != tt.want { + t.Errorf("Uint64(%s) = %d, want %d", tt.x, got, tt.want) + } + } +} + +func TestInt64_Panic(t *testing.T) { + tests := []struct { + x string + }{ + {"18446744073709551616"}, + {"18446744073709551617"}, + } + + for _, tt := range tests { + defer func() { + if r := recover(); r == nil { + t.Errorf("Int64(%s) did not panic", tt.x) + } + }() + + z := MustFromDecimal(tt.x) + z.Int64() + } +} + +func TestNeg(t *testing.T) { + tests := []struct { + x string + want string + }{ + {"0", "0"}, + {"1", "-1"}, + {"-1", "1"}, + {"9223372036854775807", "-9223372036854775807"}, + {"-18446744073709551615", "18446744073709551615"}, + } + + for _, tt := range tests { + z := MustFromDecimal(tt.x) + z.Neg(z) + + got := z.ToString() + if got != tt.want { + t.Errorf("Neg(%s) = %s, want %s", tt.x, got, tt.want) + } + } +} + +func TestSet(t *testing.T) { + tests := []struct { + x string + want string + }{ + {"0", "0"}, + {"1", "1"}, + {"-1", "-1"}, + {"9223372036854775807", "9223372036854775807"}, + {"-18446744073709551615", "-18446744073709551615"}, + } + + for _, tt := range tests { + z := MustFromDecimal(tt.x) + z.Set(z) + + got := z.ToString() + if got != tt.want { + t.Errorf("Set(%s) = %s, want %s", tt.x, got, tt.want) + } + } +} + +func TestSetUint256(t *testing.T) { + tests := []struct { + x string + want string + }{ + {"0", "0"}, + {"1", "1"}, + {"9223372036854775807", "9223372036854775807"}, + {"18446744073709551615", "18446744073709551615"}, + } + + for _, tt := range tests { + got := New() + + z := uint256.MustFromDecimal(tt.x) + got.SetUint256(z) + + if got.ToString() != tt.want { + t.Errorf("SetUint256(%s) = %s, want %s", tt.x, got.ToString(), tt.want) + } + } +} + +func TestToString(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"0", "0"}, + {"1", "1"}, + {"-1", "-1"}, + {"123456789", "123456789"}, + {"-123456789", "-123456789"}, + {"18446744073709551615", "18446744073709551615"}, // max uint64 + {"-18446744073709551615", "-18446744073709551615"}, + {"340282366920938463463374607431768211455", "340282366920938463463374607431768211455"}, // max uint128 + {"-340282366920938463463374607431768211455", "-340282366920938463463374607431768211455"}, + {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, + } + + for _, tt := range tests { + x, err := FromDecimal(tt.input) + if err != nil { + t.Errorf("Failed to parse input (%s): %v", tt.input, err) + continue + } + + output := x.ToString() + + if output != tt.expected { + t.Errorf("String(%s) = %s, want %s", tt.input, output, tt.expected) + } + } +} + +func TestNilToZero(t *testing.T) { + z := New().NilToZero() + if z.Sign() != 0 { + t.Errorf("NilToZero() = %d, want %d", z.Sign(), 0) + } +} diff --git a/examples/gno.land/p/demo/int256/doc.gno b/examples/gno.land/p/demo/int256/doc.gno index 70e1aabc8a4..4481af54069 100644 --- a/examples/gno.land/p/demo/int256/doc.gno +++ b/examples/gno.land/p/demo/int256/doc.gno @@ -1,2 +1,23 @@ -// This package provides a 256-bit signed integer type, Int and associated functions. +// The int256 package provides a 256-bit signed interger type for gno, +// supporting arithmetic operations and bitwise manipulation. +// +// It designed for applications that require high-precision arithmetic +// beyond the standard 64-bit range. +// +// ## Features +// +// - 256-bit Signed Integers: Support for large integer ranging from -2^255 tp 2^255-1. +// - Two's Complement Representation: Efficient storage and computation using two's complement. +// - Arithmetic Operations: Add, Sub, Mul, Div, Mod, Inc, Dec, etc. +// - Bitwise Operations: And, Or, Xor, Not, etc. +// - Comparison Operations: Cmp, Eq, Lt, Gt, etc. +// - Conversion Functions: Int to Uint, Uint to Int, etc. +// - String Parsing and Formatting: Convert to and from decimal string representation. +// +// ## Notes +// +// - Some methods may panic when encountering invalid inputs or overflows. +// - The `int256.Int` type can interact with `uint256.Uint` from the `p/demo/uint256` package. +// - Unlike `math/big.Int`, the `int256.Int` type has fixed size (256-bit) and does not support +// arbitrary precision arithmetic. package int256 diff --git a/examples/gno.land/p/demo/int256/int256.gno b/examples/gno.land/p/demo/int256/int256.gno index bbb8bc30611..f4ed981eecf 100644 --- a/examples/gno.land/p/demo/int256/int256.gno +++ b/examples/gno.land/p/demo/int256/int256.gno @@ -23,30 +23,26 @@ func New() *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) + return New().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 &Int{} -} +func Zero() *Int { return &Int{} } // 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 new(Int).SetInt64(1) -} +func One() *Int { return int1 } // Sign determines the sign of the Int. // // It returns -1 for negative numbers, 0 for zero, and +1 for positive numbers. func (z *Int) Sign() int { - if z.value.IsZero() { + if z.IsZero() { return 0 } // Right shift the value by 255 bits to check the sign bit. @@ -65,8 +61,7 @@ func (z *Int) Sign() int { // 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() { + if temp.Rsh(&z.value, 255).IsZero() { return 1 } return -1 @@ -78,7 +73,7 @@ func (z *Int) Sign() int { // 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) + return New().SetString(s) } // MustFromDecimal is similar to FromDecimal but panics if the input string @@ -120,26 +115,6 @@ func (z *Int) SetString(s string) (*Int, error) { return z, 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).Add(&z.value, uint1) - } - return z -} - -// SetUint64 sets the Int to the value of the provided uint64. -func (z *Int) SetUint64(v uint64) *Int { - z.value.SetUint64(v) - return z -} - // FromUint256 sets the Int to the value of the provided Uint256. // // This method allows for conversion from unsigned 256-bit integers @@ -148,14 +123,3 @@ func (z *Int) FromUint256(v *uint256.Uint) *Int { z.value.Set(v) return z } - -// 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 c027f1b7a5b..76d1d69ef34 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -149,21 +149,18 @@ func TestFromUint256(t *testing.T) { } } -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 { x string want int }{ {"0", 0}, + {"-0", 0}, + {"+0", 0}, {"1", 1}, {"-1", -1}, + {"9223372036854775807", 1}, + {"-9223372036854775808", -1}, } for _, tt := range tests { @@ -175,23 +172,11 @@ func TestSign(t *testing.T) { } } -func TestSetInt64(t *testing.T) { - tests := []struct { - v int64 - expect int - }{ - {0, 0}, - {1, 1}, - {-1, -1}, - {9223372036854775807, 1}, // overflow (max int64) - {-9223372036854775808, -1}, // underflow (min int64) - } - - for _, tt := range tests { - z := New().SetInt64(tt.v) - if z.Sign() != tt.expect { - t.Errorf("SetInt64(%d) = %d, want %d", tt.v, z.Sign(), tt.expect) - } +func BenchmarkSign(b *testing.B) { + z := New() + for i := 0; i < b.N; i++ { + z.SetUint64(uint64(i)) + z.Sign() } } From 2ced1989a92a05df4f519a518eb48b8e5b6cb5c5 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Fri, 27 Sep 2024 12:22:42 +0900 Subject: [PATCH 06/11] fix --- .../gno.land/p/demo/int256/arithmetic.gno | 103 ++++++++---------- .../p/demo/int256/arithmetic_test.gno | 5 +- examples/gno.land/p/demo/int256/bitwise.gno | 23 ++++ examples/gno.land/p/demo/int256/cmp_test.gno | 2 - examples/gno.land/p/demo/int256/int256.gno | 6 +- .../gno.land/p/demo/int256/int256_test.gno | 10 +- 6 files changed, 82 insertions(+), 67 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index 97607f6c8ed..f605ffac9e1 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -6,31 +6,47 @@ import ( var divisionByZeroError = "division by zero" +// Add adds two int256 values and saves the result in z. func (z *Int) Add(x, y *Int) *Int { z.value.Add(&x.value, &y.value) return z } +// AddUint256 adds int256 and uint256 values and saves the result in z. func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { z.value.Add(&x.value, y) return z } +// Sub subtracts two int256 values and saves the result in z. func (z *Int) Sub(x, y *Int) *Int { z.value.Sub(&x.value, &y.value) return z } +// SubUint256 subtracts uint256 and int256 values and saves the result in z. func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { z.value.Sub(&x.value, y) return z } +// Mul multiplies two int256 values and saves the result in z. +// +// It considers the signs of the operands to determine the sign of the result. func (z *Int) Mul(x, y *Int) *Int { - z.value.Mul(&x.value, &y.value) + xAbs, xSign := x.Abs(), x.Sign() + yAbs, ySign := y.Abs(), y.Sign() + + z.value.Mul(xAbs, yAbs) + + if xSign != ySign { + z.value.Neg(&z.value) + } + return z } +// Abs returns the absolute value of z. func (z *Int) Abs() *uint256.Uint { var absValue uint256.Uint if z.Sign() >= 0 { @@ -131,7 +147,7 @@ func (z *Int) Div(x, y *Int) *Int { xAbs, xSign := x.Abs(), x.Sign() yAbs, ySign := y.Abs(), y.Sign() - // perform unsigned division on the absolute values + // Step 4: Perform unsigned division on the absolute values z.value.Div(xAbs, yAbs) // Step 5: Adjust the sign of the result @@ -143,17 +159,6 @@ func (z *Int) Div(x, y *Int) *Int { return z } -// Quo sets z to the quotient x/y for y != 0 and returns z. -// It implements truncated division (or T-division). -// -// The function performs the following steps: -// 1. Check for division by zero -// 2. Determine the signs of x and y -// 3. Calculate the absolute values of x and y -// 4. Perform unsigned division and get the remainder -// 5. Adjust the quotient for truncation towards zero -// 6. Adjust the sign of the result -// // Example visualization for 8-bit integers (scaled down from 256-bit for simplicity): // // Let x = -7 (11111001 in two's complement) and y = 3 (00000011) @@ -173,24 +178,17 @@ func (z *Int) Div(x, y *Int) *Int { // // Step 4: Unsigned division // -// 7 / 3 = 2 remainder 1 -// q = 2: 00000010 -// r = 1: 00000001 -// -// Step 5: Adjust for truncation -// -// Signs are different and r != 0, so add 1 to q -// q = 3: 00000011 +// 7 / 3 = 2: 00000010 // -// Step 6: Adjust sign (x and y have different signs) +// Step 5: Adjust sign (x and y have different signs) // -// -3: 00000011 -> 11111101 -// NOT: 11111100 -// +1: 11111101 +// -2: 00000010 -> 11111110 +// NOT: 11111101 +// +1: 11111110 // -// Final result: -3 (11111101 in two's complement) +// Final result: -2 (11111110 in two's complement) // -// Note: This implementation ensures correct truncation towards zero for negative dividends. +// Note: This implementation rounds towards zero, as is standard in Go. func (z *Int) Quo(x, y *Int) *Int { // Step 1: Check for division by zero if y.IsZero() { @@ -201,32 +199,15 @@ func (z *Int) Quo(x, y *Int) *Int { xAbs, xSign := x.Abs(), x.Sign() yAbs, ySign := y.Abs(), y.Sign() - // Step 4: Perform unsigned division and get the remainder - // - // q = xAbs / yAbs - // r = xAbs % yAbs - // - // Use Euclidean division to always yields a non-negative remainder, which is - // crucial for correct truncation towards zero in subsequent steps. - // By using this method here, we can easily adjust the quotient in _Step 5_ - // to achieve truncated division semantics. - var q, r uint256.Uint - q.DivMod(xAbs, yAbs, &r) - - // Step 5: Adjust the quotient for truncation towards zero. - // - // If x and y have different signs and there's a non-zero remainder, - // we need to round towards zero by adding 1 to the quotient magnitude. - if (xSign < 0) != (ySign < 0) && !r.IsZero() { - q.Add(&q, uint1) - } + // perform unsigned division on the absolute values + z.value.Div(xAbs, yAbs) - // Step 6: Adjust the sign of the result + // Step 5: Adjust the sign of the result + // if x and y have different signs, the result must be negative if xSign != ySign { - q.Neg(&q) + z.value.Neg(&z.value) } - z.value.Set(&q) return z } @@ -311,20 +292,22 @@ func (z *Int) DivE(x, y *Int) *Int { panic(divisionByZeroError) } - z.Div(x, y) + // Compute the truncated division quotient + z.Quo(x, y) - // Get the remainder using T-division + // Compute the remainder r := new(Int).Rem(x, y) - // Adjust the quotient if necessary - if r.Sign() >= 0 { - return z - } - if y.Sign() > 0 { - return z.Sub(z, int1) + // If the remainder is negative, adjust the quotient + if r.Sign() < 0 { + if y.Sign() > 0 { + z.Sub(z, NewInt(1)) + } else { + z.Add(z, NewInt(1)) + } } - return z.Add(z, int1) + return z } // ModE computes the Euclidean modulus of x by y, setting z to the result and returning z. @@ -383,6 +366,8 @@ func (z *Int) ModE(x, y *Int) *Int { } // Sets z to the sum x + y, where z and x are uint256s and y is an int256. +// +// If the y is positive, it adds y.value to x. otherwise, it subtracts y.Abs() from x. func AddDelta(z, x *uint256.Uint, y *Int) { if y.Sign() >= 0 { z.Add(x, &y.value) @@ -392,6 +377,8 @@ func AddDelta(z, x *uint256.Uint, y *Int) { } // Sets z to the sum x + y, where z and x are uint256s and y is an int256. +// +// This function returns true if the addition overflows, false otherwise. func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { var overflow bool if y.Sign() >= 0 { diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index 0dde69f9594..3b36fb56dcd 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -276,6 +276,8 @@ func TestMul(t *testing.T) { {"5", "-3", "-15"}, {"0", "3", "0"}, {"3", "0", "0"}, + {"-5", "-3", "15"}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, } for _, tc := range tests { @@ -358,7 +360,8 @@ func TestQuo(t *testing.T) { {"10", "-1", "-10"}, {"-10", "1", "-10"}, {"-10", "-1", "10"}, - // {"10", "-3", "-3"}, + {"10", "-3", "-3"}, + {"-10", "3", "-3"}, {"10", "3", "3"}, } diff --git a/examples/gno.land/p/demo/int256/bitwise.gno b/examples/gno.land/p/demo/int256/bitwise.gno index 70f13c172ea..1a1fe2e9720 100644 --- a/examples/gno.land/p/demo/int256/bitwise.gno +++ b/examples/gno.land/p/demo/int256/bitwise.gno @@ -1,30 +1,53 @@ package int256 +// Not sets z to the bitwise NOT of x and returns z. +// +// The bitwise NOT operation flips each bit of the operand. func (z *Int) Not(x *Int) *Int { z.value.Not(&x.value) return z } +// And sets z to the bitwise AND of x and y and returns z. +// +// The bitwise AND operation results in a value that has a bit set +// only if both corresponding bits of the operands are set. func (z *Int) And(x, y *Int) *Int { z.value.And(&x.value, &y.value) return z } +// Or sets z to the bitwise OR of x and y and returns z. +// +// The bitwise OR operation results in a value that has a bit set +// if at least one of the corresponding bits of the operands is set. func (z *Int) Or(x, y *Int) *Int { z.value.Or(&x.value, &y.value) return z } +// Xor sets z to the bitwise XOR of x and y and returns z. +// +// The bitwise XOR operation results in a value that has a bit set +// only if the corresponding bits of the operands are different. func (z *Int) Xor(x, y *Int) *Int { z.value.Xor(&x.value, &y.value) return z } +// Rsh sets z to the result of right-shifting x by n bits and returns z. +// +// Right shift operation moves all bits in the operand to the right by the specified number of positions. +// Bits shifted out on the right are discarded, and zeros are shifted in on the left. func (z *Int) Rsh(x *Int, n uint) *Int { z.value.Rsh(&x.value, n) return z } +// Lsh sets z to the result of left-shifting x by n bits and returns z. +// +// Left shift operation moves all bits in the operand to the left by the specified number of positions. +// Bits shifted out on the left are discarded, and zeros are shifted in on the right. func (z *Int) Lsh(x *Int, n uint) *Int { z.value.Lsh(&x.value, n) return z diff --git a/examples/gno.land/p/demo/int256/cmp_test.gno b/examples/gno.land/p/demo/int256/cmp_test.gno index c646c7a7ea9..b552a84ba8a 100644 --- a/examples/gno.land/p/demo/int256/cmp_test.gno +++ b/examples/gno.land/p/demo/int256/cmp_test.gno @@ -173,7 +173,6 @@ func TestLt(t *testing.T) { {"0", "-1", false}, {"1", "1", false}, {"-1", "-1", false}, - // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", false}, } for _, tc := range tests { @@ -208,7 +207,6 @@ func TestGt(t *testing.T) { {"0", "-1", true}, {"1", "1", false}, {"-1", "-1", false}, - // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", true}, } for _, tc := range tests { diff --git a/examples/gno.land/p/demo/int256/int256.gno b/examples/gno.land/p/demo/int256/int256.gno index f4ed981eecf..c283e11e0d3 100644 --- a/examples/gno.land/p/demo/int256/int256.gno +++ b/examples/gno.land/p/demo/int256/int256.gno @@ -36,7 +36,11 @@ func Zero() *Int { return &Int{} } // // 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 int1 } +func One() *Int { + return &Int{ + value: *uint256.NewUint(1), + } +} // Sign determines the sign of the Int. // diff --git a/examples/gno.land/p/demo/int256/int256_test.gno b/examples/gno.land/p/demo/int256/int256_test.gno index 76d1d69ef34..375e6da0a45 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -32,7 +32,7 @@ func TestInitializers(t *testing.T) { } func TestNewInt(t *testing.T) { - testCases := []struct { + tests := []struct { input int64 expected int }{ @@ -43,10 +43,10 @@ func TestNewInt(t *testing.T) { {-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) + for _, tt := range tests { + z := NewInt(tt.input) + if z.Sign() != tt.expected { + t.Errorf("NewInt(%d) = %d, want %d", tt.input, z.Sign(), tt.expected) } } } From 641da4e253bed8fd1c52bc8c0964e466b3c3df42 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Sat, 28 Sep 2024 00:18:22 +0900 Subject: [PATCH 07/11] fix div --- examples/gno.land/p/demo/int256/arithmetic.gno | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index f605ffac9e1..afdb2bde90e 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -48,11 +48,14 @@ func (z *Int) Mul(x, y *Int) *Int { // Abs returns the absolute value of z. func (z *Int) Abs() *uint256.Uint { - var absValue uint256.Uint if z.Sign() >= 0 { - return absValue.Set(&z.value) + return &z.value } - return absValue.Sub(uint0, &z.value) + + var absValue uint256.Uint + absValue.Sub(uint0, &z.value).Neg(&z.value) + + return &absValue } /* +--------------------------------------------------------------------------+ From 05d3c16ac44dcc30c2564bef68c27398472cfc95 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Mon, 28 Oct 2024 14:11:42 +0900 Subject: [PATCH 08/11] big number tests --- .../gno.land/p/demo/int256/arithmetic.gno | 89 +++++++++---------- .../p/demo/int256/arithmetic_test.gno | 33 ++++++- .../gno.land/p/demo/int256/bitwise_test.gno | 20 +++++ examples/gno.land/p/demo/int256/cmp_test.gno | 2 +- .../gno.land/p/demo/int256/conversion.gno | 13 ++- examples/gno.land/p/demo/int256/doc.gno | 21 ++--- 6 files changed, 113 insertions(+), 65 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index afdb2bde90e..b3ebf86ba4a 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -1,3 +1,46 @@ +// # Division and modulus operations +// +// This package provides three different division and modulus operations: +// - Div and Rem: Truncated division (T-division) +// - Quo and Mod: Floored division (F-division) +// - DivE and ModE: Euclidean division (E-division) +// +// * Truncated division (Div, Rem) is the most common implementation in modern processors +// and programming languages. It rounds quotients towards zero and the remainder +// always has the same sign as the dividend. +// +// * Floored division (Quo, Mod) always rounds quotients towards negative infinity. +// This ensures that the modulus is always non-negative for a positive divisor, +// which can be useful in certain algorithms. +// +// * Euclidean division (DivE, ModE) ensures that the remainder is always non-negative, +// regardless of the signs of the dividend and divisor. This has several mathematical +// advantages: +// 1. It satisfies the unique division with remainder theorem. +// 2. It preserves division and modulus properties for negative divisors. +// 3. It allows for optimizations in divisions by powers of two. +// +// [+] Currently, ModE and Mod are shared the same implementation. +// +// ## Performance considerations: +// - For most operations, the performance difference between these division types is negligible. +// - Euclidean division may require an extra comparison and potentially an addition, +// which could impact performance in extremely performance-critical scenarios. +// - For divisions by powers of two, Euclidean division can be optimized to use +// bitwise operations, potentially offering better performance. +// +// ## Usage guidelines: +// - Use Div and Rem for general-purpose division that matches most common expectations. +// - Use Quo and Mod when you need a non-negative remainder for positive divisors, +// or when implementing algorithms that assume floored division. +// - Use DivE and ModE when you need the mathematical properties of Euclidean division, +// or when working with algorithms that specifically require it. +// +// Note: When working with negative numbers, be aware of the differences in behavior +// between these division types, especially at the boundaries of integer ranges. +// +// ## References +// 1. Daan Leijen, “Division and Modulus for Computer Scientists” (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) package int256 import ( @@ -58,52 +101,6 @@ func (z *Int) Abs() *uint256.Uint { return &absValue } -/* +--------------------------------------------------------------------------+ -// |Division and modulus operations | -// +--------------------------------------------------------------------------+ -// -// This package provides three different division and modulus operations: -// - Div and Rem: Truncated division (T-division) -// - Quo and Mod: Floored division (F-division) -// - DivE and ModE: Euclidean division (E-division) -// -// * Truncated division (Div, Rem) is the most common implementation in modern processors -// and programming languages. It rounds quotients towards zero and the remainder -// always has the same sign as the dividend. -// -// * Floored division (Quo, Mod) always rounds quotients towards negative infinity. -// This ensures that the modulus is always non-negative for a positive divisor, -// which can be useful in certain algorithms. -// -// * Euclidean division (DivE, ModE) ensures that the remainder is always non-negative, -// regardless of the signs of the dividend and divisor. This has several mathematical -// advantages: -// 1. It satisfies the unique division with remainder theorem. -// 2. It preserves division and modulus properties for negative divisors. -// 3. It allows for optimizations in divisions by powers of two. -// [+] Currently, ModE and Mod are shared the same implementation. -// -// ## Performance considerations: -// - For most operations, the performance difference between these division types is negligible. -// - Euclidean division may require an extra comparison and potentially an addition, -// which could impact performance in extremely performance-critical scenarios. -// - For divisions by powers of two, Euclidean division can be optimized to use -// bitwise operations, potentially offering better performance. -// -// ## Usage guidelines: -// - Use Div and Rem for general-purpose division that matches most common expectations. -// - Use Quo and Mod when you need a non-negative remainder for positive divisors, -// or when implementing algorithms that assume floored division. -// - Use DivE and ModE when you need the mathematical properties of Euclidean division, -// or when working with algorithms that specifically require it. -// -// Note: When working with negative numbers, be aware of the differences in behavior -// between these division types, especially at the boundaries of integer ranges. -// -// ## References -// 1. Daan Leijen, “Division and Modulus for Computer Scientists” (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) -/* ---------------------------------------------------------------------------- */ - // Div performs integer division z = x / y and returns z. // If y == 0, it panics with a "division by zero" error. // diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index 3b36fb56dcd..8e6e77b5439 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -24,6 +24,9 @@ func TestAdd(t *testing.T) { {"3", "-1", "2"}, // OVERFLOW {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "1", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // MAX_INT256 + 1 = MIN_INT256 + {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MIN_INT256 - 1 = MAX_INT256 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967", "-2"}, // MAX_INT256 + MAX_INT256 = -2 } for _, tc := range tests { @@ -192,7 +195,9 @@ func TestSub(t *testing.T) { {"-1", "-1", "0"}, {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {x: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", y: "1", want: "0"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1"}, + {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819968", "0"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967", "0"}, } for _, tc := range tests { @@ -278,6 +283,10 @@ func TestMul(t *testing.T) { {"3", "0", "0"}, {"-5", "-3", "15"}, {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "-2"}, // MAX_INT256 * 2 = -2 + {"28948022309329048855892746252171976963317496166410141009864396001978282409984", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 2^254 * 2 = MIN_INT256 + {"-28948022309329048855892746252171976963317496166410141009864396001978282409984", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // -2^254 * 2 = MIN_INT256 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "1", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MAX_INT256 * 1 = MAX_INT256 } for _, tc := range tests { @@ -325,6 +334,7 @@ func TestDiv(t *testing.T) { // the maximum value of a positive number in int256 is less than the maximum value of a uint256 {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Max int256 - 1) / 2 {"-57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "-28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Min int256 + 1) / 2 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-1", "-57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MAX_INT256 / -1 = -MAX_INT256 } for _, tt := range tests { @@ -481,6 +491,27 @@ func TestMod(t *testing.T) { } } +func TestModeOverflow(t *testing.T) { + tests := []struct { + x, y, want string + }{ + {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "2", "0"}, // MIN_INT256 % 2 = 0 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "1"}, // MAX_INT256 % 2 = 1 + {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1", "0"}, // MIN_INT256 % -1 = 0 + {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-1", "0"}, // MAX_INT256 % -1 = 0 + } + + for _, tt := range tests { + x := MustFromDecimal(tt.x) + y := MustFromDecimal(tt.y) + want := MustFromDecimal(tt.want) + got := New().Mod(x, y) + if got.Neq(want) { + t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + } + } +} + func TestModPanic(t *testing.T) { tests := []struct { x, y string diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gno index 6e3d4a92a9b..7a974976545 100644 --- a/examples/gno.land/p/demo/int256/bitwise_test.gno +++ b/examples/gno.land/p/demo/int256/bitwise_test.gno @@ -11,6 +11,10 @@ func TestBitwise_And(t *testing.T) { {"5", "1", "1"}, // 0101 & 0001 = 0001 {"-1", "1", "1"}, // 1111 & 0001 = 0001 {"-5", "3", "3"}, // 1111...1011 & 0000...0011 = 0000...0011 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // MAX_INT256 & MAX_INT256 = MAX_INT256 + {"340282366920938463463374607431768211456", "340282366920938463463374607431768211455", "0"}, // 2^128 & (2^128 - 1) = 0 + {"340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456"}, // 2^128 & MAX_INT256 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "340282366920938463463374607431768211456"}, // MAX_INT256 & 2^128 } for _, tc := range tests { @@ -33,6 +37,10 @@ func TestBitwise_Or(t *testing.T) { {"5", "1", "5"}, // 0101 | 0001 = 0101 {"-1", "1", "-1"}, // 1111 | 0001 = 1111 {"-5", "3", "-5"}, // 1111...1011 | 0000...0011 = 1111...1011 + {"340282366920938463463374607431768211456", "340282366920938463463374607431768211455", "680564733841876926926749214863536422911"}, + {"340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // 2^128 | MAX_INT256 = MAX_INT256 + {"0", "340282366920938463463374607431768211456", "340282366920938463463374607431768211456"}, // 0 | 2^128 = 2^128 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // MAX_INT256 | 2^128 = MAX_INT256 } for _, tc := range tests { @@ -54,6 +62,8 @@ func TestBitwise_Not(t *testing.T) { }{ {"5", "-6"}, // 0101 -> 1111...1010 {"-1", "0"}, // 1111...1111 -> 0000...0000 + {"340282366920938463463374607431768211456", "-340282366920938463463374607431768211457"}, // NOT 2^128 + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819969"}, // NOT 2^255 } for _, tc := range tests { @@ -75,6 +85,9 @@ func TestBitwise_Xor(t *testing.T) { {"5", "1", "4"}, // 0101 ^ 0001 = 0100 {"-1", "1", "-2"}, // 1111...1111 ^ 0000...0001 = 1111...1110 {"-5", "3", "-8"}, // 1111...1011 ^ 0000...0011 = 1111...1000 + {"340282366920938463463374607431768211456", "340282366920938463463374607431768211456", "0"}, // 2^128 ^ 2^128 = 0 + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "-340282366920938463463374607431768211457"}, // MAX_INT256 ^ 2^128 + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "-57896044618658097711785492504343953926634992332820282019728792003956564819969"}, // 2^255 ^ MAX_INT256 } for _, tt := range tests { @@ -98,6 +111,10 @@ func TestBitwise_Rsh(t *testing.T) { }{ {"5", 1, "2"}, // 0101 >> 1 = 0010 {"42", 3, "5"}, // 00101010 >> 3 = 00000101 + {"340282366920938463463374607431768211456", 128, "1"}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 255, "1"}, + {"57896044618658097711785492504343953926634992332820282019728792003956564819968", 254, "2"}, + {"-340282366920938463463374607431768211456", 128, "340282366920938463463374607431768211455"}, } for _, tt := range tests { @@ -120,6 +137,9 @@ func TestBitwise_Lsh(t *testing.T) { }{ {"5", 2, "20"}, // 0101 << 2 = 10100 {"42", 5, "1344"}, // 00101010 << 5 = 10101000000 + {"1", 128, "340282366920938463463374607431768211456"}, // 1 << 128 = 2^128 + {"2", 254, "57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 2 << 254 = 2^255 + {"1", 255, "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 1 << 255 = MIN_INT256 (overflow) } for _, tt := range tests { diff --git a/examples/gno.land/p/demo/int256/cmp_test.gno b/examples/gno.land/p/demo/int256/cmp_test.gno index b552a84ba8a..c1c6559de3c 100644 --- a/examples/gno.land/p/demo/int256/cmp_test.gno +++ b/examples/gno.land/p/demo/int256/cmp_test.gno @@ -85,7 +85,7 @@ func TestCmp(t *testing.T) { {"-1", "0", -1}, {"0", "-1", 1}, {"1", "1", 0}, - // {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", 1}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", -1}, } for _, tc := range tests { diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gno index 7da74ea2c2e..0757e9dddc7 100644 --- a/examples/gno.land/p/demo/int256/conversion.gno +++ b/examples/gno.land/p/demo/int256/conversion.gno @@ -43,14 +43,13 @@ func (z *Int) Int64() int64 { panic("overflow: int256 does not fit in int64 type") } return int64(z.value.Uint64()) - } else { - var temp uint256.Uint - temp.Sub(uint256.NewUint(0), &z.value) // temp = -z.value - if temp.BitLen() > 64 { - panic("overflow: int256 does not fit in int64 type") - } - return -int64(temp.Uint64()) } + var temp uint256.Uint + temp.Sub(uint256.NewUint(0), &z.value) // temp = -z.value + if temp.BitLen() > 64 { + panic("overflow: int256 does not fit in int64 type") + } + return -int64(temp.Uint64()) } // Neg sets z to -x and returns z.) diff --git a/examples/gno.land/p/demo/int256/doc.gno b/examples/gno.land/p/demo/int256/doc.gno index 4481af54069..6b3b06f371a 100644 --- a/examples/gno.land/p/demo/int256/doc.gno +++ b/examples/gno.land/p/demo/int256/doc.gno @@ -6,18 +6,19 @@ // // ## Features // -// - 256-bit Signed Integers: Support for large integer ranging from -2^255 tp 2^255-1. -// - Two's Complement Representation: Efficient storage and computation using two's complement. -// - Arithmetic Operations: Add, Sub, Mul, Div, Mod, Inc, Dec, etc. -// - Bitwise Operations: And, Or, Xor, Not, etc. -// - Comparison Operations: Cmp, Eq, Lt, Gt, etc. -// - Conversion Functions: Int to Uint, Uint to Int, etc. -// - String Parsing and Formatting: Convert to and from decimal string representation. +// - 256-bit Signed Integers: Support for large integer ranging from -2^255 to 2^255-1. +// - Two's Complement Representation: Efficient storage and computation using two's complement. +// - Arithmetic Operations: Add, Sub, Mul, Div, Mod, Inc, Dec, etc. +// - Bitwise Operations: And, Or, Xor, Not, etc. +// - Comparison Operations: Cmp, Eq, Lt, Gt, etc. +// - Conversion Functions: Int to Uint, Uint to Int, etc. +// - String Parsing and Formatting: Convert to and from decimal string representation. // // ## Notes // -// - Some methods may panic when encountering invalid inputs or overflows. -// - The `int256.Int` type can interact with `uint256.Uint` from the `p/demo/uint256` package. -// - Unlike `math/big.Int`, the `int256.Int` type has fixed size (256-bit) and does not support +// - Some methods may panic when encountering invalid inputs or overflows. +// - The `int256.Int` type can interact with `uint256.Uint` from the `p/demo/uint256` package. +// - Unlike `math/big.Int`, the `int256.Int` type has fixed size (256-bit) and does not support +// // arbitrary precision arithmetic. package int256 From a55524a10d4eae3dec9e79707b8775e379ed87f1 Mon Sep 17 00:00:00 2001 From: Morgan Bazalgette Date: Mon, 28 Oct 2024 13:58:02 +0100 Subject: [PATCH 09/11] fixup doc --- .../gno.land/p/demo/int256/arithmetic.gno | 43 ---------------- examples/gno.land/p/demo/int256/doc.gno | 51 ++++++++++++++++++- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic.gno b/examples/gno.land/p/demo/int256/arithmetic.gno index b3ebf86ba4a..10f578f6e61 100644 --- a/examples/gno.land/p/demo/int256/arithmetic.gno +++ b/examples/gno.land/p/demo/int256/arithmetic.gno @@ -1,46 +1,3 @@ -// # Division and modulus operations -// -// This package provides three different division and modulus operations: -// - Div and Rem: Truncated division (T-division) -// - Quo and Mod: Floored division (F-division) -// - DivE and ModE: Euclidean division (E-division) -// -// * Truncated division (Div, Rem) is the most common implementation in modern processors -// and programming languages. It rounds quotients towards zero and the remainder -// always has the same sign as the dividend. -// -// * Floored division (Quo, Mod) always rounds quotients towards negative infinity. -// This ensures that the modulus is always non-negative for a positive divisor, -// which can be useful in certain algorithms. -// -// * Euclidean division (DivE, ModE) ensures that the remainder is always non-negative, -// regardless of the signs of the dividend and divisor. This has several mathematical -// advantages: -// 1. It satisfies the unique division with remainder theorem. -// 2. It preserves division and modulus properties for negative divisors. -// 3. It allows for optimizations in divisions by powers of two. -// -// [+] Currently, ModE and Mod are shared the same implementation. -// -// ## Performance considerations: -// - For most operations, the performance difference between these division types is negligible. -// - Euclidean division may require an extra comparison and potentially an addition, -// which could impact performance in extremely performance-critical scenarios. -// - For divisions by powers of two, Euclidean division can be optimized to use -// bitwise operations, potentially offering better performance. -// -// ## Usage guidelines: -// - Use Div and Rem for general-purpose division that matches most common expectations. -// - Use Quo and Mod when you need a non-negative remainder for positive divisors, -// or when implementing algorithms that assume floored division. -// - Use DivE and ModE when you need the mathematical properties of Euclidean division, -// or when working with algorithms that specifically require it. -// -// Note: When working with negative numbers, be aware of the differences in behavior -// between these division types, especially at the boundaries of integer ranges. -// -// ## References -// 1. Daan Leijen, “Division and Modulus for Computer Scientists” (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) package int256 import ( diff --git a/examples/gno.land/p/demo/int256/doc.gno b/examples/gno.land/p/demo/int256/doc.gno index 6b3b06f371a..ec7d2d3bf9a 100644 --- a/examples/gno.land/p/demo/int256/doc.gno +++ b/examples/gno.land/p/demo/int256/doc.gno @@ -19,6 +19,55 @@ // - Some methods may panic when encountering invalid inputs or overflows. // - The `int256.Int` type can interact with `uint256.Uint` from the `p/demo/uint256` package. // - Unlike `math/big.Int`, the `int256.Int` type has fixed size (256-bit) and does not support +// arbitrary precision arithmetic. // -// arbitrary precision arithmetic. +// # Division and modulus operations +// +// This package provides three different division and modulus operations: +// +// - Div and Rem: Truncated division (T-division) +// - Quo and Mod: Floored division (F-division) +// - DivE and ModE: Euclidean division (E-division) +// +// Truncated division (Div, Rem) is the most common implementation in modern processors +// and programming languages. It rounds quotients towards zero and the remainder +// always has the same sign as the dividend. +// +// Floored division (Quo, Mod) always rounds quotients towards negative infinity. +// This ensures that the modulus is always non-negative for a positive divisor, +// which can be useful in certain algorithms. +// +// Euclidean division (DivE, ModE) ensures that the remainder is always non-negative, +// regardless of the signs of the dividend and divisor. This has several mathematical +// advantages: +// +// 1. It satisfies the unique division with remainder theorem. +// 2. It preserves division and modulus properties for negative divisors. +// 3. It allows for optimizations in divisions by powers of two. +// +// [+] Currently, ModE and Mod are shared the same implementation. +// +// ## Performance considerations: +// +// - For most operations, the performance difference between these division types is negligible. +// - Euclidean division may require an extra comparison and potentially an addition, +// which could impact performance in extremely performance-critical scenarios. +// - For divisions by powers of two, Euclidean division can be optimized to use +// bitwise operations, potentially offering better performance. +// +// ## Usage guidelines: +// +// - Use Div and Rem for general-purpose division that matches most common expectations. +// - Use Quo and Mod when you need a non-negative remainder for positive divisors, +// or when implementing algorithms that assume floored division. +// - Use DivE and ModE when you need the mathematical properties of Euclidean division, +// or when working with algorithms that specifically require it. +// +// Note: When working with negative numbers, be aware of the differences in behavior +// between these division types, especially at the boundaries of integer ranges. +// +// ## References +// +// Daan Leijen, “Division and Modulus for Computer Scientists”: +// https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf package int256 From 269f90f69e02d8f97032d73310fbc09d1a2d9663 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Tue, 29 Oct 2024 10:50:20 +0900 Subject: [PATCH 10/11] ToString -> String --- .../p/demo/int256/arithmetic_test.gno | 30 +++++++++---------- .../gno.land/p/demo/int256/bitwise_test.gno | 12 ++++---- .../gno.land/p/demo/int256/conversion.gno | 2 +- .../p/demo/int256/conversion_test.gno | 10 +++---- .../gno.land/p/demo/int256/int256_test.gno | 8 ++--- .../p/demo/uint256/arithmetic_test.gno | 24 +++++++-------- .../gno.land/p/demo/uint256/bitwise_test.gno | 16 +++++----- examples/gno.land/p/demo/uint256/cmp_test.gno | 2 +- .../gno.land/p/demo/uint256/conversion.gno | 2 +- .../p/demo/uint256/conversion_test.gno | 2 +- .../gno.land/p/demo/uint256/uint256_test.gno | 8 ++--- 11 files changed, 58 insertions(+), 58 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index 8e6e77b5439..a16d990527a 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -52,7 +52,7 @@ func TestAdd(t *testing.T) { got.Add(x, y) if got.Neq(want) { - t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Add(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -96,7 +96,7 @@ func TestAddUint256(t *testing.T) { got.AddUint256(x, y) if got.Neq(want) { - t.Errorf("AddUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("AddUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -143,7 +143,7 @@ func TestAddDelta(t *testing.T) { 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()) + t.Errorf("AddDelta(%s, %s, %s) = %v, want %v", tc.z, tc.x, tc.y, z.String(), want.String()) } } } @@ -223,7 +223,7 @@ func TestSub(t *testing.T) { got.Sub(x, y) if got.Neq(want) { - t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Sub(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -267,7 +267,7 @@ func TestSubUint256(t *testing.T) { got.SubUint256(x, y) if got.Neq(want) { - t.Errorf("SubUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("SubUint256(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -312,7 +312,7 @@ func TestMul(t *testing.T) { got.Mul(x, y) if got.Neq(want) { - t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Mul(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -342,8 +342,8 @@ func TestDiv(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.String() != tt.expected { + t.Errorf("Div(%s, %s) = %s, want %s", tt.x, tt.y, result.String(), tt.expected) } }) } @@ -398,7 +398,7 @@ func TestQuo(t *testing.T) { got.Quo(x, y) if got.Neq(want) { - t.Errorf("Quo(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Quo(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -442,7 +442,7 @@ func TestRem(t *testing.T) { got.Rem(x, y) if got.Neq(want) { - t.Errorf("Rem(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Rem(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -486,7 +486,7 @@ func TestMod(t *testing.T) { got.Mod(x, y) if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.ToString(), want.ToString()) + t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, got.String(), want.String()) } } } @@ -507,7 +507,7 @@ func TestModeOverflow(t *testing.T) { want := MustFromDecimal(tt.want) got := New().Mod(x, y) if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.String(), want.String()) } } } @@ -541,7 +541,7 @@ func TestModPanic(t *testing.T) { } result := New().Mod(x, y) - t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, result.ToString(), "0") + t.Errorf("Mod(%s, %s) = %v, want %v", tc.x, tc.y, result.String(), "0") } } @@ -637,8 +637,8 @@ func TestAbs(t *testing.T) { got := x.Abs() - if got.ToString() != tc.want { - t.Errorf("Abs(%s) = %v, want %v", tc.x, got.ToString(), tc.want) + if got.String() != tc.want { + t.Errorf("Abs(%s) = %v, want %v", tc.x, got.String(), tc.want) } } } diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gno index 7a974976545..b8cfd547d8d 100644 --- a/examples/gno.land/p/demo/int256/bitwise_test.gno +++ b/examples/gno.land/p/demo/int256/bitwise_test.gno @@ -25,7 +25,7 @@ func TestBitwise_And(t *testing.T) { got := new(Int).And(x, y) if got.Neq(want) { - t.Errorf("And(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + t.Errorf("And(%s, %s) = %s, want %s", x.String(), y.String(), got.String(), want.String()) } } } @@ -51,7 +51,7 @@ func TestBitwise_Or(t *testing.T) { got := new(Int).Or(x, y) if got.Neq(want) { - t.Errorf("Or(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + t.Errorf("Or(%s, %s) = %s, want %s", x.String(), y.String(), got.String(), want.String()) } } } @@ -73,7 +73,7 @@ func TestBitwise_Not(t *testing.T) { got := new(Int).Not(x) if got.Neq(want) { - t.Errorf("Not(%s) = %s, want %s", x.ToString(), got.ToString(), want.ToString()) + t.Errorf("Not(%s) = %s, want %s", x.String(), got.String(), want.String()) } } } @@ -98,7 +98,7 @@ func TestBitwise_Xor(t *testing.T) { got := new(Int).Xor(x, y) if got.Neq(want) { - t.Errorf("Xor(%s, %s) = %s, want %s", x.ToString(), y.ToString(), got.ToString(), want.ToString()) + t.Errorf("Xor(%s, %s) = %s, want %s", x.String(), y.String(), got.String(), want.String()) } } } @@ -124,7 +124,7 @@ func TestBitwise_Rsh(t *testing.T) { got := new(Int).Rsh(x, tt.n) if got.Neq(want) { - t.Errorf("Rsh(%s, %d) = %s, want %s", x.ToString(), tt.n, got.ToString(), want.ToString()) + t.Errorf("Rsh(%s, %d) = %s, want %s", x.String(), tt.n, got.String(), want.String()) } } } @@ -149,7 +149,7 @@ func TestBitwise_Lsh(t *testing.T) { got := new(Int).Lsh(x, tt.n) if got.Neq(want) { - t.Errorf("Lsh(%s, %d) = %s, want %s", x.ToString(), tt.n, got.ToString(), want.ToString()) + t.Errorf("Lsh(%s, %d) = %s, want %s", x.String(), tt.n, got.String(), want.String()) } } } diff --git a/examples/gno.land/p/demo/int256/conversion.gno b/examples/gno.land/p/demo/int256/conversion.gno index 0757e9dddc7..c8829ea754b 100644 --- a/examples/gno.land/p/demo/int256/conversion.gno +++ b/examples/gno.land/p/demo/int256/conversion.gno @@ -76,7 +76,7 @@ func (z *Int) SetUint256(x *uint256.Uint) *Int { // ToString returns a string representation of z in base 10. // The string is prefixed with a minus sign if z is negative. -func (z *Int) ToString() string { +func (z *Int) String() string { if z.value.IsZero() { return "0" } diff --git a/examples/gno.land/p/demo/int256/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gno index 5b8c5fe456a..68fd3486ff5 100644 --- a/examples/gno.land/p/demo/int256/conversion_test.gno +++ b/examples/gno.land/p/demo/int256/conversion_test.gno @@ -127,7 +127,7 @@ func TestNeg(t *testing.T) { z := MustFromDecimal(tt.x) z.Neg(z) - got := z.ToString() + got := z.String() if got != tt.want { t.Errorf("Neg(%s) = %s, want %s", tt.x, got, tt.want) } @@ -150,7 +150,7 @@ func TestSet(t *testing.T) { z := MustFromDecimal(tt.x) z.Set(z) - got := z.ToString() + got := z.String() if got != tt.want { t.Errorf("Set(%s) = %s, want %s", tt.x, got, tt.want) } @@ -174,8 +174,8 @@ func TestSetUint256(t *testing.T) { z := uint256.MustFromDecimal(tt.x) got.SetUint256(z) - if got.ToString() != tt.want { - t.Errorf("SetUint256(%s) = %s, want %s", tt.x, got.ToString(), tt.want) + if got.String() != tt.want { + t.Errorf("SetUint256(%s) = %s, want %s", tt.x, got.String(), tt.want) } } } @@ -205,7 +205,7 @@ func TestToString(t *testing.T) { continue } - output := x.ToString() + output := x.String() if output != tt.expected { t.Errorf("String(%s) = %s, want %s", tt.input, output, tt.expected) diff --git a/examples/gno.land/p/demo/int256/int256_test.gno b/examples/gno.land/p/demo/int256/int256_test.gno index 375e6da0a45..9fbe22bf072 100644 --- a/examples/gno.land/p/demo/int256/int256_test.gno +++ b/examples/gno.land/p/demo/int256/int256_test.gno @@ -24,8 +24,8 @@ func TestInitializers(t *testing.T) { if z.Sign() != tt.wantSign { t.Errorf("%s() = %d, want %d", tt.name, z.Sign(), tt.wantSign) } - if z.ToString() != tt.wantStr { - t.Errorf("%s() = %s, want %s", tt.name, z.ToString(), tt.wantStr) + if z.String() != tt.wantStr { + t.Errorf("%s() = %s, want %s", tt.name, z.String(), tt.wantStr) } }) } @@ -205,8 +205,8 @@ func TestSetAndToString(t *testing.T) { t.Errorf("SetString(%s) unexpected error: %v", tt.input, err) } else if z.Sign() != tt.expected { t.Errorf("SetString(%s) sign is incorrect. Expected: %d, Actual: %d", tt.input, tt.expected, z.Sign()) - } else if z.ToString() != tt.input { - t.Errorf("SetString(%s) string representation is incorrect. Expected: %s, Actual: %s", tt.input, tt.input, z.ToString()) + } else if z.String() != tt.input { + t.Errorf("SetString(%s) string representation is incorrect. Expected: %s, Actual: %s", tt.input, tt.input, z.String()) } } } diff --git a/examples/gno.land/p/demo/uint256/arithmetic_test.gno b/examples/gno.land/p/demo/uint256/arithmetic_test.gno index 079d89fa794..addd33db997 100644 --- a/examples/gno.land/p/demo/uint256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/uint256/arithmetic_test.gno @@ -26,7 +26,7 @@ func TestAdd(t *testing.T) { got := new(Uint).Add(x, y) if got.Neq(want) { - t.Errorf("Add(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Add(%s, %s) = %v, want %v", tt.x, tt.y, got.String(), want.String()) } } } @@ -56,7 +56,7 @@ func TestAddOverflow(t *testing.T) { if got.Cmp(want) != 0 || overflow != tt.overflow { t.Errorf("AddOverflow(%s, %s) = (%s, %v), want (%s, %v)", - tt.x, tt.y, got.ToString(), overflow, tt.want, tt.overflow) + tt.x, tt.y, got.String(), overflow, tt.want, tt.overflow) } } } @@ -81,7 +81,7 @@ func TestSub(t *testing.T) { if got.Neq(want) { t.Errorf( "Sub(%s, %s) = %v, want %v", - tc.x, tc.y, got.ToString(), want.ToString(), + tc.x, tc.y, got.String(), want.String(), ) } } @@ -112,7 +112,7 @@ func TestSubOverflow(t *testing.T) { if got.Cmp(want) != 0 || overflow != tc.overflow { t.Errorf( "SubOverflow(%s, %s) = (%s, %v), want (%s, %v)", - tc.x, tc.y, got.ToString(), overflow, tc.want, tc.overflow, + tc.x, tc.y, got.String(), overflow, tc.want, tc.overflow, ) } } @@ -133,7 +133,7 @@ func TestMul(t *testing.T) { got := new(Uint).Mul(x, y) if got.Neq(want) { - t.Errorf("Mul(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Mul(%s, %s) = %v, want %v", tt.x, tt.y, got.String(), want.String()) } } } @@ -165,7 +165,7 @@ func TestMulOverflow(t *testing.T) { if gotZ.Neq(wantZ) { t.Errorf( "MulOverflow(%s, %s) = %s, want %s", - tt.x, tt.y, gotZ.ToString(), wantZ.ToString(), + tt.x, tt.y, gotZ.String(), wantZ.String(), ) } if gotOver != tt.wantOver { @@ -192,7 +192,7 @@ func TestDiv(t *testing.T) { got := new(Uint).Div(x, y) if got.Neq(want) { - t.Errorf("Div(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Div(%s, %s) = %v, want %v", tt.x, tt.y, got.String(), want.String()) } } } @@ -217,7 +217,7 @@ func TestMod(t *testing.T) { got := new(Uint).Mod(x, y) if got.Neq(want) { - t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Mod(%s, %s) = %v, want %v", tt.x, tt.y, got.String(), want.String()) } } } @@ -252,7 +252,7 @@ func TestMulMod(t *testing.T) { if got.Neq(want) { t.Errorf( "MulMod(%s, %s, %s) = %s, want %s", - tt.x, tt.y, tt.m, got.ToString(), want.ToString(), + tt.x, tt.y, tt.m, got.String(), want.String(), ) } } @@ -318,7 +318,7 @@ func TestNeg(t *testing.T) { got := new(Uint).Neg(x) if got.Neq(want) { - t.Errorf("Neg(%s) = %v, want %v", tt.x, got.ToString(), want.ToString()) + t.Errorf("Neg(%s) = %v, want %v", tt.x, got.String(), want.String()) } } } @@ -346,7 +346,7 @@ func TestExp(t *testing.T) { if got.Neq(want) { t.Errorf( "Exp(%s, %s) = %v, want %v", - tt.x, tt.y, got.ToString(), want.ToString(), + tt.x, tt.y, got.String(), want.String(), ) } } @@ -384,7 +384,7 @@ func TestExp_LargeExponent(t *testing.T) { if result.Neq(expected) { t.Errorf( "Test %s failed. Expected %s, got %s", - tt.name, expected.ToString(), result.ToString(), + tt.name, expected.String(), result.String(), ) } }) diff --git a/examples/gno.land/p/demo/uint256/bitwise_test.gno b/examples/gno.land/p/demo/uint256/bitwise_test.gno index 3561629fd94..45118af0b0f 100644 --- a/examples/gno.land/p/demo/uint256/bitwise_test.gno +++ b/examples/gno.land/p/demo/uint256/bitwise_test.gno @@ -43,7 +43,7 @@ func TestOr(t *testing.T) { if *res != tt.want { t.Errorf( "Or(%s, %s) = %s, want %s", - tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + tt.x.String(), tt.y.String(), res.String(), (tt.want).String(), ) } }) @@ -102,7 +102,7 @@ func TestAnd(t *testing.T) { if *res != tt.want { t.Errorf( "And(%s, %s) = %s, want %s", - tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + tt.x.String(), tt.y.String(), res.String(), (tt.want).String(), ) } }) @@ -138,7 +138,7 @@ func TestNot(t *testing.T) { if *res != tt.want { t.Errorf( "Not(%s) = %s, want %s", - tt.x.ToString(), res.ToString(), (tt.want).ToString(), + tt.x.String(), res.String(), (tt.want).String(), ) } }) @@ -197,7 +197,7 @@ func TestAndNot(t *testing.T) { if *res != tt.want { t.Errorf( "AndNot(%s, %s) = %s, want %s", - tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + tt.x.String(), tt.y.String(), res.String(), (tt.want).String(), ) } }) @@ -256,7 +256,7 @@ func TestXor(t *testing.T) { if *res != tt.want { t.Errorf( "Xor(%s, %s) = %s, want %s", - tt.x.ToString(), tt.y.ToString(), res.ToString(), (tt.want).ToString(), + tt.x.String(), tt.y.String(), res.String(), (tt.want).String(), ) } }) @@ -311,7 +311,7 @@ func TestLsh(t *testing.T) { got := new(Uint).Lsh(x, tt.y) if got.Neq(want) { - t.Errorf("Lsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Lsh(%s, %d) = %s, want %s", tt.x, tt.y, got.String(), want.String()) } } } @@ -357,7 +357,7 @@ func TestRsh(t *testing.T) { got := new(Uint).Rsh(x, tt.y) if got.Neq(want) { - t.Errorf("Rsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("Rsh(%s, %d) = %s, want %s", tt.x, tt.y, got.String(), want.String()) } } } @@ -417,7 +417,7 @@ func TestSRsh(t *testing.T) { got := new(Uint).SRsh(x, tt.y) if !got.Eq(want) { - t.Errorf("SRsh(%s, %d) = %s, want %s", tt.x, tt.y, got.ToString(), want.ToString()) + t.Errorf("SRsh(%s, %d) = %s, want %s", tt.x, tt.y, got.String(), want.String()) } } } diff --git a/examples/gno.land/p/demo/uint256/cmp_test.gno b/examples/gno.land/p/demo/uint256/cmp_test.gno index 51c9e70d9a7..05243290271 100644 --- a/examples/gno.land/p/demo/uint256/cmp_test.gno +++ b/examples/gno.land/p/demo/uint256/cmp_test.gno @@ -29,7 +29,7 @@ func TestSign(t *testing.T) { } for _, tt := range tests { - t.Run(tt.input.ToString(), func(t *testing.T) { + t.Run(tt.input.String(), func(t *testing.T) { result := tt.input.Sign() if result != tt.expected { t.Errorf("Sign() = %d; want %d", result, tt.expected) diff --git a/examples/gno.land/p/demo/uint256/conversion.gno b/examples/gno.land/p/demo/uint256/conversion.gno index 4ef90602ab3..c2f228f314c 100644 --- a/examples/gno.land/p/demo/uint256/conversion.gno +++ b/examples/gno.land/p/demo/uint256/conversion.gno @@ -130,7 +130,7 @@ func (z *Uint) scanScientificFromString(src string) error { // ToString returns the decimal string representation of z. It returns an empty string if z is nil. // OBS: doesn't exist from holiman's uint256 -func (z *Uint) ToString() string { +func (z *Uint) String() string { if z == nil { return "" } diff --git a/examples/gno.land/p/demo/uint256/conversion_test.gno b/examples/gno.land/p/demo/uint256/conversion_test.gno index 0ea20158be4..3942a102511 100644 --- a/examples/gno.land/p/demo/uint256/conversion_test.gno +++ b/examples/gno.land/p/demo/uint256/conversion_test.gno @@ -169,7 +169,7 @@ func TestSetBytes(t *testing.T) { z.SetBytes(test.input) expected := MustFromDecimal(test.expected) if z.Cmp(expected) != 0 { - t.Errorf("SetBytes(%x) = %s, expected %s", test.input, z.ToString(), test.expected) + t.Errorf("SetBytes(%x) = %s, expected %s", test.input, z.String(), test.expected) } } } diff --git a/examples/gno.land/p/demo/uint256/uint256_test.gno b/examples/gno.land/p/demo/uint256/uint256_test.gno index 0089af15c66..ae8129b6e27 100644 --- a/examples/gno.land/p/demo/uint256/uint256_test.gno +++ b/examples/gno.land/p/demo/uint256/uint256_test.gno @@ -7,8 +7,8 @@ import ( func TestSetAllOne(t *testing.T) { z := Zero() z.SetAllOne() - if z.ToString() != twoPow256Sub1 { - t.Errorf("Expected all ones, got %s", z.ToString()) + if z.String() != twoPow256Sub1 { + t.Errorf("Expected all ones, got %s", z.String()) } } @@ -120,8 +120,8 @@ func TestClone(t *testing.T) { for _, tt := range tests { z, _ := FromHex(tt.input) result := z.Clone() - if result.ToString() != tt.expected { - t.Errorf("Test %s failed. Expected %s, got %s", tt.input, tt.expected, result.ToString()) + if result.String() != tt.expected { + t.Errorf("Test %s failed. Expected %s, got %s", tt.input, tt.expected, result.String()) } } } From b10e8d98ba6b74a59db40ac5ae4bcb5a70fde89d Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Tue, 29 Oct 2024 12:26:29 +0900 Subject: [PATCH 11/11] const --- .../p/demo/int256/arithmetic_test.gno | 86 +++++++++++++------ .../gno.land/p/demo/int256/bitwise_test.gno | 59 +++++++------ .../p/demo/int256/conversion_test.gno | 10 +-- 3 files changed, 94 insertions(+), 61 deletions(-) diff --git a/examples/gno.land/p/demo/int256/arithmetic_test.gno b/examples/gno.land/p/demo/int256/arithmetic_test.gno index a16d990527a..0b55552aca4 100644 --- a/examples/gno.land/p/demo/int256/arithmetic_test.gno +++ b/examples/gno.land/p/demo/int256/arithmetic_test.gno @@ -6,6 +6,36 @@ import ( "gno.land/p/demo/uint256" ) +const ( + // 2^255 - 1 + MAX_INT256 = "57896044618658097711785492504343953926634992332820282019728792003956564819967" + // -(2^255 - 1) + MINUS_MAX_INT256 = "-57896044618658097711785492504343953926634992332820282019728792003956564819967" + + // 2^255 - 1 + MAX_UINT256 = "115792089237316195423570985008687907853269984665640564039457584007913129639935" + MAX_UINT256_MINUS_1 = "115792089237316195423570985008687907853269984665640564039457584007913129639934" + + MINUS_MAX_UINT256 = "-115792089237316195423570985008687907853269984665640564039457584007913129639935" + MINUS_MAX_UINT256_PLUS_1 = "-115792089237316195423570985008687907853269984665640564039457584007913129639934" + + TWO_POW_128 = "340282366920938463463374607431768211456" + MINUS_TWO_POW_128 = "-340282366920938463463374607431768211456" + MINUS_TWO_POW_128_MINUS_1 = "-340282366920938463463374607431768211457" + TWO_POW_128_MINUS_1 = "340282366920938463463374607431768211455" + + TWO_POW_129_MINUS_1 = "680564733841876926926749214863536422911" + + TWO_POW_254 = "28948022309329048855892746252171976963317496166410141009864396001978282409984" + MINUS_TWO_POW_254 = "-28948022309329048855892746252171976963317496166410141009864396001978282409984" + HALF_MAX_INT256 = "28948022309329048855892746252171976963317496166410141009864396001978282409983" + MINUS_HALF_MAX_INT256 = "-28948022309329048855892746252171976963317496166410141009864396001978282409983" + + TWO_POW_255 = "57896044618658097711785492504343953926634992332820282019728792003956564819968" + MIN_INT256 = "-57896044618658097711785492504343953926634992332820282019728792003956564819968" + MIN_INT256_MINUS_1 = "-57896044618658097711785492504343953926634992332820282019728792003956564819969" +) + func TestAdd(t *testing.T) { tests := []struct { x, y, want string @@ -23,10 +53,10 @@ func TestAdd(t *testing.T) { {"-1", "3", "2"}, {"3", "-1", "2"}, // OVERFLOW - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "0"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "1", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // MAX_INT256 + 1 = MIN_INT256 - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MIN_INT256 - 1 = MAX_INT256 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967", "-2"}, // MAX_INT256 + MAX_INT256 = -2 + {MAX_UINT256, "1", "0"}, + {MAX_INT256, "1", MIN_INT256}, + {MIN_INT256, "-1", MAX_INT256}, + {MAX_INT256, MAX_INT256, "-2"}, } for _, tc := range tests { @@ -67,10 +97,10 @@ func TestAddUint256(t *testing.T) { {"1", "2", "3"}, {"-1", "1", "0"}, {"-1", "3", "2"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639934", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "1"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639934", "-1"}, + {MINUS_MAX_UINT256_PLUS_1, MAX_UINT256, "1"}, + {MINUS_MAX_UINT256, MAX_UINT256_MINUS_1, "-1"}, // OVERFLOW - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, + {MINUS_MAX_UINT256, MAX_UINT256, "0"}, } for _, tc := range tests { @@ -112,7 +142,7 @@ func TestAddDelta(t *testing.T) { {"1", "2", "3", "5"}, {"5", "10", "-3", "7"}, // underflow - {"1", "2", "-3", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, + {"1", "2", "-3", MAX_UINT256}, } for _, tc := range tests { @@ -193,11 +223,11 @@ func TestSub(t *testing.T) { {"-1", "1", "-2"}, {"1", "-1", "2"}, {"-1", "-1", "0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "0", "-115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819968", "0"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967", "0"}, + {MINUS_MAX_UINT256, MINUS_MAX_UINT256, "0"}, + {MINUS_MAX_UINT256, "0", MINUS_MAX_UINT256}, + {MAX_INT256, MIN_INT256, "-1"}, + {MIN_INT256, MIN_INT256, "0"}, + {MAX_INT256, MAX_INT256, "0"}, } for _, tc := range tests { @@ -239,9 +269,9 @@ func TestSubUint256(t *testing.T) { {"-1", "1", "-2"}, {"-1", "3", "-4"}, // underflow - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "-0"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "2", "-1"}, - {"-115792089237316195423570985008687907853269984665640564039457584007913129639935", "3", "-2"}, + {MINUS_MAX_UINT256, "1", "0"}, + {MINUS_MAX_UINT256, "2", "-1"}, + {MINUS_MAX_UINT256, "3", "-2"}, } for _, tc := range tests { @@ -282,11 +312,11 @@ func TestMul(t *testing.T) { {"0", "3", "0"}, {"3", "0", "0"}, {"-5", "-3", "15"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "1", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "-2"}, // MAX_INT256 * 2 = -2 - {"28948022309329048855892746252171976963317496166410141009864396001978282409984", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 2^254 * 2 = MIN_INT256 - {"-28948022309329048855892746252171976963317496166410141009864396001978282409984", "2", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // -2^254 * 2 = MIN_INT256 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "1", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MAX_INT256 * 1 = MAX_INT256 + {MAX_UINT256, "1", MAX_UINT256}, + {MAX_INT256, "2", "-2"}, + {TWO_POW_254, "2", MIN_INT256}, + {MINUS_TWO_POW_254, "2", MIN_INT256}, + {MAX_INT256, "1", MAX_INT256}, } for _, tc := range tests { @@ -332,9 +362,9 @@ func TestDiv(t *testing.T) { {"7", "3", "2"}, {"-7", "3", "-2"}, // the maximum value of a positive number in int256 is less than the maximum value of a uint256 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Max int256 - 1) / 2 - {"-57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "-28948022309329048855892746252171976963317496166410141009864396001978282409983"}, // (Min int256 + 1) / 2 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-1", "-57896044618658097711785492504343953926634992332820282019728792003956564819967"}, // MAX_INT256 / -1 = -MAX_INT256 + {MAX_INT256, "2", HALF_MAX_INT256}, + {MINUS_MAX_INT256, "2", MINUS_HALF_MAX_INT256}, + {MAX_INT256, "-1", MINUS_MAX_INT256}, } for _, tt := range tests { @@ -495,10 +525,10 @@ func TestModeOverflow(t *testing.T) { tests := []struct { x, y, want string }{ - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "2", "0"}, // MIN_INT256 % 2 = 0 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "2", "1"}, // MAX_INT256 % 2 = 1 - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-1", "0"}, // MIN_INT256 % -1 = 0 - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "-1", "0"}, // MAX_INT256 % -1 = 0 + {MIN_INT256, "2", "0"}, // MIN_INT256 % 2 = 0 + {MAX_INT256, "2", "1"}, // MAX_INT256 % 2 = 1 + {MIN_INT256, "-1", "0"}, // MIN_INT256 % -1 = 0 + {MAX_INT256, "-1", "0"}, // MAX_INT256 % -1 = 0 } for _, tt := range tests { diff --git a/examples/gno.land/p/demo/int256/bitwise_test.gno b/examples/gno.land/p/demo/int256/bitwise_test.gno index b8cfd547d8d..fc7b9bb578f 100644 --- a/examples/gno.land/p/demo/int256/bitwise_test.gno +++ b/examples/gno.land/p/demo/int256/bitwise_test.gno @@ -11,10 +11,10 @@ func TestBitwise_And(t *testing.T) { {"5", "1", "1"}, // 0101 & 0001 = 0001 {"-1", "1", "1"}, // 1111 & 0001 = 0001 {"-5", "3", "3"}, // 1111...1011 & 0000...0011 = 0000...0011 - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // MAX_INT256 & MAX_INT256 = MAX_INT256 - {"340282366920938463463374607431768211456", "340282366920938463463374607431768211455", "0"}, // 2^128 & (2^128 - 1) = 0 - {"340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456"}, // 2^128 & MAX_INT256 - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "340282366920938463463374607431768211456"}, // MAX_INT256 & 2^128 + {MAX_UINT256, MAX_UINT256, MAX_UINT256}, + {TWO_POW_128, TWO_POW_128_MINUS_1, "0"}, // 2^128 & (2^128 - 1) = 0 + {TWO_POW_128, MAX_UINT256, TWO_POW_128}, // 2^128 & MAX_INT256 + {MAX_UINT256, TWO_POW_128, TWO_POW_128}, // MAX_INT256 & 2^128 } for _, tc := range tests { @@ -37,10 +37,10 @@ func TestBitwise_Or(t *testing.T) { {"5", "1", "5"}, // 0101 | 0001 = 0101 {"-1", "1", "-1"}, // 1111 | 0001 = 1111 {"-5", "3", "-5"}, // 1111...1011 | 0000...0011 = 1111...1011 - {"340282366920938463463374607431768211456", "340282366920938463463374607431768211455", "680564733841876926926749214863536422911"}, - {"340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // 2^128 | MAX_INT256 = MAX_INT256 - {"0", "340282366920938463463374607431768211456", "340282366920938463463374607431768211456"}, // 0 | 2^128 = 2^128 - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "115792089237316195423570985008687907853269984665640564039457584007913129639935"}, // MAX_INT256 | 2^128 = MAX_INT256 + {TWO_POW_128, TWO_POW_128_MINUS_1, TWO_POW_129_MINUS_1}, + {TWO_POW_128, MAX_UINT256, MAX_UINT256}, + {"0", TWO_POW_128, TWO_POW_128}, // 0 | 2^128 = 2^128 + {MAX_UINT256, TWO_POW_128, MAX_UINT256}, // MAX_INT256 | 2^128 = MAX_INT256 } for _, tc := range tests { @@ -51,7 +51,10 @@ func TestBitwise_Or(t *testing.T) { got := new(Int).Or(x, y) if got.Neq(want) { - t.Errorf("Or(%s, %s) = %s, want %s", x.String(), y.String(), got.String(), want.String()) + t.Errorf( + "Or(%s, %s) = %s, want %s", + x.String(), y.String(), got.String(), want.String(), + ) } } } @@ -60,10 +63,10 @@ func TestBitwise_Not(t *testing.T) { tests := []struct { x, want string }{ - {"5", "-6"}, // 0101 -> 1111...1010 - {"-1", "0"}, // 1111...1111 -> 0000...0000 - {"340282366920938463463374607431768211456", "-340282366920938463463374607431768211457"}, // NOT 2^128 - {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819969"}, // NOT 2^255 + {"5", "-6"}, // 0101 -> 1111...1010 + {"-1", "0"}, // 1111...1111 -> 0000...0000 + {TWO_POW_128, MINUS_TWO_POW_128_MINUS_1}, // NOT 2^128 + {TWO_POW_255, MIN_INT256_MINUS_1}, // NOT 2^255 } for _, tc := range tests { @@ -82,12 +85,12 @@ func TestBitwise_Xor(t *testing.T) { tests := []struct { x, y, want string }{ - {"5", "1", "4"}, // 0101 ^ 0001 = 0100 - {"-1", "1", "-2"}, // 1111...1111 ^ 0000...0001 = 1111...1110 - {"-5", "3", "-8"}, // 1111...1011 ^ 0000...0011 = 1111...1000 - {"340282366920938463463374607431768211456", "340282366920938463463374607431768211456", "0"}, // 2^128 ^ 2^128 = 0 - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", "340282366920938463463374607431768211456", "-340282366920938463463374607431768211457"}, // MAX_INT256 ^ 2^128 - {"57896044618658097711785492504343953926634992332820282019728792003956564819968", "115792089237316195423570985008687907853269984665640564039457584007913129639935", "-57896044618658097711785492504343953926634992332820282019728792003956564819969"}, // 2^255 ^ MAX_INT256 + {"5", "1", "4"}, // 0101 ^ 0001 = 0100 + {"-1", "1", "-2"}, // 1111...1111 ^ 0000...0001 = 1111...1110 + {"-5", "3", "-8"}, // 1111...1011 ^ 0000...0011 = 1111...1000 + {TWO_POW_128, TWO_POW_128, "0"}, // 2^128 ^ 2^128 = 0 + {MAX_UINT256, TWO_POW_128, MINUS_TWO_POW_128_MINUS_1}, // MAX_INT256 ^ 2^128 + {TWO_POW_255, MAX_UINT256, MIN_INT256_MINUS_1}, // 2^255 ^ MAX_INT256 } for _, tt := range tests { @@ -111,10 +114,10 @@ func TestBitwise_Rsh(t *testing.T) { }{ {"5", 1, "2"}, // 0101 >> 1 = 0010 {"42", 3, "5"}, // 00101010 >> 3 = 00000101 - {"340282366920938463463374607431768211456", 128, "1"}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639935", 255, "1"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819968", 254, "2"}, - {"-340282366920938463463374607431768211456", 128, "340282366920938463463374607431768211455"}, + {TWO_POW_128, 128, "1"}, + {MAX_UINT256, 255, "1"}, + {TWO_POW_255, 254, "2"}, + {MINUS_TWO_POW_128, 128, TWO_POW_128_MINUS_1}, } for _, tt := range tests { @@ -135,11 +138,11 @@ func TestBitwise_Lsh(t *testing.T) { n uint want string }{ - {"5", 2, "20"}, // 0101 << 2 = 10100 - {"42", 5, "1344"}, // 00101010 << 5 = 10101000000 - {"1", 128, "340282366920938463463374607431768211456"}, // 1 << 128 = 2^128 - {"2", 254, "57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 2 << 254 = 2^255 - {"1", 255, "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, // 1 << 255 = MIN_INT256 (overflow) + {"5", 2, "20"}, // 0101 << 2 = 10100 + {"42", 5, "1344"}, // 00101010 << 5 = 10101000000 + {"1", 128, TWO_POW_128}, // 1 << 128 = 2^128 + {"2", 254, TWO_POW_255}, + {"1", 255, MIN_INT256}, // 1 << 255 = MIN_INT256 (overflow) } for _, tt := range tests { diff --git a/examples/gno.land/p/demo/int256/conversion_test.gno b/examples/gno.land/p/demo/int256/conversion_test.gno index 68fd3486ff5..44e59fe79de 100644 --- a/examples/gno.land/p/demo/int256/conversion_test.gno +++ b/examples/gno.land/p/demo/int256/conversion_test.gno @@ -180,7 +180,7 @@ func TestSetUint256(t *testing.T) { } } -func TestToString(t *testing.T) { +func TestString(t *testing.T) { tests := []struct { input string expected string @@ -192,10 +192,10 @@ func TestToString(t *testing.T) { {"-123456789", "-123456789"}, {"18446744073709551615", "18446744073709551615"}, // max uint64 {"-18446744073709551615", "-18446744073709551615"}, - {"340282366920938463463374607431768211455", "340282366920938463463374607431768211455"}, // max uint128 - {"-340282366920938463463374607431768211455", "-340282366920938463463374607431768211455"}, - {"-57896044618658097711785492504343953926634992332820282019728792003956564819968", "-57896044618658097711785492504343953926634992332820282019728792003956564819968"}, - {"57896044618658097711785492504343953926634992332820282019728792003956564819967", "57896044618658097711785492504343953926634992332820282019728792003956564819967"}, + {TWO_POW_128_MINUS_1, TWO_POW_128_MINUS_1}, + {MINUS_TWO_POW_128, MINUS_TWO_POW_128}, + {MIN_INT256, MIN_INT256}, + {MAX_INT256, MAX_INT256}, } for _, tt := range tests {