Golang - How to turn an exponent and mantissa to a float64 or float32

Viewed 61

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

2 Answers

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.

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.

Related