Skip to content

Commit

Permalink
feat(u128): saturating add and sub
Browse files Browse the repository at this point in the history
  • Loading branch information
failfmi committed Sep 27, 2023
1 parent 8abeec4 commit 9fe57ae
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 20 deletions.
20 changes: 20 additions & 0 deletions math.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ func SaturatingAddU64(a, b U64) U64 {
return U64(sum)
}

func SaturatingAddU128(a, b U128) U128 {
sumLow, carry := bits.Add64(uint64(a[0]), uint64(b[0]), 0)
sumHigh, overflow := bits.Add64(uint64(a[1]), uint64(b[1]), carry)
// check for overflow
if overflow == 1 || (carry == 1 && sumHigh <= uint64(a[1]) && sumHigh <= uint64(b[1])) {
return MaxU128()
}
return U128{U64(sumLow), U64(sumHigh)}
}

func SaturatingSubU64(a, b U64) U64 {
diff, borrow := bits.Sub64(uint64(a), uint64(b), 0)
if borrow != 0 {
Expand All @@ -110,6 +120,16 @@ func SaturatingSubU64(a, b U64) U64 {
return U64(diff)
}

func SaturatingSubU128(a, b U128) U128 {
low, borrow := bits.Sub64(uint64(a[0]), uint64(b[0]), 0)
high, _ := bits.Sub64(uint64(a[1]), uint64(b[1]), borrow)
// check for underflow
if borrow == 1 || high > uint64(a[1]) {
return U128{0, 0}
}
return U128{U64(low), U64(high)}
}

func SaturatingMulU64(a, b U64) U64 {
if a == 0 || b == 0 {
return U64(0)
Expand Down
40 changes: 40 additions & 0 deletions math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,26 @@ func Test_SaturatingAddU64(t *testing.T) {
}
}

func Test_SaturatingAddU128(t *testing.T) {
testExamples := []struct {
label string
a U128
b U128
expect U128
}{
{"2 + 1", NewU128(2), NewU128(1), NewU128(3)},
{"MaxU128+1", MaxU128(), NewU128(1), MaxU128()},
{"MaxU128+MaxU128", MaxU128(), MaxU128(), MaxU128()},
}

for _, testExample := range testExamples {
t.Run(testExample.label, func(t *testing.T) {
result := SaturatingAddU128(testExample.a, testExample.b)
assert.Equal(t, testExample.expect, result)
})
}
}

func Test_SaturatingSubU64(t *testing.T) {
testExamples := []struct {
label string
Expand All @@ -192,6 +212,26 @@ func Test_SaturatingSubU64(t *testing.T) {
}
}

func Test_SaturatingSubU128(t *testing.T) {
testExamples := []struct {
label string
a U128
b U128
expect U128
}{
{"2-1", NewU128(2), NewU128(1), NewU128(1)},
{"0-1", NewU128(0), NewU128(1), NewU128(0)},
{"0-MaxU128", NewU128(0), MaxU128(), NewU128(0)},
}

for _, testExample := range testExamples {
t.Run(testExample.label, func(t *testing.T) {
result := SaturatingSubU128(testExample.a, testExample.b)
assert.Equal(t, testExample.expect, result)
})
}
}

func Test_SaturatingMul(t *testing.T) {
testExamples := []struct {
label string
Expand Down
20 changes: 0 additions & 20 deletions u128.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,26 +101,6 @@ func (n U128) Gte(other U128) bool {
return n.ToBigInt().Cmp(other.ToBigInt()) >= 0
}

//func (n U128) SaturatingAdd(other U128) U128 {
// sumLow, carry := bits.Add64(uint64(n[0]), uint64(other[0]), 0)
// sumHigh, overflow := bits.Add64(uint64(n[1]), uint64(other[1]), carry)
// // check for overflow
// if overflow == 1 || (carry == 1 && sumHigh <= uint64(n[1]) && sumHigh <= uint64(other[1])) {
// return MaxU128()
// }
// return U128{U64(sumLow), U64(sumHigh)}
//}
//
//func (n U128) SaturatingSub(other U128) U128 {
// low, borrow := bits.Sub64(uint64(n[0]), uint64(other[0]), 0)
// high, _ := bits.Sub64(uint64(n[1]), uint64(other[1]), borrow)
// // check for underflow
// if borrow == 1 || high > uint64(n[1]) {
// return U128{0, 0}
// }
// return U128{U64(low), U64(high)}
//}
//
//func (n U128) SaturatingMul(other U128) U128 {
// result := new(big.Int).Mul(n.ToBigInt(), other.ToBigInt())
// // check for overflow
Expand Down

0 comments on commit 9fe57ae

Please sign in to comment.