I have a library that gives floats in mantissa and exponent values for no loss of precision.
Mantissa: 375400000000000
Exponent: -9
How do I turn this into a float32 or float64 in golang?
I gave it a shot here but the number is definitely not coming out correctly: https://go.dev/play/p/8wMxhq11qwS
package main
import (
"fmt"
"math/big"
)
func main() {
mantissa := 375600000000000
exp := int8(-9)
var price big.Float
mant := big.NewFloat(float64(mantissa))
price.SetMantExp(mant, int(exp))
fmt.Println("price: ", price.String())
fmt.Println("mant: ", mantissa)
fmt.Println("exp: ", exp)
}
Apparently this doesn't work because big.Float is represented by sign × mantissa × 2**exponent
when I need sign x mantissa x 10 ^ exp
CodePudding user response:
I think the most obvious solution would be to use the Pow10
function in the math package:
package main
import (
"fmt"
"math"
)
func main() {
mantissa := 375600000000000
exp := int8(-9)
price := float64(mantissa) * math.Pow10(int(exp))
fmt.Println("price: ", price)
fmt.Println("mant: ", mantissa)
fmt.Println("exp: ", exp)
}
This function is valid for all possible values of your exponent, but precision may be degraded depending on the value of your mantissa.
CodePudding user response:
As someone who's had to deal with precision issues in Go quite a bit, the math/big
package is an excellent alternative to using float32
or float64
. However, it does not offer an exponentiation function. One package that does is ericlagergren/decimal:
package main
import (
"fmt"
"github.com/ericlagergren/decimal"
)
func main() {
mantissa := decimal.New(375600000000000, 0)
exp := decimal.New(-9, 0)
ctx := decimal.Context {
Precision: 9, // Set this to determine the number of expected decimal places
}
price := new(decimal.Big)
ctx.Pow(price, decimal.New(10, 0), exp).Mul(price, mantissa)
fmt.Println("price: ", price)
fmt.Println("mant: ", mantissa)
fmt.Println("exp: ", exp)
}
The upside to this package is that the result is guaranteed to the set precision. The downside is that you have to set that precision explicitly. In this example, I set a precision of 9 digits because an interim calculation would result in an output of 1e-9
, which requires 9 digits of precision.