Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions internal/staging/primitives/uint256/uint256.go
Original file line number Diff line number Diff line change
Expand Up @@ -1504,11 +1504,19 @@ func (n *Uint256) toDecimal() []byte {
// check, there will always be a nonzero most-significant word. Also, note
// that partial digit handling is needed in this case because the shift
// amount does not evenly divide the bits per internal word.
const outputDigitsPerDiv = 19
var remainingDigitsPerDiv uint8
var quo, rem, t Uint256
var r uint64
outputIdx := maxOutDigits - 1
quo = *n
for !quo.IsZero() {
for i := uint8(0); i < remainingDigitsPerDiv; i++ {
result[outputIdx] = '0'
outputIdx--
}
remainingDigitsPerDiv = outputDigitsPerDiv

rem.Set(&quo)
quo.Div(maxPow10ForInternalWord)
t.Mul2(&quo, maxPow10ForInternalWord)
Expand All @@ -1517,6 +1525,7 @@ func (n *Uint256) toDecimal() []byte {
inputWord, r = inputWord/10, inputWord%10
result[outputIdx] = '0' + byte(r)
outputIdx--
remainingDigitsPerDiv--
}
}

Expand Down
59 changes: 59 additions & 0 deletions internal/staging/primitives/uint256/uint256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"math/big"
"math/rand"
"reflect"
"strings"
"testing"
"time"
)
Expand Down Expand Up @@ -3645,6 +3646,11 @@ func TestUint256Format(t *testing.T) {
n: "3b9aca00",
fmt: "%s",
want: "1000000000",
}, {
name: "10^77 decimal via %s",
n: "dd15fe86affad91249ef0eb713f39ebeaa987b6e6fd2a0000000000000000000",
fmt: "%s",
want: "1" + strings.Repeat("0", 77),
}, {
name: "123456789 decimal via %v",
n: "75bcd15",
Expand Down Expand Up @@ -4043,6 +4049,59 @@ func TestUint256Format(t *testing.T) {
}
}

// TestUint256FormatRandom ensures that the binary, octal, decimal, and hex
// output of uint256s created from random values works as expected by also
// performing the same operation with big ints and comparing the results.
func TestUint256FormatRandom(t *testing.T) {
t.Parallel()

// Use a unique random seed each test instance and log it if the tests fail.
seed := time.Now().Unix()
rng := rand.New(rand.NewSource(seed))
defer func(t *testing.T, seed int64) {
if t.Failed() {
t.Logf("random seed: %d", seed)
}
}(t, seed)

for i := 0; i < 100; i++ {
// Generate big integer and uint256 pair.
bigN1, n1 := randBigIntAndUint256(t, rng)

// Ensure base 2 output matches.
bigIntBinary := bigN1.Text(2)
uint256Binary := n1.Text(OutputBaseBinary)
if bigIntBinary != uint256Binary {
t.Fatalf("mismatched binary n: %x -- got %s, want %s", bigN1,
bigIntBinary, uint256Binary)
}

// Ensure base 8 output matches.
bigIntOctal := bigN1.Text(8)
uint256Octal := n1.Text(OutputBaseOctal)
if bigIntOctal != uint256Octal {
t.Fatalf("mismatched octal n: %x -- got %s, want %s", bigN1,
bigIntOctal, uint256Octal)
}

// Ensure base 10 output matches.
bigIntDecimal := bigN1.Text(10)
uint256Decimal := n1.Text(OutputBaseDecimal)
if bigIntDecimal != uint256Decimal {
t.Fatalf("mismatched decimal n: %x -- got %s, want %s", bigN1,
bigIntDecimal, uint256Decimal)
}

// Ensure base 16 output matches.
bigIntHex := bigN1.Text(16)
uint256Hex := n1.Text(OutputBaseHex)
if bigIntHex != uint256Hex {
t.Fatalf("mismatched hex n: %x -- got %s, want %s", bigN1,
bigIntHex, uint256Hex)
}
}
}

// TestUint256ToBigRandom ensures that converting uint256s created from random
// values to big ints works as expected.
func TestUint256ToBigRandom(t *testing.T) {
Expand Down