1// run 2 3// Copyright 2021 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7// Excerpted from go/constant/value.go to capture a bug from there. 8 9package main 10 11import ( 12 "fmt" 13 "math" 14 "math/big" 15) 16 17type ( 18 unknownVal struct{} 19 intVal struct{ val *big.Int } // Int values not representable as an int64 20 ratVal struct{ val *big.Rat } // Float values representable as a fraction 21 floatVal struct{ val *big.Float } // Float values not representable as a fraction 22 complexVal struct{ re, im Value } 23) 24 25const prec = 512 26 27func (unknownVal) String() string { return "unknown" } 28 29func (x intVal) String() string { return x.val.String() } 30func (x ratVal) String() string { return rtof(x).String() } 31 32func (x floatVal) String() string { 33 f := x.val 34 35 // Use exact fmt formatting if in float64 range (common case): 36 // proceed if f doesn't underflow to 0 or overflow to inf. 37 if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) { 38 return fmt.Sprintf("%.6g", x) 39 } 40 41 return "OOPS" 42} 43 44func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) } 45 46func newFloat() *big.Float { return new(big.Float).SetPrec(prec) } 47 48//go:noinline 49//go:registerparams 50func itor(x intVal) ratVal { return ratVal{nil} } 51 52//go:noinline 53//go:registerparams 54func itof(x intVal) floatVal { return floatVal{nil} } 55func rtof(x ratVal) floatVal { return floatVal{newFloat().SetRat(x.val)} } 56 57type Value interface { 58 String() string 59} 60 61//go:noinline 62//go:registerparams 63func ToFloat(x Value) Value { 64 switch x := x.(type) { 65 case intVal: 66 if smallInt(x.val) { 67 return itor(x) 68 } 69 return itof(x) 70 case ratVal, floatVal: 71 return x 72 case complexVal: 73 if Sign(x.im) == 0 { 74 return ToFloat(x.re) 75 } 76 } 77 return unknownVal{} 78} 79 80//go:noinline 81//go:registerparams 82func smallInt(x *big.Int) bool { 83 return false 84} 85 86//go:noinline 87//go:registerparams 88func Sign(x Value) int { 89 return 0 90} 91 92 93func main() { 94 v := ratVal{big.NewRat(22,7)} 95 s := ToFloat(v).String() 96 fmt.Printf("s=%s\n", s) 97} 98