mirror of
https://github.com/metabarcoding/obitools4.git
synced 2025-06-29 16:20:46 +00:00
Patch a bug on writing to stdout, and add clearer error on openning data files
This commit is contained in:
289
pkg/obifp/uint128.go
Normal file
289
pkg/obifp/uint128.go
Normal file
@ -0,0 +1,289 @@
|
||||
package obifp
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Uint128 struct {
|
||||
w1 uint64
|
||||
w0 uint64
|
||||
}
|
||||
|
||||
// Zero returns a zero-valued uint128.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint128 value.
|
||||
func (u Uint128) Zero() Uint128 {
|
||||
return Uint128{w1: 0, w0: 0}
|
||||
}
|
||||
|
||||
// MaxValue returns the maximum possible value for a Uint128.
|
||||
//
|
||||
// It returns a Uint128 value with the highest possible values for high and low fields.
|
||||
func (u Uint128) MaxValue() Uint128 {
|
||||
return Uint128{
|
||||
w1: math.MaxUint64,
|
||||
w0: math.MaxUint64,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// IsZero checks if the Uint128 value is zero.
|
||||
//
|
||||
// It returns a boolean indicating whether the Uint128 value is zero.
|
||||
func (u Uint128) IsZero() bool {
|
||||
return u.w0 == 0 && u.w1 == 0
|
||||
}
|
||||
|
||||
// Cast a Uint128 to a Uint64.
|
||||
//
|
||||
// A Warning will be logged if an overflow occurs.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint64 value.
|
||||
func (u Uint128) Uint64() Uint64 {
|
||||
if u.w1 != 0 {
|
||||
log.Warnf("Uint128 overflow at Uint64(%v)", u)
|
||||
}
|
||||
return Uint64{w0: u.w0}
|
||||
}
|
||||
|
||||
// Uint128 cast a Uint128 to a Uint128.
|
||||
//
|
||||
// Which is a no-op.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint128 value.
|
||||
func (u Uint128) Uint128() Uint128 {
|
||||
return u
|
||||
}
|
||||
|
||||
// Cast a Uint128 to a Uint256.
|
||||
//
|
||||
// A Warning will be logged if an overflow occurs.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint256 value.
|
||||
func (u Uint128) Uint256() Uint256 {
|
||||
return Uint256{0, 0, u.w1, u.w0}
|
||||
}
|
||||
|
||||
func (u Uint128) Set64(v uint64) Uint128 {
|
||||
|
||||
return Uint128{
|
||||
w1: 0,
|
||||
w0: v,
|
||||
}
|
||||
}
|
||||
|
||||
// LeftShift performs a left shift operation on the Uint128 value by the specified number of bits.
|
||||
//
|
||||
// Parameters:
|
||||
// - n: the number of bits to shift the Uint128 value to the left.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint128: the result of the left shift operation.
|
||||
func (u Uint128) LeftShift(n uint) Uint128 {
|
||||
lo, carry := Uint64{w0: u.w0}.LeftShift64(n, 0)
|
||||
hi, _ := Uint64{w0: u.w1}.LeftShift64(n, carry)
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
// RightShift performs a right shift operation on the Uint128 value by the specified number of bits.
|
||||
//
|
||||
// Parameters:
|
||||
// - n: the number of bits to shift the Uint128 value to the right.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint128: the result of the right shift operation.
|
||||
func (u Uint128) RightShift(n uint) Uint128 {
|
||||
hi, carry := Uint64{w0: u.w1}.RightShift64(n, 0)
|
||||
lo, _ := Uint64{w0: u.w0}.RightShift64(n, carry)
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
// Add performs addition of two Uint128 values and returns the result.
|
||||
//
|
||||
// Parameters:
|
||||
// - v: the Uint128 value to add to the receiver.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint128: the result of the addition.
|
||||
func (u Uint128) Add(v Uint128) Uint128 {
|
||||
lo, carry := bits.Add64(u.w0, v.w0, 0)
|
||||
hi, carry := bits.Add64(u.w1, v.w1, carry)
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint128 overflow at Add(%v, %v)", u, v)
|
||||
}
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
func (u Uint128) Add64(v uint64) Uint128 {
|
||||
lo, carry := bits.Add64(u.w0, v, 0)
|
||||
hi, carry := bits.Add64(u.w1, 0, carry)
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint128 overflow at Add64(%v, %v)", u, v)
|
||||
}
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
func (u Uint128) Sub(v Uint128) Uint128 {
|
||||
lo, borrow := bits.Sub64(u.w0, v.w0, 0)
|
||||
hi, borrow := bits.Sub64(u.w1, v.w1, borrow)
|
||||
if borrow != 0 {
|
||||
log.Panicf("Uint128 underflow at Sub(%v, %v)", u, v)
|
||||
}
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
func (u Uint128) Mul(v Uint128) Uint128 {
|
||||
hi, lo := bits.Mul64(u.w0, v.w0)
|
||||
p0, p1 := bits.Mul64(u.w1, v.w0)
|
||||
p2, p3 := bits.Mul64(u.w0, v.w1)
|
||||
hi, c0 := bits.Add64(hi, p1, 0)
|
||||
hi, c1 := bits.Add64(hi, p3, c0)
|
||||
if (u.w1 != 0 && v.w1 != 0) || p0 != 0 || p2 != 0 || c1 != 0 {
|
||||
log.Panicf("Uint128 overflow at Mul(%v, %v)", u, v)
|
||||
}
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
func (u Uint128) Mul64(v uint64) Uint128 {
|
||||
hi, lo := bits.Mul64(u.w0, v)
|
||||
p0, p1 := bits.Mul64(u.w1, v)
|
||||
hi, c0 := bits.Add64(hi, p1, 0)
|
||||
if p0 != 0 || c0 != 0 {
|
||||
log.Panicf("Uint128 overflow at Mul64(%v, %v)", u, v)
|
||||
}
|
||||
return Uint128{w1: hi, w0: lo}
|
||||
}
|
||||
|
||||
func (u Uint128) QuoRem(v Uint128) (q, r Uint128) {
|
||||
if v.w1 == 0 {
|
||||
var r64 uint64
|
||||
q, r64 = u.QuoRem64(v.w0)
|
||||
r = Uint128{w1: 0, w0: r64}
|
||||
} else {
|
||||
// generate a "trial quotient," guaranteed to be within 1 of the actual
|
||||
// quotient, then adjust.
|
||||
n := uint(bits.LeadingZeros64(v.w1))
|
||||
v1 := v.LeftShift(n)
|
||||
u1 := u.RightShift(1)
|
||||
tq, _ := bits.Div64(u1.w1, u1.w0, v1.w1)
|
||||
tq >>= 63 - n
|
||||
if tq != 0 {
|
||||
tq--
|
||||
}
|
||||
q = Uint128{w1: 0, w0: tq}
|
||||
// calculate remainder using trial quotient, then adjust if remainder is
|
||||
// greater than divisor
|
||||
r = u.Sub(v.Mul64(tq))
|
||||
if r.Cmp(v) >= 0 {
|
||||
q = q.Add64(1)
|
||||
r = r.Sub(v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// QuoRem64 returns q = u/v and r = u%v.
|
||||
func (u Uint128) QuoRem64(v uint64) (q Uint128, r uint64) {
|
||||
if u.w1 < v {
|
||||
q.w0, r = bits.Div64(u.w1, u.w0, v)
|
||||
} else {
|
||||
q.w1, r = bits.Div64(0, u.w1, v)
|
||||
q.w0, r = bits.Div64(r, u.w0, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (u Uint128) Div(v Uint128) Uint128 {
|
||||
q, _ := u.QuoRem(v)
|
||||
return q
|
||||
}
|
||||
|
||||
func (u Uint128) Div64(v uint64) Uint128 {
|
||||
q, _ := u.QuoRem64(v)
|
||||
return q
|
||||
}
|
||||
|
||||
func (u Uint128) Mod(v Uint128) Uint128 {
|
||||
_, r := u.QuoRem(v)
|
||||
return r
|
||||
}
|
||||
|
||||
func (u Uint128) Mod64(v uint64) uint64 {
|
||||
_, r := u.QuoRem64(v)
|
||||
return r
|
||||
}
|
||||
|
||||
func (u Uint128) Cmp(v Uint128) int {
|
||||
switch {
|
||||
case u.w1 > v.w1:
|
||||
return 1
|
||||
case u.w1 < v.w1:
|
||||
return -1
|
||||
case u.w0 > v.w0:
|
||||
return 1
|
||||
case u.w0 < v.w0:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint128) Cmp64(v uint64) int {
|
||||
switch {
|
||||
case u.w1 > 0:
|
||||
return 1
|
||||
case u.w0 > v:
|
||||
return 1
|
||||
case u.w0 < v:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint128) Equals(v Uint128) bool {
|
||||
return u.Cmp(v) == 0
|
||||
}
|
||||
|
||||
func (u Uint128) LessThan(v Uint128) bool {
|
||||
return u.Cmp(v) < 0
|
||||
}
|
||||
|
||||
func (u Uint128) GreaterThan(v Uint128) bool {
|
||||
return u.Cmp(v) > 0
|
||||
}
|
||||
|
||||
func (u Uint128) LessThanOrEqual(v Uint128) bool {
|
||||
return !u.GreaterThan(v)
|
||||
}
|
||||
|
||||
func (u Uint128) GreaterThanOrEqual(v Uint128) bool {
|
||||
return !u.LessThan(v)
|
||||
}
|
||||
|
||||
func (u Uint128) And(v Uint128) Uint128 {
|
||||
return Uint128{w1: u.w1 & v.w1, w0: u.w0 & v.w0}
|
||||
}
|
||||
|
||||
func (u Uint128) Or(v Uint128) Uint128 {
|
||||
return Uint128{w1: u.w1 | v.w1, w0: u.w0 | v.w0}
|
||||
}
|
||||
|
||||
func (u Uint128) Xor(v Uint128) Uint128 {
|
||||
return Uint128{w1: u.w1 ^ v.w1, w0: u.w0 ^ v.w0}
|
||||
}
|
||||
|
||||
func (u Uint128) Not() Uint128 {
|
||||
return Uint128{w1: ^u.w1, w0: ^u.w0}
|
||||
}
|
||||
|
||||
func (u Uint128) AsUint64() uint64 {
|
||||
return u.w0
|
||||
}
|
307
pkg/obifp/uint256.go
Normal file
307
pkg/obifp/uint256.go
Normal file
@ -0,0 +1,307 @@
|
||||
package obifp
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Uint256 struct {
|
||||
w3 uint64
|
||||
w2 uint64
|
||||
w1 uint64
|
||||
w0 uint64
|
||||
}
|
||||
|
||||
// Zero returns a zero value of type Uint256.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint256 value of 0.
|
||||
func (u Uint256) Zero() Uint256 {
|
||||
return Uint256{}
|
||||
}
|
||||
|
||||
// MaxValue returns the maximum possible value of type Uint256.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns the maximum value of type Uint256.
|
||||
func (u Uint256) MaxValue() Uint256 {
|
||||
return Uint256{
|
||||
w3: math.MaxUint64,
|
||||
w2: math.MaxUint64,
|
||||
w1: math.MaxUint64,
|
||||
w0: math.MaxUint64,
|
||||
}
|
||||
}
|
||||
|
||||
// IsZero checks if the Uint256 value is zero.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a boolean indicating if the value is zero.
|
||||
func (u Uint256) IsZero() bool {
|
||||
return u == Uint256{}
|
||||
}
|
||||
|
||||
// Cast a Uint256 to a Uint64.
|
||||
//
|
||||
// A Warning will be logged if an overflow occurs.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint64 value.
|
||||
func (u Uint256) Uint64() Uint64 {
|
||||
if u.w3 != 0 || u.w2 != 0 || u.w1 != 0 {
|
||||
log.Warnf("Uint256 overflow at Uint64(%v)", u)
|
||||
}
|
||||
return Uint64{w0: u.w0}
|
||||
}
|
||||
|
||||
// Cast a Uint256 to a Uint128.
|
||||
//
|
||||
// A Warning will be logged if an overflow occurs.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint128 value.
|
||||
func (u Uint256) Uint128() Uint128 {
|
||||
if u.w3 != 0 || u.w2 != 0 {
|
||||
log.Warnf("Uint256 overflow at Uint128(%v)", u)
|
||||
}
|
||||
return Uint128{u.w1, u.w0}
|
||||
}
|
||||
|
||||
// Cast a Uint128 to a Uint256.
|
||||
//
|
||||
// A Warning will be logged if an overflow occurs.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint256 value.
|
||||
func (u Uint256) Uint256() Uint256 {
|
||||
return u
|
||||
}
|
||||
|
||||
func (u Uint256) Set64(v uint64) Uint256 {
|
||||
|
||||
return Uint256{
|
||||
w3: 0,
|
||||
w2: 0,
|
||||
w1: 0,
|
||||
w0: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint256) LeftShift(n uint) Uint256 {
|
||||
w0, carry := Uint64{w0: u.w0}.LeftShift64(n, 0)
|
||||
w1, carry := Uint64{w0: u.w1}.LeftShift64(n, carry)
|
||||
w2, carry := Uint64{w0: u.w2}.LeftShift64(n, carry)
|
||||
w3, _ := Uint64{w0: u.w3}.LeftShift64(n, carry)
|
||||
return Uint256{w3, w2, w1, w0}
|
||||
}
|
||||
|
||||
func (u Uint256) RightShift(n uint) Uint256 {
|
||||
w3, carry := Uint64{w0: u.w3}.RightShift64(n, 0)
|
||||
w2, carry := Uint64{w0: u.w2}.RightShift64(n, carry)
|
||||
w1, carry := Uint64{w0: u.w1}.RightShift64(n, carry)
|
||||
w0, _ := Uint64{w0: u.w0}.RightShift64(n, carry)
|
||||
return Uint256{w3, w2, w1, w0}
|
||||
}
|
||||
|
||||
func (u Uint256) Cmp(v Uint256) int {
|
||||
switch {
|
||||
case u.w3 > v.w3:
|
||||
return 1
|
||||
case u.w3 < v.w3:
|
||||
return -1
|
||||
case u.w2 > v.w2:
|
||||
return 1
|
||||
case u.w2 < v.w2:
|
||||
return -1
|
||||
case u.w1 > v.w1:
|
||||
return 1
|
||||
case u.w1 < v.w1:
|
||||
return -1
|
||||
case u.w0 > v.w0:
|
||||
return 1
|
||||
case u.w0 < v.w0:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Add performs addition of two Uint256 values and returns the result.
|
||||
//
|
||||
// Parameters:
|
||||
// - v: the Uint256 value to add to the receiver.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint256: the result of the addition.
|
||||
func (u Uint256) Add(v Uint256) Uint256 {
|
||||
w0, carry := bits.Add64(u.w0, v.w0, 0)
|
||||
w1, carry := bits.Add64(u.w1, v.w1, carry)
|
||||
w2, carry := bits.Add64(u.w2, v.w2, carry)
|
||||
w3, carry := bits.Add64(u.w3, v.w3, carry)
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint256 overflow at Add(%v, %v)", u, v)
|
||||
}
|
||||
return Uint256{w3, w2, w1, w0}
|
||||
}
|
||||
|
||||
// Sub performs subtraction of two Uint256 values and returns the result.
|
||||
//
|
||||
// Parameters:
|
||||
// - v: the Uint256 value to subtract from the receiver.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint256: the result of the subtraction.
|
||||
func (u Uint256) Sub(v Uint256) Uint256 {
|
||||
w0, borrow := bits.Sub64(u.w0, v.w0, 0)
|
||||
w1, borrow := bits.Sub64(u.w1, v.w1, borrow)
|
||||
w2, borrow := bits.Sub64(u.w2, v.w2, borrow)
|
||||
w3, borrow := bits.Sub64(u.w3, v.w3, borrow)
|
||||
if borrow != 0 {
|
||||
log.Panicf("Uint256 overflow at Sub(%v, %v)", u, v)
|
||||
}
|
||||
return Uint256{w3, w2, w1, w0}
|
||||
}
|
||||
|
||||
// Mul performs multiplication of two Uint256 values and returns the result.
|
||||
//
|
||||
// Parameters:
|
||||
// - v: the Uint256 value to multiply with the receiver.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint256: the result of the multiplication.
|
||||
func (u Uint256) Mul(v Uint256) Uint256 {
|
||||
var w0, w1, w2, w3, carry uint64
|
||||
|
||||
w0Low, w0High := bits.Mul64(u.w0, v.w0)
|
||||
w1Low1, w1High1 := bits.Mul64(u.w0, v.w1)
|
||||
w1Low2, w1High2 := bits.Mul64(u.w1, v.w0)
|
||||
w2Low1, w2High1 := bits.Mul64(u.w0, v.w2)
|
||||
w2Low2, w2High2 := bits.Mul64(u.w1, v.w1)
|
||||
w2Low3, w2High3 := bits.Mul64(u.w2, v.w0)
|
||||
w3Low1, w3High1 := bits.Mul64(u.w0, v.w3)
|
||||
w3Low2, w3High2 := bits.Mul64(u.w1, v.w2)
|
||||
w3Low3, w3High3 := bits.Mul64(u.w2, v.w1)
|
||||
w3Low4, w3High4 := bits.Mul64(u.w3, v.w0)
|
||||
|
||||
w0 = w0Low
|
||||
|
||||
w1, carry = bits.Add64(w1Low1, w1Low2, 0)
|
||||
w1, _ = bits.Add64(w1, w0High, carry)
|
||||
|
||||
w2, carry = bits.Add64(w2Low1, w2Low2, 0)
|
||||
w2, carry = bits.Add64(w2, w2Low3, carry)
|
||||
w2, carry = bits.Add64(w2, w1High1, carry)
|
||||
w2, _ = bits.Add64(w2, w1High2, carry)
|
||||
|
||||
w3, carry = bits.Add64(w3Low1, w3Low2, 0)
|
||||
w3, carry = bits.Add64(w3, w3Low3, carry)
|
||||
w3, carry = bits.Add64(w3, w3Low4, carry)
|
||||
w3, carry = bits.Add64(w3, w2High1, carry)
|
||||
w3, carry = bits.Add64(w3, w2High2, carry)
|
||||
w3, carry = bits.Add64(w3, w2High3, carry)
|
||||
|
||||
if w3High1 != 0 || w3High2 != 0 || w3High3 != 0 || w3High4 != 0 || carry != 0 {
|
||||
log.Panicf("Uint256 overflow at Mul(%v, %v)", u, v)
|
||||
}
|
||||
|
||||
return Uint256{w3, w2, w1, w0}
|
||||
}
|
||||
|
||||
// Div performs division of two Uint256 values and returns the result.
|
||||
//
|
||||
// Parameters:
|
||||
// - v: the Uint256 value to divide with the receiver.
|
||||
//
|
||||
// Returns:
|
||||
// - Uint256: the result of the division.
|
||||
func (u Uint256) Div(v Uint256) Uint256 {
|
||||
if v.IsZero() {
|
||||
log.Panicf("division by zero")
|
||||
}
|
||||
|
||||
if u.IsZero() || u.LessThan(v) {
|
||||
return Uint256{}
|
||||
}
|
||||
|
||||
if v.Equals(Uint256{0, 0, 0, 1}) {
|
||||
return u // Division by 1
|
||||
}
|
||||
|
||||
var q, r Uint256
|
||||
r = u
|
||||
|
||||
for r.GreaterThanOrEqual(v) {
|
||||
var t Uint256 = v
|
||||
var m Uint256 = Uint256{0, 0, 0, 1}
|
||||
for t.LeftShift(1).LessThanOrEqual(r) {
|
||||
t = t.LeftShift(1)
|
||||
m = m.LeftShift(1)
|
||||
}
|
||||
r = r.Sub(t)
|
||||
q = q.Add(m)
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
func (u Uint256) Equals(v Uint256) bool {
|
||||
return u.Cmp(v) == 0
|
||||
}
|
||||
|
||||
func (u Uint256) LessThan(v Uint256) bool {
|
||||
return u.Cmp(v) < 0
|
||||
}
|
||||
|
||||
func (u Uint256) GreaterThan(v Uint256) bool {
|
||||
return u.Cmp(v) > 0
|
||||
}
|
||||
|
||||
func (u Uint256) LessThanOrEqual(v Uint256) bool {
|
||||
return !u.GreaterThan(v)
|
||||
}
|
||||
|
||||
func (u Uint256) GreaterThanOrEqual(v Uint256) bool {
|
||||
return !u.LessThan(v)
|
||||
}
|
||||
|
||||
func (u Uint256) And(v Uint256) Uint256 {
|
||||
return Uint256{
|
||||
w3: u.w3 & v.w3,
|
||||
w2: u.w2 & v.w2,
|
||||
w1: u.w1 & v.w1,
|
||||
w0: u.w0 & v.w0,
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint256) Or(v Uint256) Uint256 {
|
||||
return Uint256{
|
||||
w3: u.w3 | v.w3,
|
||||
w2: u.w2 | v.w2,
|
||||
w1: u.w1 | v.w1,
|
||||
w0: u.w0 | v.w0,
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint256) Xor(v Uint256) Uint256 {
|
||||
return Uint256{
|
||||
w3: u.w3 ^ v.w3,
|
||||
w2: u.w2 ^ v.w2,
|
||||
w1: u.w1 ^ v.w1,
|
||||
w0: u.w0 ^ v.w0,
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint256) Not() Uint256 {
|
||||
return Uint256{
|
||||
w3: ^u.w3,
|
||||
w2: ^u.w2,
|
||||
w1: ^u.w1,
|
||||
w0: ^u.w0,
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint256) AsUint64() uint64 {
|
||||
return u.w0
|
||||
}
|
231
pkg/obifp/uint64.go
Normal file
231
pkg/obifp/uint64.go
Normal file
@ -0,0 +1,231 @@
|
||||
package obifp
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Uint64 struct {
|
||||
w0 uint64
|
||||
}
|
||||
|
||||
// Zero returns a zero value of type Uint64.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint64 value of 0.
|
||||
func (u Uint64) Zero() Uint64 {
|
||||
return Uint64{0}
|
||||
}
|
||||
|
||||
// MaxValue returns the maximum possible value of type Uint64.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns the maximum value of type Uint64.
|
||||
func (u Uint64) MaxValue() Uint64 {
|
||||
return Uint64{math.MaxUint64}
|
||||
}
|
||||
|
||||
// IsZero checks if the Uint64 value is zero.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a boolean indicating if the value is zero.
|
||||
func (u Uint64) IsZero() bool {
|
||||
return u.w0 == 0
|
||||
}
|
||||
|
||||
// Cast a Uint64 to a Uint64.
|
||||
//
|
||||
// Which is a no-op.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns the Uint64 value itself.
|
||||
func (u Uint64) Uint64() Uint64 {
|
||||
return u
|
||||
}
|
||||
|
||||
// Cast a Uint64 to a Uint128.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint128 value with the high field set to 0 and the low field set to the value of the Uint64.
|
||||
func (u Uint64) Uint128() Uint128 {
|
||||
return Uint128{w1: 0, w0: u.w0}
|
||||
}
|
||||
|
||||
// Cast a Uint64 to a Uint256.
|
||||
//
|
||||
// No parameters.
|
||||
// Returns a Uint256 value with the high fields set to 0 and the low fields set to the value of the Uint64.
|
||||
func (u Uint64) Uint256() Uint256 {
|
||||
return Uint256{w3: 0, w2: 0, w1: 0, w0: u.w0}
|
||||
}
|
||||
|
||||
func (u Uint64) Set64(v uint64) Uint64 {
|
||||
|
||||
return Uint64{
|
||||
w0: v,
|
||||
}
|
||||
}
|
||||
|
||||
// LeftShift64 performs a left shift operation on the Uint64 value by n bits, with carry-in from carryIn.
|
||||
//
|
||||
// The carry-in value is used as the first bit of the shifted value.
|
||||
//
|
||||
// The function returns u << n | (carryIn & ((1 << n) - 1)).
|
||||
//
|
||||
// This is a shift left operation, lowest bits are set with the lowest bits of
|
||||
// the carry-in value instead of 0 as they would be in classical a left shift operation.
|
||||
//
|
||||
// Parameters:
|
||||
// - n: the number of bits to shift by.
|
||||
// - carryIn: the carry-in value.
|
||||
//
|
||||
// Returns:
|
||||
// - value: the result of the left shift operation.
|
||||
// - carry: the carry-out value.
|
||||
func (u Uint64) LeftShift64(n uint, carryIn uint64) (value, carry uint64) {
|
||||
switch {
|
||||
case n == 0:
|
||||
return u.w0, 0
|
||||
|
||||
case n < 64:
|
||||
return u.w0<<n | (carryIn & ((1 << n) - 1)), u.w0 >> (64 - n)
|
||||
|
||||
case n == 64:
|
||||
return carryIn, u.w0
|
||||
}
|
||||
|
||||
log.Warnf("Uint64 overflow at LeftShift64(%v, %v)", u, n)
|
||||
return 0, 0
|
||||
|
||||
}
|
||||
|
||||
// RightShift64 performs a right shift operation on the Uint64 value by n bits, with carry-out to carry.
|
||||
//
|
||||
// The function returns the result of the right shift operation and the carry-out value.
|
||||
//
|
||||
// Parameters:
|
||||
// - n: the number of bits to shift by.
|
||||
//
|
||||
// Returns:
|
||||
// - value: the result of the right shift operation.
|
||||
// - carry: the carry-out value.
|
||||
func (u Uint64) RightShift64(n uint, carryIn uint64) (value, carry uint64) {
|
||||
switch {
|
||||
case n == 0:
|
||||
return u.w0, 0
|
||||
|
||||
case n < 64:
|
||||
return u.w0>>n | (carryIn & ^((1 << (64 - n)) - 1)), u.w0 << (n - 64)
|
||||
|
||||
case n == 64:
|
||||
return carryIn, u.w0
|
||||
}
|
||||
|
||||
log.Warnf("Uint64 overflow at RightShift64(%v, %v)", u, n)
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
func (u Uint64) Add64(v Uint64, carryIn uint64) (value, carry uint64) {
|
||||
return bits.Add64(u.w0, v.w0, uint64(carryIn))
|
||||
}
|
||||
|
||||
func (u Uint64) Sub64(v Uint64, carryIn uint64) (value, carry uint64) {
|
||||
return bits.Sub64(u.w0, v.w0, uint64(carryIn))
|
||||
}
|
||||
|
||||
func (u Uint64) Mul64(v Uint64) (value, carry uint64) {
|
||||
return bits.Mul64(u.w0, v.w0)
|
||||
}
|
||||
|
||||
func (u Uint64) LeftShift(n uint) Uint64 {
|
||||
sl, _ := u.LeftShift64(n, 0)
|
||||
return Uint64{w0: sl}
|
||||
}
|
||||
|
||||
func (u Uint64) RightShift(n uint) Uint64 {
|
||||
sr, _ := u.RightShift64(n, 0)
|
||||
return Uint64{w0: sr}
|
||||
}
|
||||
|
||||
func (u Uint64) Add(v Uint64) Uint64 {
|
||||
value, carry := u.Add64(v, 0)
|
||||
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint64 overflow at Add(%v, %v)", u, v)
|
||||
}
|
||||
|
||||
return Uint64{w0: value}
|
||||
}
|
||||
|
||||
func (u Uint64) Sub(v Uint64) Uint64 {
|
||||
value, carry := u.Sub64(v, 0)
|
||||
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint64 overflow at Sub(%v, %v)", u, v)
|
||||
}
|
||||
|
||||
return Uint64{w0: value}
|
||||
}
|
||||
|
||||
func (u Uint64) Mul(v Uint64) Uint64 {
|
||||
value, carry := u.Mul64(v)
|
||||
|
||||
if carry != 0 {
|
||||
log.Panicf("Uint64 overflow at Mul(%v, %v)", u, v)
|
||||
}
|
||||
|
||||
return Uint64{w0: value}
|
||||
}
|
||||
|
||||
func (u Uint64) Cmp(v Uint64) int {
|
||||
switch {
|
||||
case u.w0 < v.w0:
|
||||
return -1
|
||||
case u.w0 > v.w0:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (u Uint64) Equals(v Uint64) bool {
|
||||
return u.Cmp(v) == 0
|
||||
}
|
||||
|
||||
func (u Uint64) LessThan(v Uint64) bool {
|
||||
return u.Cmp(v) < 0
|
||||
}
|
||||
|
||||
func (u Uint64) GreaterThan(v Uint64) bool {
|
||||
return u.Cmp(v) > 0
|
||||
}
|
||||
|
||||
func (u Uint64) LessThanOrEqual(v Uint64) bool {
|
||||
return !u.GreaterThan(v)
|
||||
}
|
||||
|
||||
func (u Uint64) GreaterThanOrEqual(v Uint64) bool {
|
||||
return !u.LessThan(v)
|
||||
}
|
||||
|
||||
func (u Uint64) And(v Uint64) Uint64 {
|
||||
return Uint64{w0: u.w0 & v.w0}
|
||||
}
|
||||
|
||||
func (u Uint64) Or(v Uint64) Uint64 {
|
||||
return Uint64{w0: u.w0 | v.w0}
|
||||
}
|
||||
|
||||
func (u Uint64) Xor(v Uint64) Uint64 {
|
||||
return Uint64{w0: u.w0 ^ v.w0}
|
||||
}
|
||||
|
||||
func (u Uint64) Not() Uint64 {
|
||||
return Uint64{w0: ^u.w0}
|
||||
}
|
||||
|
||||
func (u Uint64) AsUint64() uint64 {
|
||||
return u.w0
|
||||
}
|
41
pkg/obifp/unint.go
Normal file
41
pkg/obifp/unint.go
Normal file
@ -0,0 +1,41 @@
|
||||
package obifp
|
||||
|
||||
type FPUint[T Uint64 | Uint128 | Uint256] interface {
|
||||
Zero() T
|
||||
Set64(v uint64) T
|
||||
|
||||
IsZero() bool
|
||||
LeftShift(n uint) T
|
||||
RightShift(n uint) T
|
||||
|
||||
Add(v T) T
|
||||
Sub(v T) T
|
||||
Mul(v T) T
|
||||
//Div(v T) T
|
||||
|
||||
And(v T) T
|
||||
Or(v T) T
|
||||
Xor(v T) T
|
||||
Not() T
|
||||
|
||||
LessThan(v T) bool
|
||||
LessThanOrEqual(v T) bool
|
||||
GreaterThan(v T) bool
|
||||
GreaterThanOrEqual(v T) bool
|
||||
|
||||
AsUint64() uint64
|
||||
|
||||
Uint64 | Uint128 | Uint256
|
||||
}
|
||||
|
||||
func ZeroUint[T FPUint[T]]() T {
|
||||
return *new(T)
|
||||
}
|
||||
|
||||
func OneUint[T FPUint[T]]() T {
|
||||
return ZeroUint[T]().Set64(1)
|
||||
}
|
||||
|
||||
func From64[T FPUint[T]](v uint64) T {
|
||||
return ZeroUint[T]().Set64(v)
|
||||
}
|
Reference in New Issue
Block a user