Skip to content

Commit 487c5cc

Browse files
committed
Added WIP number package
1 parent ee9df32 commit 487c5cc

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed

ethutil/number/int.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package number
2+
3+
import (
4+
"math/big"
5+
6+
"github.com/ethereum/go-ethereum/ethutil"
7+
)
8+
9+
var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
10+
var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
11+
var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
12+
13+
func limitUnsigned256(x *Number) *Number {
14+
x.num.And(x.num, tt256m1)
15+
return x
16+
}
17+
18+
func limitSigned256(x *Number) *Number {
19+
if x.num.Cmp(tt255) < 0 {
20+
return x
21+
} else {
22+
x.num.Sub(x.num, tt256)
23+
return x
24+
}
25+
}
26+
27+
// Number function
28+
type Initialiser func(n int64) *Number
29+
30+
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
31+
// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda
32+
// with the new Initialiser.
33+
type Number struct {
34+
num *big.Int
35+
limit func(n *Number) *Number
36+
}
37+
38+
// Returns a new initialiser for a new *Number without having to expose certain fields
39+
func NewInitialiser(limiter func(*Number) *Number) Initialiser {
40+
return func(n int64) *Number {
41+
return &Number{big.NewInt(n), limiter}
42+
}
43+
}
44+
45+
// Return a Number with a UNSIGNED limiter up to 256 bits
46+
func Uint256(n int64) *Number {
47+
return &Number{big.NewInt(n), limitUnsigned256}
48+
}
49+
50+
// Return a Number with a SIGNED limiter up to 256 bits
51+
func Int256(n int64) *Number {
52+
return &Number{big.NewInt(n), limitSigned256}
53+
}
54+
55+
// Returns a Number with a SIGNED unlimited size
56+
func Big(n int64) *Number {
57+
return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
58+
}
59+
60+
// Sets i to sum of x+y
61+
func (i *Number) Add(x, y *Number) *Number {
62+
i.num.Add(x.num, y.num)
63+
return i.limit(i)
64+
}
65+
66+
// Sets i to difference of x-y
67+
func (i *Number) Sub(x, y *Number) *Number {
68+
i.num.Sub(x.num, y.num)
69+
return i.limit(i)
70+
}
71+
72+
// Sets i to product of x*y
73+
func (i *Number) Mul(x, y *Number) *Number {
74+
i.num.Mul(x.num, y.num)
75+
return i.limit(i)
76+
}
77+
78+
// Sets i to the quotient prodject of x/y
79+
func (i *Number) Div(x, y *Number) *Number {
80+
i.num.Div(x.num, y.num)
81+
return i.limit(i)
82+
}
83+
84+
// Sets i to x % y
85+
func (i *Number) Mod(x, y *Number) *Number {
86+
i.num.Mod(x.num, y.num)
87+
return i.limit(i)
88+
}
89+
90+
// Sets i to x << s
91+
func (i *Number) Lsh(x *Number, s uint) *Number {
92+
i.num.Lsh(x.num, s)
93+
return i.limit(i)
94+
}
95+
96+
// Sets i to x^y
97+
func (i *Number) Pow(x, y *Number) *Number {
98+
i.num.Exp(x.num, y.num, big.NewInt(0))
99+
return i.limit(i)
100+
}
101+
102+
// Setters
103+
104+
// Set x to i
105+
func (i *Number) Set(x *Number) *Number {
106+
i.num.Set(x.num)
107+
return i.limit(i)
108+
}
109+
110+
// Set x bytes to i
111+
func (i *Number) SetBytes(x []byte) *Number {
112+
i.num.SetBytes(x)
113+
return i.limit(i)
114+
}
115+
116+
// Cmp compares x and y and returns:
117+
//
118+
// -1 if x < y
119+
// 0 if x == y
120+
// +1 if x > y
121+
func (i *Number) Cmp(x *Number) int {
122+
return i.num.Cmp(x.num)
123+
}
124+
125+
// Getters
126+
127+
// Returns the string representation of i
128+
func (i *Number) String() string {
129+
return i.num.String()
130+
}
131+
132+
// Returns the byte representation of i
133+
func (i *Number) Bytes() []byte {
134+
return i.num.Bytes()
135+
}
136+
137+
// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined.
138+
func (i *Number) Uint64() uint64 {
139+
return i.num.Uint64()
140+
}
141+
142+
// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined.
143+
func (i *Number) Int64() int64 {
144+
return i.num.Int64()
145+
}
146+
147+
// Returns the signed version of i
148+
func (i *Number) Int256() *Number {
149+
return Int(0).Set(i)
150+
}
151+
152+
// Returns the unsigned version of i
153+
func (i *Number) Uint256() *Number {
154+
return Uint(0).Set(i)
155+
}
156+
157+
// Returns the index of the first bit that's set to 1
158+
func (i *Number) FirstBitSet() int {
159+
for j := 0; j < i.num.BitLen(); j++ {
160+
if i.num.Bit(j) > 0 {
161+
return j
162+
}
163+
}
164+
165+
return i.num.BitLen()
166+
}
167+
168+
// Variables
169+
170+
var (
171+
Zero = Uint(0)
172+
One = Uint(1)
173+
Two = Uint(2)
174+
MaxUint256 = Uint(0).SetBytes(ethutil.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
175+
176+
MinOne = Int(-1)
177+
178+
// "typedefs"
179+
Uint = Uint256
180+
Int = Int256
181+
)

ethutil/number/uint_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package number
2+
3+
import (
4+
"math/big"
5+
"testing"
6+
7+
"github.com/ethereum/go-ethereum/ethutil"
8+
)
9+
10+
func TestSet(t *testing.T) {
11+
a := Uint(0)
12+
b := Uint(10)
13+
a.Set(b)
14+
if a.num.Cmp(b.num) != 0 {
15+
t.Error("didn't compare", a, b)
16+
}
17+
18+
c := Uint(0).SetBytes(ethutil.Hex2Bytes("0a"))
19+
if c.num.Cmp(big.NewInt(10)) != 0 {
20+
t.Error("c set bytes failed.")
21+
}
22+
}
23+
24+
func TestInitialiser(t *testing.T) {
25+
check := false
26+
init := NewInitialiser(func(x *Number) *Number {
27+
check = true
28+
return x
29+
})
30+
a := init(0).Add(init(1), init(2))
31+
if a.Cmp(init(3)) != 0 {
32+
t.Error("expected 3. got", a)
33+
}
34+
if !check {
35+
t.Error("expected limiter to be called")
36+
}
37+
}
38+
39+
func TestGet(t *testing.T) {
40+
a := Uint(10)
41+
if a.Uint64() != 10 {
42+
t.Error("expected to get 10. got", a.Uint64())
43+
}
44+
45+
a = Uint(10)
46+
if a.Int64() != 10 {
47+
t.Error("expected to get 10. got", a.Int64())
48+
}
49+
}
50+
51+
func TestCmp(t *testing.T) {
52+
a := Uint(10)
53+
b := Uint(10)
54+
c := Uint(11)
55+
56+
if a.Cmp(b) != 0 {
57+
t.Error("a b == 0 failed", a, b)
58+
}
59+
60+
if a.Cmp(c) >= 0 {
61+
t.Error("a c < 0 failed", a, c)
62+
}
63+
64+
if c.Cmp(b) <= 0 {
65+
t.Error("c b > 0 failed", c, b)
66+
}
67+
}
68+
69+
func TestMaxArith(t *testing.T) {
70+
a := Uint(0).Add(MaxUint256, One)
71+
if a.Cmp(Zero) != 0 {
72+
t.Error("expected max256 + 1 = 0 got", a)
73+
}
74+
75+
a = Uint(0).Sub(Uint(0), One)
76+
if a.Cmp(MaxUint256) != 0 {
77+
t.Error("expected 0 - 1 = max256 got", a)
78+
}
79+
80+
a = Int(0).Sub(Int(0), One)
81+
if a.Cmp(MinOne) != 0 {
82+
t.Error("expected 0 - 1 = -1 got", a)
83+
}
84+
}
85+
86+
func TestConversion(t *testing.T) {
87+
a := Int(-1)
88+
b := a.Uint256()
89+
if b.Cmp(MaxUint256) != 0 {
90+
t.Error("expected -1 => unsigned to return max. got", b)
91+
}
92+
}

0 commit comments

Comments
 (0)