Skip to content

Commit

Permalink
uint256: Correct base 10 output formatting.
Browse files Browse the repository at this point in the history
The corrects a formatting issue where the base 10 output is not always
printing the expected results.

It also adds a test which triggers the condition as well as a new
randomized test to compare the output of random values against the big
int output for all of the supported bases.
  • Loading branch information
davecgh committed Dec 9, 2021
1 parent 3bcb7d9 commit a29d933
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
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

0 comments on commit a29d933

Please sign in to comment.