【问题标题】:golang convert big.Float to big.Intgolang 将 big.Float 转换为 big.Int
【发布时间】:2017-11-29 05:47:16
【问题描述】:

将 big.Float 转换为 big.Int,我在下面写了代码,但是它会溢出 uint64,那么将 big.Float 转换为 big.Int 的正确方法是什么。

package main

import "fmt"
import "math/big"

func FloatToBigInt(val float64) *big.Int {
    bigval := new(big.Float)
    bigval.SetFloat64(val)

    coin := new(big.Float)
    coin.SetInt(big.NewInt(1000000000000000000))
    bigval.Mul(bigval, coin)

    result := new(big.Int)
    f,_ := bigval.Uint64()
    result.SetUint64(f)

    return result
}

func main() {
    fmt.Println("vim-go")
    fmt.Println(FloatToBigInt(float64(10)))
    fmt.Println(FloatToBigInt(float64(20)))
    fmt.Println(FloatToBigInt(float64(30)))
    fmt.Println(FloatToBigInt(float64(40)))
    fmt.Println(FloatToBigInt(float64(50)))
    fmt.Println(FloatToBigInt(float64(100)))
    fmt.Println(FloatToBigInt(float64(1000)))
    fmt.Println(FloatToBigInt(float64(10000)))
}

【问题讨论】:

    标签: go


    【解决方案1】:

    大于uint64 的大整数总是会导致溢出,因为uint64 具有固定大小。您应该在*Float 上使用以下method

    func (*Float) Int
    

    所需的更改是:

    func FloatToBigInt(val float64) *big.Int {
        bigval := new(big.Float)
        bigval.SetFloat64(val)
        // Set precision if required.
        // bigval.SetPrec(64)
    
        coin := new(big.Float)
        coin.SetInt(big.NewInt(1000000000000000000))
    
        bigval.Mul(bigval, coin)
    
        result := new(big.Int)
        bigval.Int(result) // store converted number in result
    
        return result
    }
    

    工作示例:https://play.golang.org/p/sEhH6iPkrK

    【讨论】:

    • 感谢它有效。但是你看到这个例子play.golang.org/p/P02AN1e09C它也有一些问题。
    • bigval 的默认精度为 53 位。您需要增加此值才能获得准确的结果:play.golang.org/p/Xy88JX57JE。您需要阅读浮点精度文档以确定程序所需的位数。
    【解决方案2】:

    使用函数Float.Int(nil)

    【讨论】:

      【解决方案3】:

      我使用了一个常规的 float64 数字(不是 big.Float),发现通过字符串进行转换是最精确的方式。看看吧

      注意:示例是用于 float64 -> decimal(,20) 转换。

      func bigIntViaString(flt float64) (b *big.Int) {
      
          if math.IsNaN(flt) || math.IsInf(flt, 0) {
              return nil // illegal case
          }
      
          var in = strconv.FormatFloat(flt, 'f', -1, 64)
      
          const parts = 2
      
          var ss = strings.SplitN(in, ".", parts)
      
          // protect from numbers without period
          if len(ss) != parts {
              ss = append(ss, "0")
          }
      
          // protect from ".0" and "0." values
          if ss[0] == "" {
              ss[0] = "0"
          }
      
          if ss[1] == "" {
              ss[1] = "0"
          }
      
          const (
              base     = 10
              fraction = 20
          )
      
          // get fraction length
          var fract = len(ss[1])
          if fract > fraction {
              ss[1], fract = ss[1][:fraction], fraction
          }
      
          in = strings.Join([]string{ss[0], ss[1]}, "")
          // convert to big integer from the string
          b, _ = big.NewInt(0).SetString(in, base)
          if fract == fraction {
              return // ready
          }
          // fract < 20, * (20 - fract)
          var (
              ten = big.NewInt(base)
              exp = ten.Exp(ten, big.NewInt(fraction-int64(fract)), nil)
          )
          b = b.Mul(b, exp)
          return
      
      }
      

      https://play.golang.org/p/_lkyQ_0udjd

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-31
        • 1970-01-01
        • 2016-08-26
        • 1970-01-01
        • 2018-12-09
        • 2022-10-23
        • 2016-01-01
        • 1970-01-01
        相关资源
        最近更新 更多