From c4605cc4c30e4eeee29662265dfa852d58a96549 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Thu, 18 Jan 2024 18:51:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20huge=20=E5=8C=85=20NewInt=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=94=AF=E6=8C=81=20string=E3=80=81bool=E3=80=81float?= =?UTF-8?q?=20=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/huge/int.go | 67 ++++++++++++++++++++++++++++++++-------- utils/huge/int_test.go | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 12 deletions(-) create mode 100644 utils/huge/int_test.go diff --git a/utils/huge/int.go b/utils/huge/int.go index 68db831e..b46bf541 100644 --- a/utils/huge/int.go +++ b/utils/huge/int.go @@ -17,33 +17,70 @@ var ( type Int big.Int -// NewInt 创建一个 Int -func NewInt[T generic.Number](x T) *Int { - return (*Int)(big.NewInt(int64(x))) -} - -// NewIntByString 通过字符串创建一个 Int -// - 如果字符串不是一个合法的数字,则返回 0 -func NewIntByString(i string) *Int { - v, suc := new(big.Int).SetString(i, 10) - if !suc { - return IntZero.Copy() +// NewInt 创建一个 Int 对象,该对象的值为 x +func NewInt[T generic.Basic](x T) *Int { + var xa any = x + switch x := xa.(type) { + case int: + return (*Int)(big.NewInt(int64(x))) + case int8: + return (*Int)(big.NewInt(int64(x))) + case int16: + return (*Int)(big.NewInt(int64(x))) + case int32: + return (*Int)(big.NewInt(int64(x))) + case int64: + return (*Int)(big.NewInt(x)) + case uint: + return (*Int)(big.NewInt(int64(x))) + case uint8: + return (*Int)(big.NewInt(int64(x))) + case uint16: + return (*Int)(big.NewInt(int64(x))) + case uint32: + return (*Int)(big.NewInt(int64(x))) + case uint64: + return (*Int)(big.NewInt(int64(x))) + case string: + si, suc := new(big.Int).SetString(x, 10) + if !suc { + return (*Int)(big.NewInt(0)) + } + return (*Int)(si) + case bool: + if x { + return (*Int)(big.NewInt(1)) + } + return (*Int)(big.NewInt(0)) + case float32: + return (*Int)(big.NewInt(int64(x))) + case float64: + return (*Int)(big.NewInt(int64(x))) } - return (*Int)(v) + return (*Int)(big.NewInt(0)) } +// applyIntOperation 应用一个 Int 操作 func applyIntOperation[T generic.Number](v *Int, i T, op func(*big.Int, *big.Int) *big.Int) *Int { return (*Int)(op(v.ToBigint(), NewInt(i).ToBigint())) } +// Copy 拷贝当前 Int 对象 func (slf *Int) Copy() *Int { return (*Int)(new(big.Int).Set(slf.ToBigint())) } +// Set 设置当前 Int 对象的值为 i func (slf *Int) Set(i *Int) *Int { return (*Int)(slf.ToBigint().Set(i.ToBigint())) } +// SetString 设置当前 Int 对象的值为 i +func (slf *Int) SetString(i string) *Int { + return (*Int)(slf.ToBigint().Set((*big.Int)(NewInt(i)))) +} + +// SetInt 设置当前 Int 对象的值为 i func (slf *Int) SetInt(i int) *Int { return (*Int)(slf.ToBigint().Set((*big.Int)(NewInt(i)))) } @@ -92,6 +129,9 @@ func (slf *Int) IsZero() bool { } func (slf *Int) ToBigint() *big.Int { + if slf == nil { + return big.NewInt(0) + } return (*big.Int)(slf) } @@ -130,6 +170,9 @@ func (slf *Int) Int64() int64 { } func (slf *Int) String() string { + if slf == nil { + return "0" + } return slf.ToBigint().String() } diff --git a/utils/huge/int_test.go b/utils/huge/int_test.go new file mode 100644 index 00000000..cfdc4d84 --- /dev/null +++ b/utils/huge/int_test.go @@ -0,0 +1,69 @@ +package huge_test + +import ( + "github.com/kercylan98/minotaur/utils/huge" + "testing" +) + +func TestNewInt(t *testing.T) { + var cases = []struct { + name string + nil bool + in int64 + mul int64 + want string + }{ + {name: "TestNewIntNegative", in: -1, want: "-1"}, + {name: "TestNewIntZero", in: 0, want: "0"}, + {name: "TestNewIntPositive", in: 1, want: "1"}, + {name: "TestNewIntMax", in: 9223372036854775807, want: "9223372036854775807"}, + {name: "TestNewIntMin", in: -9223372036854775808, want: "-9223372036854775808"}, + {name: "TestNewIntMulNegative", in: -9223372036854775808, mul: 10000000, want: "-92233720368547758080000000"}, + {name: "TestNewIntMulPositive", in: 9223372036854775807, mul: 10000000, want: "92233720368547758070000000"}, + {name: "TestNewIntNil", nil: true, want: "0"}, + {name: "TestNewIntNilMul", nil: true, mul: 10000000, want: "0"}, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + var got *huge.Int + switch { + case c.nil: + if c.mul > 0 { + got = huge.NewInt(0).MulInt64(c.mul) + } + case c.mul == 0: + got = huge.NewInt(c.in) + default: + got = huge.NewInt(c.in).MulInt64(c.mul) + } + if s := got.String(); s != c.want { + t.Errorf("want: %s, got: %s", c.want, got.String()) + } else { + t.Log(s) + } + }) + } + + // other + t.Run("TestNewIntFromString", func(t *testing.T) { + if got := huge.NewInt("1234567890123456789012345678901234567890"); got.String() != "1234567890123456789012345678901234567890" { + t.Fatalf("want: %s, got: %s", "1234567890123456789012345678901234567890", got.String()) + } + }) + t.Run("TestNewIntFromInt", func(t *testing.T) { + if got := huge.NewInt(1234567890); got.String() != "1234567890" { + t.Fatalf("want: %s, got: %s", "1234567890", got.String()) + } + }) + t.Run("TestNewIntFromBool", func(t *testing.T) { + if got := huge.NewInt(true); got.String() != "1" { + t.Fatalf("want: %s, got: %s", "1", got.String()) + } + }) + t.Run("TestNewIntFromFloat", func(t *testing.T) { + if got := huge.NewInt(1234567890.1234567890); got.String() != "1234567890" { + t.Fatalf("want: %s, got: %s", "1234567890", got.String()) + } + }) +}