@@ -72,6 +72,17 @@ const prec = 512
72
72
// too large (incl. infinity), that could be recorded in unknownVal.
73
73
// See also #20583 and #42695 for use cases.
74
74
75
+ // Representation of values:
76
+ //
77
+ // Values of Int and Float Kind have two different representations each: int64Val
78
+ // and intVal, and ratVal and floatVal. When possible, the "smaller", respectively
79
+ // more precise (for Floats) representation is chosen. However, once a Float value
80
+ // is represented as a floatVal, any subsequent results remain floatVals (unless
81
+ // explicitly converted); i.e., no attempt is made to convert a floatVal back into
82
+ // a ratVal. The reasoning is that all representations but floatVal are mathematically
83
+ // exact, but once that precision is lost (by moving to floatVal), moving back to
84
+ // a different representation implies a precision that's not actually there.
85
+
75
86
type (
76
87
unknownVal struct {}
77
88
boolVal bool
@@ -263,14 +274,8 @@ func i64tor(x int64Val) ratVal { return ratVal{newRat().SetInt64(int64(x))} }
263
274
func i64tof (x int64Val ) floatVal { return floatVal {newFloat ().SetInt64 (int64 (x ))} }
264
275
func itor (x intVal ) ratVal { return ratVal {newRat ().SetInt (x .val )} }
265
276
func itof (x intVal ) floatVal { return floatVal {newFloat ().SetInt (x .val )} }
266
-
267
- func rtof (x ratVal ) floatVal {
268
- a := newFloat ().SetInt (x .val .Num ())
269
- b := newFloat ().SetInt (x .val .Denom ())
270
- return floatVal {a .Quo (a , b )}
271
- }
272
-
273
- func vtoc (x Value ) complexVal { return complexVal {x , int64Val (0 )} }
277
+ func rtof (x ratVal ) floatVal { return floatVal {newFloat ().SetRat (x .val )} }
278
+ func vtoc (x Value ) complexVal { return complexVal {x , int64Val (0 )} }
274
279
275
280
func makeInt (x * big.Int ) Value {
276
281
if x .IsInt64 () {
@@ -279,21 +284,15 @@ func makeInt(x *big.Int) Value {
279
284
return intVal {x }
280
285
}
281
286
282
- // Permit fractions with component sizes up to maxExp
283
- // before switching to using floating-point numbers.
284
- const maxExp = 4 << 10
285
-
286
287
func makeRat (x * big.Rat ) Value {
287
288
a := x .Num ()
288
289
b := x .Denom ()
289
- if a . BitLen () < maxExp && b . BitLen () < maxExp {
290
+ if smallInt ( a ) && smallInt ( b ) {
290
291
// ok to remain fraction
291
292
return ratVal {x }
292
293
}
293
294
// components too large => switch to float
294
- fa := newFloat ().SetInt (a )
295
- fb := newFloat ().SetInt (b )
296
- return floatVal {fa .Quo (fa , fb )}
295
+ return floatVal {newFloat ().SetRat (x )}
297
296
}
298
297
299
298
var floatVal0 = floatVal {newFloat ()}
@@ -306,6 +305,9 @@ func makeFloat(x *big.Float) Value {
306
305
if x .IsInf () {
307
306
return unknownVal {}
308
307
}
308
+ // No attempt is made to "go back" to ratVal, even if possible,
309
+ // to avoid providing the illusion of a mathematically exact
310
+ // representation.
309
311
return floatVal {x }
310
312
}
311
313
@@ -318,7 +320,7 @@ func makeComplex(re, im Value) Value {
318
320
319
321
func makeFloatFromLiteral (lit string ) Value {
320
322
if f , ok := newFloat ().SetString (lit ); ok {
321
- if smallRat (f ) {
323
+ if smallFloat (f ) {
322
324
// ok to use rationals
323
325
if f .Sign () == 0 {
324
326
// Issue 20228: If the float underflowed to zero, parse just "0".
@@ -337,14 +339,34 @@ func makeFloatFromLiteral(lit string) Value {
337
339
return nil
338
340
}
339
341
340
- // smallRat reports whether x would lead to "reasonably"-sized fraction
342
+ // Permit fractions with component sizes up to maxExp
343
+ // before switching to using floating-point numbers.
344
+ const maxExp = 4 << 10
345
+
346
+ // smallInt reports whether x would lead to "reasonably"-sized fraction
347
+ // if converted to a *big.Rat.
348
+ func smallInt (x * big.Int ) bool {
349
+ return x .BitLen () < maxExp
350
+ }
351
+
352
+ // smallFloat64 reports whether x would lead to "reasonably"-sized fraction
341
353
// if converted to a *big.Rat.
342
- func smallRat (x * big.Float ) bool {
343
- if ! x .IsInf () {
344
- e := x .MantExp (nil )
345
- return - maxExp < e && e < maxExp
354
+ func smallFloat64 (x float64 ) bool {
355
+ if math .IsInf (x , 0 ) {
356
+ return false
357
+ }
358
+ _ , e := math .Frexp (x )
359
+ return - maxExp < e && e < maxExp
360
+ }
361
+
362
+ // smallFloat reports whether x would lead to "reasonably"-sized fraction
363
+ // if converted to a *big.Rat.
364
+ func smallFloat (x * big.Float ) bool {
365
+ if x .IsInf () {
366
+ return false
346
367
}
347
- return false
368
+ e := x .MantExp (nil )
369
+ return - maxExp < e && e < maxExp
348
370
}
349
371
350
372
// ----------------------------------------------------------------------------
@@ -377,7 +399,10 @@ func MakeFloat64(x float64) Value {
377
399
if math .IsInf (x , 0 ) || math .IsNaN (x ) {
378
400
return unknownVal {}
379
401
}
380
- return ratVal {newRat ().SetFloat64 (x + 0 )} // convert -0 to 0
402
+ if smallFloat64 (x ) {
403
+ return ratVal {newRat ().SetFloat64 (x + 0 )} // convert -0 to 0
404
+ }
405
+ return floatVal {newFloat ().SetFloat64 (x + 0 )}
381
406
}
382
407
383
408
// MakeFromLiteral returns the corresponding integer, floating-point,
@@ -733,7 +758,7 @@ func Num(x Value) Value {
733
758
case ratVal :
734
759
return makeInt (x .val .Num ())
735
760
case floatVal :
736
- if smallRat (x .val ) {
761
+ if smallFloat (x .val ) {
737
762
r , _ := x .val .Rat (nil )
738
763
return makeInt (r .Num ())
739
764
}
@@ -755,7 +780,7 @@ func Denom(x Value) Value {
755
780
case ratVal :
756
781
return makeInt (x .val .Denom ())
757
782
case floatVal :
758
- if smallRat (x .val ) {
783
+ if smallFloat (x .val ) {
759
784
r , _ := x .val .Rat (nil )
760
785
return makeInt (r .Denom ())
761
786
}
@@ -828,7 +853,7 @@ func ToInt(x Value) Value {
828
853
// avoid creation of huge integers
829
854
// (Existing tests require permitting exponents of at least 1024;
830
855
// allow any value that would also be permissible as a fraction.)
831
- if smallRat (x .val ) {
856
+ if smallFloat (x .val ) {
832
857
i := newInt ()
833
858
if _ , acc := x .val .Int (i ); acc == big .Exact {
834
859
return makeInt (i )
@@ -871,14 +896,16 @@ func ToInt(x Value) Value {
871
896
func ToFloat (x Value ) Value {
872
897
switch x := x .(type ) {
873
898
case int64Val :
874
- return i64tor (x )
899
+ return i64tor (x ) // x is always a small int
875
900
case intVal :
876
- return itor (x )
901
+ if smallInt (x .val ) {
902
+ return itor (x )
903
+ }
904
+ return itof (x )
877
905
case ratVal , floatVal :
878
906
return x
879
907
case complexVal :
880
- if im := ToInt (x .im ); im .Kind () == Int && Sign (im ) == 0 {
881
- // imaginary component is 0
908
+ if Sign (x .im ) == 0 {
882
909
return ToFloat (x .re )
883
910
}
884
911
}
@@ -889,13 +916,7 @@ func ToFloat(x Value) Value {
889
916
// Otherwise it returns an Unknown.
890
917
func ToComplex (x Value ) Value {
891
918
switch x := x .(type ) {
892
- case int64Val :
893
- return vtoc (i64tof (x ))
894
- case intVal :
895
- return vtoc (itof (x ))
896
- case ratVal :
897
- return vtoc (x )
898
- case floatVal :
919
+ case int64Val , intVal , ratVal , floatVal :
899
920
return vtoc (x )
900
921
case complexVal :
901
922
return x
0 commit comments