226 lines
6.7 KiB
Go
226 lines
6.7 KiB
Go
// uint256: Fixed size 256-bit math library
|
|
// Copyright 2020 uint256 Authors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package uint256
|
|
|
|
import (
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
const twoPow256Sub1 = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
|
|
|
// Dec returns the decimal representation of z.
|
|
func (z *Int) Dec() string {
|
|
if z.IsZero() {
|
|
return "0"
|
|
}
|
|
if z.IsUint64() {
|
|
return strconv.FormatUint(z.Uint64(), 10)
|
|
}
|
|
// The max uint64 value being 18446744073709551615, the largest
|
|
// power-of-ten below that is 10000000000000000000.
|
|
// When we do a DivMod using that number, the remainder that we
|
|
// get back is the lower part of the output.
|
|
//
|
|
// The ascii-output of remainder will never exceed 19 bytes (since it will be
|
|
// below 10000000000000000000).
|
|
//
|
|
// Algorithm example using 100 as divisor
|
|
//
|
|
// 12345 % 100 = 45 (rem)
|
|
// 12345 / 100 = 123 (quo)
|
|
// -> output '45', continue iterate on 123
|
|
var (
|
|
// out is 98 bytes long: 78 (max size of a string without leading zeroes,
|
|
// plus slack so we can copy 19 bytes every iteration).
|
|
// We init it with zeroes, because when strconv appends the ascii representations,
|
|
// it will omit leading zeroes.
|
|
out = []byte("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
divisor = NewInt(10000000000000000000) // 20 digits
|
|
y = new(Int).Set(z) // copy to avoid modifying z
|
|
pos = len(out) // position to write to
|
|
buf = make([]byte, 0, 19) // buffer to write uint64:s to
|
|
)
|
|
for {
|
|
// Obtain Q and R for divisor
|
|
var quot, rem Int
|
|
udivrem(quot[:], y[:], divisor, &rem)
|
|
y.Set(") // Set Q for next loop
|
|
// Convert the R to ascii representation
|
|
buf = strconv.AppendUint(buf[:0], rem.Uint64(), 10)
|
|
// Copy in the ascii digits
|
|
copy(out[pos-len(buf):], buf)
|
|
if y.IsZero() {
|
|
break
|
|
}
|
|
// Move 19 digits left
|
|
pos -= 19
|
|
}
|
|
// skip leading zeroes by only using the 'used size' of buf
|
|
return string(out[pos-len(buf):])
|
|
}
|
|
|
|
// PrettyDec returns the decimal representation of z, with thousands-separators.
|
|
func (z *Int) PrettyDec(separator byte) string {
|
|
if z.IsZero() {
|
|
return "0"
|
|
}
|
|
// See algorithm-description in Dec()
|
|
// This just also inserts comma while copying byte-for-byte instead
|
|
// of using copy().
|
|
var (
|
|
out = []byte("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
divisor = NewInt(10000000000000000000)
|
|
y = new(Int).Set(z) // copy to avoid modifying z
|
|
pos = len(out) - 1 // position to write to
|
|
buf = make([]byte, 0, 19) // buffer to write uint64:s to
|
|
comma = 0
|
|
)
|
|
for {
|
|
var quot, rem Int
|
|
udivrem(quot[:], y[:], divisor, &rem)
|
|
y.Set(") // Set Q for next loop
|
|
buf = strconv.AppendUint(buf[:0], rem.Uint64(), 10)
|
|
for j := len(buf) - 1; j >= 0; j-- {
|
|
if comma == 3 {
|
|
out[pos] = separator
|
|
pos--
|
|
comma = 0
|
|
}
|
|
out[pos] = buf[j]
|
|
comma++
|
|
pos--
|
|
}
|
|
if y.IsZero() {
|
|
break
|
|
}
|
|
// Need to do zero-padding if we have more iterations coming
|
|
for j := 0; j < 19-len(buf); j++ {
|
|
if comma == 3 {
|
|
out[pos] = separator
|
|
pos--
|
|
comma = 0
|
|
}
|
|
comma++
|
|
pos--
|
|
}
|
|
}
|
|
return string(out[pos+1:])
|
|
}
|
|
|
|
// FromDecimal is a convenience-constructor to create an Int from a
|
|
// decimal (base 10) string. Numbers larger than 256 bits are not accepted.
|
|
func FromDecimal(decimal string) (*Int, error) {
|
|
var z Int
|
|
if err := z.SetFromDecimal(decimal); err != nil {
|
|
return nil, err
|
|
}
|
|
return &z, nil
|
|
}
|
|
|
|
// MustFromDecimal is a convenience-constructor to create an Int from a
|
|
// decimal (base 10) string.
|
|
// Returns a new Int and panics if any error occurred.
|
|
func MustFromDecimal(decimal string) *Int {
|
|
var z Int
|
|
if err := z.SetFromDecimal(decimal); err != nil {
|
|
panic(err)
|
|
}
|
|
return &z
|
|
}
|
|
|
|
// SetFromDecimal sets z from the given string, interpreted as a decimal number.
|
|
// OBS! This method is _not_ strictly identical to the (*big.Int).SetString(..., 10) method.
|
|
// Notable differences:
|
|
// - This method does not accept underscore input, e.g. "100_000",
|
|
// - This method does not accept negative zero as valid, e.g "-0",
|
|
// - (this method does not accept any negative input as valid))
|
|
func (z *Int) SetFromDecimal(s string) (err error) {
|
|
// Remove max one leading +
|
|
if len(s) > 0 && s[0] == '+' {
|
|
s = s[1:]
|
|
}
|
|
// Remove any number of leading zeroes
|
|
if len(s) > 0 && s[0] == '0' {
|
|
var i int
|
|
var c rune
|
|
for i, c = range s {
|
|
if c != '0' {
|
|
break
|
|
}
|
|
}
|
|
s = s[i:]
|
|
}
|
|
if len(s) < len(twoPow256Sub1) {
|
|
return z.fromDecimal(s)
|
|
}
|
|
if len(s) == len(twoPow256Sub1) {
|
|
if s > twoPow256Sub1 {
|
|
return ErrBig256Range
|
|
}
|
|
return z.fromDecimal(s)
|
|
}
|
|
return ErrBig256Range
|
|
}
|
|
|
|
// multipliers holds the values that are needed for fromDecimal
|
|
var multipliers = [5]*Int{
|
|
nil, // represents first round, no multiplication needed
|
|
{10000000000000000000, 0, 0, 0}, // 10 ^ 19
|
|
{687399551400673280, 5421010862427522170, 0, 0}, // 10 ^ 38
|
|
{5332261958806667264, 17004971331911604867, 2938735877055718769, 0}, // 10 ^ 57
|
|
{0, 8607968719199866880, 532749306367912313, 1593091911132452277}, // 10 ^ 76
|
|
}
|
|
|
|
// fromDecimal is a helper function to only ever be called via SetFromDecimal
|
|
// this function takes a string and chunks it up, calling ParseUint on it up to 5 times
|
|
// these chunks are then multiplied by the proper power of 10, then added together.
|
|
// Note: this method assumes that some basic validity-checks have already been performed
|
|
// on the input 'bs'. See SetFromDecimal.
|
|
func (z *Int) fromDecimal(bs string) error {
|
|
// first clear the input
|
|
z.Clear()
|
|
// the maximum value of uint64 is 18446744073709551615, which is 20 characters
|
|
// one less means that a string of 19 9's is always within the uint64 limit
|
|
var (
|
|
num uint64
|
|
err error
|
|
remaining = len(bs)
|
|
)
|
|
if remaining == 0 {
|
|
return io.EOF
|
|
}
|
|
// We proceed in steps of 19 characters (nibbles), from least significant to most significant.
|
|
// This means that the first (up to) 19 characters do not need to be multiplied.
|
|
// In the second iteration, our slice of 19 characters needs to be multipleied
|
|
// by a factor of 10^19. Et cetera.
|
|
for i, mult := range multipliers {
|
|
if remaining <= 0 {
|
|
return nil // Done
|
|
} else if remaining > 19 {
|
|
num, err = strconv.ParseUint(bs[remaining-19:remaining], 10, 64)
|
|
} else {
|
|
// Final round
|
|
num, err = strconv.ParseUint(bs, 10, 64)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// add that number to our running total
|
|
if i == 0 {
|
|
z.SetUint64(num)
|
|
} else {
|
|
base := NewInt(num)
|
|
z.Add(z, base.Mul(base, mult))
|
|
}
|
|
// Chop off another 19 characters
|
|
if remaining > 19 {
|
|
bs = bs[0 : remaining-19]
|
|
}
|
|
remaining -= 19
|
|
}
|
|
return nil
|
|
}
|