1 // Copyright 2015 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.
16 type StringTest
struct {
21 var setStringTests
= []StringTest
{
36 {"-0.1", "-1/10", true},
37 {"-.1", "-1/10", true},
40 {"-1/5", "-1/5", true},
41 {"8129567.7690E14", "812956776900000000000", true},
42 {"78189e+4", "781890000", true},
43 {"553019.8935e+8", "55301989350000", true},
44 {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
45 {"9877861857500000E-7", "3951144743/4", true},
46 {"2169378.417e-3", "2169378417/1000000", true},
47 {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
48 {"53/70893980658822810696", "53/70893980658822810696", true},
49 {"106/141787961317645621392", "53/70893980658822810696", true},
50 {"204211327800791583.81095", "4084226556015831676219/20000", true},
54 // These are not supported by fmt.Fscanf.
55 var setStringTests2
= []StringTest
{
57 {"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
58 {"-010.", "-10", true},
59 {"0x10/0x20", "1/2", true},
60 {"0b1000/3", "8/3", true},
61 // TODO(gri) add more tests
64 func TestRatSetString(t
*testing
.T
) {
65 var tests
[]StringTest
66 tests
= append(tests
, setStringTests
...)
67 tests
= append(tests
, setStringTests2
...)
69 for i
, test
:= range tests
{
70 x
, ok
:= new(Rat
).SetString(test
.in
)
74 t
.Errorf("#%d SetString(%q) expected failure", i
, test
.in
)
75 } else if x
.RatString() != test
.out
{
76 t
.Errorf("#%d SetString(%q) got %s want %s", i
, test
.in
, x
.RatString(), test
.out
)
79 t
.Errorf("#%d SetString(%q) got %p want nil", i
, test
.in
, x
)
84 func TestRatScan(t
*testing
.T
) {
86 for i
, test
:= range setStringTests
{
89 buf
.WriteString(test
.in
)
91 _
, err
:= fmt
.Fscanf(&buf
, "%v", x
)
92 if err
== nil != test
.ok
{
94 t
.Errorf("#%d (%s) error: %s", i
, test
.in
, err
)
96 t
.Errorf("#%d (%s) expected error", i
, test
.in
)
100 if err
== nil && x
.RatString() != test
.out
{
101 t
.Errorf("#%d got %s want %s", i
, x
.RatString(), test
.out
)
106 var floatStringTests
= []struct {
117 {"-0.05", 1, "-0.1"},
121 {"-1/3", 3, "-0.333"},
122 {"-2/3", 4, "-0.6667"},
124 {"0.999", 2, "1.00"},
130 func TestFloatString(t
*testing
.T
) {
131 for i
, test
:= range floatStringTests
{
132 x
, _
:= new(Rat
).SetString(test
.in
)
134 if x
.FloatString(test
.prec
) != test
.out
{
135 t
.Errorf("#%d got %s want %s", i
, x
.FloatString(test
.prec
), test
.out
)
140 // Test inputs to Rat.SetString. The prefix "long:" causes the test
141 // to be skipped in --test.short mode. (The threshold is about 500us.)
142 var float64inputs
= []string{
143 // Constants plundered from strconv/testfp.txt.
145 // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
158 "3142213164987e-294",
159 "46202199371337e-072",
160 "231010996856685e-073",
161 "9324754620109615e+212",
162 "78459735791271921e+049",
163 "272104041512242479e+200",
164 "6802601037806061975e+198",
165 "20505426358836677347e-221",
166 "836168422905420598437e-234",
167 "4891559871276714924261e+222",
169 // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
182 "2335141086879e+218",
183 "36167929443327e-159",
184 "609610927149051e-255",
185 "3743626360493413e-165",
186 "94080055902682397e-242",
187 "899810892172646163e+283",
188 "7120190517612959703e+120",
189 "25188282901709339043e-252",
190 "308984926168550152811e-052",
191 "6372891218502368041059e+064",
193 // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
207 // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
221 // Constants plundered from strconv/atof_test.go.
228 "100000000000000000000000",
231 "99999999999999974834176",
232 "100000000000000000000001",
233 "100000000000000008388608",
234 "100000000000000016777215",
235 "100000000000000016777216",
238 "-0", // NB: exception made for this input
243 "1.7976931348623157e308",
244 "-1.7976931348623157e308",
245 // next float64 - too large
246 "1.7976931348623159e308",
247 "-1.7976931348623159e308",
248 // the border is ...158079
250 "1.7976931348623158e308",
251 "-1.7976931348623158e308",
252 // borderline - too large
253 "1.797693134862315808e308",
254 "-1.797693134862315808e308",
256 // a little too large
286 // way too small, negative
290 // try to overflow exponent
291 // [Disabled: too slow and memory-hungry with rationals.]
294 // "1e-18446744073709551616",
295 // "1e+18446744073709551616",
297 // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
298 "2.2250738585072012e-308",
299 // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
300 "2.2250738585072011e-308",
302 // A very large number (initially wrongly parsed by the fast algorithm).
303 "4.630813248087435e+307",
305 // A different kind of very large number.
306 "22.222222222222222",
307 "long:2." + strings
.Repeat("2", 4000) + "e+1",
309 // Exactly halfway between 1 and math.Nextafter(1, 2).
310 // Round to even (down).
311 "1.00000000000000011102230246251565404236316680908203125",
312 // Slightly lower; still round down.
313 "1.00000000000000011102230246251565404236316680908203124",
314 // Slightly higher; round up.
315 "1.00000000000000011102230246251565404236316680908203126",
316 // Slightly higher, but you have to read all the way to the end.
317 "long:1.00000000000000011102230246251565404236316680908203125" + strings
.Repeat("0", 10000) + "1",
319 // Smallest denormal, 2^(-1022-52)
320 "4.940656458412465441765687928682213723651e-324",
321 // Half of smallest denormal, 2^(-1022-53)
322 "2.470328229206232720882843964341106861825e-324",
323 // A little more than the exact half of smallest denormal
324 // 2^-1075 + 2^-1100. (Rounds to 1p-1074.)
325 "2.470328302827751011111470718709768633275e-324",
326 // The exact halfway between smallest normal and largest denormal:
327 // 2^-1022 - 2^-1075. (Rounds to 2^-1022.)
328 "2.225073858507201136057409796709131975935e-308",
330 "1152921504606846975", // 1<<60 - 1
331 "-1152921504606846975", // -(1<<60 - 1)
332 "1152921504606846977", // 1<<60 + 1
333 "-1152921504606846977", // -(1<<60 + 1)
338 // isFinite reports whether f represents a finite rational value.
339 // It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
340 func isFinite(f
float64) bool {
341 return math
.Abs(f
) <= math
.MaxFloat64
344 func TestFloat32SpecialCases(t
*testing
.T
) {
345 for _
, input
:= range float64inputs
{
346 if strings
.HasPrefix(input
, "long:") {
350 input
= input
[len("long:"):]
353 r
, ok
:= new(Rat
).SetString(input
)
355 t
.Errorf("Rat.SetString(%q) failed", input
)
358 f
, exact
:= r
.Float32()
360 // 1. Check string -> Rat -> float32 conversions are
361 // consistent with strconv.ParseFloat.
362 // Skip this check if the input uses "a/b" rational syntax.
363 if !strings
.Contains(input
, "/") {
364 e64
, _
:= strconv
.ParseFloat(input
, 32)
367 // Careful: negative Rats too small for
368 // float64 become -0, but Rat obviously cannot
369 // preserve the sign from SetString("-0").
371 case math
.Float32bits(e
) == math
.Float32bits(f
):
372 // Ok: bitwise equal.
373 case f
== 0 && r
.Num().BitLen() == 0:
374 // Ok: Rat(0) is equivalent to both +/- float64(0).
376 t
.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input
, e
, e
, f
, f
, f
-e
)
380 if !isFinite(float64(f
)) {
384 // 2. Check f is best approximation to r.
385 if !checkIsBestApprox32(t
, f
, r
) {
386 // Append context information.
387 t
.Errorf("(input was %q)", input
)
390 // 3. Check f->R->f roundtrip is non-lossy.
391 checkNonLossyRoundtrip32(t
, f
)
393 // 4. Check exactness using slow algorithm.
394 if wasExact
:= new(Rat
).SetFloat64(float64(f
)).Cmp(r
) == 0; wasExact
!= exact
{
395 t
.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input
, exact
, wasExact
)
400 func TestFloat64SpecialCases(t
*testing
.T
) {
401 for _
, input
:= range float64inputs
{
402 if strings
.HasPrefix(input
, "long:") {
406 input
= input
[len("long:"):]
409 r
, ok
:= new(Rat
).SetString(input
)
411 t
.Errorf("Rat.SetString(%q) failed", input
)
414 f
, exact
:= r
.Float64()
416 // 1. Check string -> Rat -> float64 conversions are
417 // consistent with strconv.ParseFloat.
418 // Skip this check if the input uses "a/b" rational syntax.
419 if !strings
.Contains(input
, "/") {
420 e
, _
:= strconv
.ParseFloat(input
, 64)
422 // Careful: negative Rats too small for
423 // float64 become -0, but Rat obviously cannot
424 // preserve the sign from SetString("-0").
426 case math
.Float64bits(e
) == math
.Float64bits(f
):
427 // Ok: bitwise equal.
428 case f
== 0 && r
.Num().BitLen() == 0:
429 // Ok: Rat(0) is equivalent to both +/- float64(0).
431 t
.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input
, e
, e
, f
, f
, f
-e
)
439 // 2. Check f is best approximation to r.
440 if !checkIsBestApprox64(t
, f
, r
) {
441 // Append context information.
442 t
.Errorf("(input was %q)", input
)
445 // 3. Check f->R->f roundtrip is non-lossy.
446 checkNonLossyRoundtrip64(t
, f
)
448 // 4. Check exactness using slow algorithm.
449 if wasExact
:= new(Rat
).SetFloat64(f
).Cmp(r
) == 0; wasExact
!= exact
{
450 t
.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input
, exact
, wasExact
)