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

Time:09-13

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.

  •  Tags:  
  • go
  • Related