int256.gno
3.24 Kb ยท 129 lines
1package int256
2
3import (
4 "errors"
5
6 "gno.land/p/demo/uint256"
7)
8
9var (
10 int1 = NewInt(1)
11 uint0 = uint256.NewUint(0)
12 uint1 = uint256.NewUint(1)
13)
14
15type Int struct {
16 value uint256.Uint
17}
18
19// New creates and returns a new Int initialized to zero.
20func New() *Int {
21 return &Int{}
22}
23
24// NewInt allocates and returns a new Int set to the value of the provided int64.
25func NewInt(x int64) *Int {
26 return New().SetInt64(x)
27}
28
29// Zero returns a new Int initialized to 0.
30//
31// This function is useful for creating a starting point for calculations or
32// when an explicit zero value is needed.
33func Zero() *Int { return &Int{} }
34
35// One returns a new Int initialized to one.
36//
37// This function is convenient for operations that require a unit value,
38// such as incrementing or serving as an identity element in multiplication.
39func One() *Int {
40 return &Int{
41 value: *uint256.NewUint(1),
42 }
43}
44
45// Sign determines the sign of the Int.
46//
47// It returns -1 for negative numbers, 0 for zero, and +1 for positive numbers.
48func (z *Int) Sign() int {
49 if z == nil || z.IsZero() {
50 return 0
51 }
52 // Right shift the value by 255 bits to check the sign bit.
53 // In two's complement representation, the most significant bit (MSB) is the sign bit.
54 // If the MSB is 0, the number is positive; if it is 1, the number is negative.
55 //
56 // Example:
57 // Original value: 1 0 1 0 ... 0 1 (256 bits)
58 // After Rsh 255: 0 0 0 0 ... 0 1 (1 bit)
59 //
60 // This approach is highly efficient as it avoids the need for comparisons
61 // or arithmetic operations on the full 256-bit number. Instead it reduces
62 // the problem to checking a single bit.
63 //
64 // Additionally, this method will work correctly for all values,
65 // including the minimum possible negative number (which in two's complement
66 // doesn't have a positive counterpart in the same bit range).
67 var temp uint256.Uint
68 if temp.Rsh(&z.value, 255).IsZero() {
69 return 1
70 }
71 return -1
72}
73
74// FromDecimal creates a new Int from a decimal string representation.
75// It handles both positive and negative values.
76//
77// This function is useful for parsing user input or reading numeric data
78// from text-based formats.
79func FromDecimal(s string) (*Int, error) {
80 return New().SetString(s)
81}
82
83// MustFromDecimal is similar to FromDecimal but panics if the input string
84// is not a valid decimal representation.
85func MustFromDecimal(s string) *Int {
86 z, err := FromDecimal(s)
87 if err != nil {
88 panic(err)
89 }
90 return z
91}
92
93// SetString sets the Int to the value represented by the input string.
94// This method supports decimal string representations of integers and handles
95// both positive and negative values.
96func (z *Int) SetString(s string) (*Int, error) {
97 if len(s) == 0 {
98 return nil, errors.New("cannot set int256 from empty string")
99 }
100
101 // Check for negative sign
102 neg := s[0] == '-'
103 if neg || s[0] == '+' {
104 s = s[1:]
105 }
106
107 // Convert string to uint256
108 temp, err := uint256.FromDecimal(s)
109 if err != nil {
110 return nil, err
111 }
112
113 // If negative, negate the uint256 value
114 if neg {
115 temp.Neg(temp)
116 }
117
118 z.value.Set(temp)
119 return z, nil
120}
121
122// FromUint256 sets the Int to the value of the provided Uint256.
123//
124// This method allows for conversion from unsigned 256-bit integers
125// to signed integers.
126func (z *Int) FromUint256(v *uint256.Uint) *Int {
127 z.value.Set(v)
128 return z
129}