Source file src/internal/strconv/math_test.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package strconv_test
     6  
     7  import (
     8  	. "internal/strconv"
     9  	"math"
    10  	"testing"
    11  )
    12  
    13  var pow10Tests = []struct {
    14  	exp10 int
    15  	mant  uint128
    16  	exp2  int
    17  	ok    bool
    18  }{
    19  	{-349, uint128{0, 0}, 0, false},
    20  	{-348, uint128{0xFA8FD5A0081C0288, 0x1732C869CD60E453}, -1156, true},
    21  	{0, uint128{0x8000000000000000, 0x0000000000000000}, 1, true},
    22  	{347, uint128{0xD13EB46469447567, 0x4B7195F2D2D1A9FB}, 1153, true},
    23  	{348, uint128{0, 0}, 0, false},
    24  }
    25  
    26  func TestPow10(t *testing.T) {
    27  	for _, tt := range pow10Tests {
    28  		mant, exp2, ok := pow10(tt.exp10)
    29  		if mant != tt.mant || exp2 != tt.exp2 {
    30  			t.Errorf("pow10(%d) = %#016x, %#016x, %d, %v want %#016x,%#016x, %d, %v",
    31  				tt.exp10, mant.Hi, mant.Lo, exp2, ok,
    32  				tt.mant.Hi, tt.mant.Lo, tt.exp2, tt.ok)
    33  		}
    34  	}
    35  
    36  	for p := pow10Min; p <= pow10Max; p++ {
    37  		mant, exp2, ok := pow10(p)
    38  		if !ok {
    39  			t.Errorf("pow10(%d) not ok", p)
    40  			continue
    41  		}
    42  		// Note: -64 instead of -128 because we only used mant.Hi, not all of mant.
    43  		have := math.Ldexp(float64(mant.Hi), exp2-64)
    44  		want := math.Pow(10, float64(p))
    45  		if math.Abs(have-want)/want > 0.00001 {
    46  			t.Errorf("pow10(%d) = %#016x%016x/2^128 * 2^%d = %g want ~%g", p, mant.Hi, mant.Lo, exp2, have, want)
    47  		}
    48  	}
    49  
    50  }
    51  
    52  func u128(hi, lo uint64) uint128 {
    53  	return uint128{Hi: hi, Lo: lo}
    54  }
    55  
    56  var umul192Tests = []struct {
    57  	x   uint64
    58  	y   uint128
    59  	hi  uint64
    60  	mid uint64
    61  	lo  uint64
    62  }{
    63  	{0, u128(0, 0), 0, 0, 0},
    64  	{^uint64(0), u128(^uint64(0), ^uint64(0)), ^uint64(1), ^uint64(0), 1},
    65  }
    66  
    67  func TestUmul192(t *testing.T) {
    68  	for _, tt := range umul192Tests {
    69  		hi, mid, lo := Umul192(tt.x, tt.y)
    70  		if hi != tt.hi || mid != tt.mid || lo != tt.lo {
    71  			t.Errorf("umul192(%#x, {%#x,%#x}) = %#x, %#x, %#x, want %#x, %#x, %#x",
    72  				tt.x, tt.y.Hi, tt.y.Lo, hi, mid, lo, tt.hi, tt.mid, tt.lo)
    73  		}
    74  	}
    75  }
    76  
    77  func TestMulLog10_2(t *testing.T) {
    78  	for x := -1600; x <= +1600; x++ {
    79  		iMath := mulLog10_2(x)
    80  		fMath := int(math.Floor(float64(x) * math.Ln2 / math.Ln10))
    81  		if iMath != fMath {
    82  			t.Errorf("mulLog10_2(%d) failed: %d vs %d\n", x, iMath, fMath)
    83  		}
    84  	}
    85  }
    86  
    87  func TestMulLog2_10(t *testing.T) {
    88  	for x := -500; x <= +500; x++ {
    89  		iMath := mulLog2_10(x)
    90  		fMath := int(math.Floor(float64(x) * math.Ln10 / math.Ln2))
    91  		if iMath != fMath {
    92  			t.Errorf("mulLog2_10(%d) failed: %d vs %d\n", x, iMath, fMath)
    93  		}
    94  	}
    95  }
    96  
    97  func pow5(p int) uint64 {
    98  	x := uint64(1)
    99  	for range p {
   100  		x *= 5
   101  	}
   102  	return x
   103  }
   104  
   105  func TestDivisiblePow5(t *testing.T) {
   106  	for p := 1; p <= 22; p++ {
   107  		x := pow5(p)
   108  		if divisiblePow5(1, p) {
   109  			t.Errorf("divisiblePow5(1, %d) = true, want, false", p)
   110  		}
   111  		if divisiblePow5(x-1, p) {
   112  			t.Errorf("divisiblePow5(%d, %d) = true, want false", x-1, p)
   113  		}
   114  		if divisiblePow5(x+1, p) {
   115  			t.Errorf("divisiblePow5(%d, %d) = true, want false", x-1, p)
   116  		}
   117  		if divisiblePow5(x/5, p) {
   118  			t.Errorf("divisiblePow5(%d, %d) = true, want false", x/5, p)
   119  		}
   120  		if !divisiblePow5(0, p) {
   121  			t.Errorf("divisiblePow5(0, %d) = false, want true", p)
   122  		}
   123  		if !divisiblePow5(x, p) {
   124  			t.Errorf("divisiblePow5(%d, %d) = false, want true", x, p)
   125  		}
   126  		if 2*x > x && !divisiblePow5(2*x, p) {
   127  			t.Errorf("divisiblePow5(%d, %d) = false, want true", 2*x, p)
   128  		}
   129  	}
   130  }
   131  
   132  func TestDiv5Tab(t *testing.T) {
   133  	for p := 1; p <= 22; p++ {
   134  		m := div5Tab[p-1][0]
   135  		le := div5Tab[p-1][1]
   136  
   137  		// See comment in math.go on div5Tab.
   138  		// m needs to be multiplicative inverse of pow5(p).
   139  		if m*pow5(p) != 1 {
   140  			t.Errorf("pow5Tab[%d-1][0] = %#x, but %#x * (5**%d) = %d, want 1", p, m, m, p, m*pow5(p))
   141  		}
   142  
   143  		// le needs to be ⌊(1<<64 - 1) / 5^pāŒ‹.
   144  		want := (1<<64 - 1) / pow5(p)
   145  		if le != want {
   146  			t.Errorf("pow5Tab[%d-1][1] = %#x, want %#x", p, le, want)
   147  		}
   148  	}
   149  }
   150  
   151  func TestTrimZeros(t *testing.T) {
   152  	for _, x := range []uint64{1, 2, 3, 4, 101, 123} {
   153  		want := x
   154  		for p := range 20 {
   155  			haveX, haveP := trimZeros(x)
   156  			if haveX != want || haveP != p {
   157  				t.Errorf("trimZeros(%d) = %d, %d, want %d, %d", x, haveX, haveP, want, p)
   158  			}
   159  			if x >= (1<<64-1)/10 {
   160  				break
   161  			}
   162  			x *= 10
   163  		}
   164  	}
   165  }
   166  

View as plain text