github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/strconv/fp_test.go (about) 1 // Copyright 2009 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 "bufio" 9 "fmt" 10 "os" 11 "strconv" 12 "strings" 13 "testing" 14 ) 15 16 func pow2(i int) float64 { 17 switch { 18 case i < 0: 19 return 1 / pow2(-i) 20 case i == 0: 21 return 1 22 case i == 1: 23 return 2 24 } 25 return pow2(i/2) * pow2(i-i/2) 26 } 27 28 // Wrapper around strconv.ParseFloat(x, 64). Handles dddddp+ddd (binary exponent) 29 // itself, passes the rest on to strconv.ParseFloat. 30 func myatof64(s string) (f float64, ok bool) { 31 if mant, exp, ok := strings.Cut(s, "p"); ok { 32 n, err := strconv.ParseInt(mant, 10, 64) 33 if err != nil { 34 return 0, false 35 } 36 e, err1 := strconv.Atoi(exp) 37 if err1 != nil { 38 println("bad e", exp) 39 return 0, false 40 } 41 v := float64(n) 42 // We expect that v*pow2(e) fits in a float64, 43 // but pow2(e) by itself may not. Be careful. 44 if e <= -1000 { 45 v *= pow2(-1000) 46 e += 1000 47 for e < 0 { 48 v /= 2 49 e++ 50 } 51 return v, true 52 } 53 if e >= 1000 { 54 v *= pow2(1000) 55 e -= 1000 56 for e > 0 { 57 v *= 2 58 e-- 59 } 60 return v, true 61 } 62 return v * pow2(e), true 63 } 64 f1, err := strconv.ParseFloat(s, 64) 65 if err != nil { 66 return 0, false 67 } 68 return f1, true 69 } 70 71 // Wrapper around strconv.ParseFloat(x, 32). Handles dddddp+ddd (binary exponent) 72 // itself, passes the rest on to strconv.ParseFloat. 73 func myatof32(s string) (f float32, ok bool) { 74 if mant, exp, ok := strings.Cut(s, "p"); ok { 75 n, err := strconv.Atoi(mant) 76 if err != nil { 77 println("bad n", mant) 78 return 0, false 79 } 80 e, err1 := strconv.Atoi(exp) 81 if err1 != nil { 82 println("bad p", exp) 83 return 0, false 84 } 85 return float32(float64(n) * pow2(e)), true 86 } 87 f64, err1 := strconv.ParseFloat(s, 32) 88 f1 := float32(f64) 89 if err1 != nil { 90 return 0, false 91 } 92 return f1, true 93 } 94 95 func TestFp(t *testing.T) { 96 f, err := os.Open("testdata/testfp.txt") 97 if err != nil { 98 t.Fatal("testfp: open testdata/testfp.txt:", err) 99 } 100 defer f.Close() 101 102 s := bufio.NewScanner(f) 103 104 for lineno := 1; s.Scan(); lineno++ { 105 line := s.Text() 106 if len(line) == 0 || line[0] == '#' { 107 continue 108 } 109 a := strings.Split(line, " ") 110 if len(a) != 4 { 111 t.Error("testdata/testfp.txt:", lineno, ": wrong field count") 112 continue 113 } 114 var s string 115 var v float64 116 switch a[0] { 117 case "float64": 118 var ok bool 119 v, ok = myatof64(a[2]) 120 if !ok { 121 t.Error("testdata/testfp.txt:", lineno, ": cannot atof64 ", a[2]) 122 continue 123 } 124 s = fmt.Sprintf(a[1], v) 125 case "float32": 126 v1, ok := myatof32(a[2]) 127 if !ok { 128 t.Error("testdata/testfp.txt:", lineno, ": cannot atof32 ", a[2]) 129 continue 130 } 131 s = fmt.Sprintf(a[1], v1) 132 v = float64(v1) 133 } 134 if s != a[3] { 135 t.Error("testdata/testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ", 136 "want ", a[3], " got ", s) 137 } 138 } 139 if s.Err() != nil { 140 t.Fatal("testfp: read testdata/testfp.txt: ", s.Err()) 141 } 142 }