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