Golang中计算两个大int64数值百分比时遇到的精度问题

Golang中计算两个大int64数值百分比时遇到的精度问题 大家好,

我有两个大的 int64 值 A 和 B,其中 B 接近 math.MaxInt64。

我想知道 A 相对于 B 的百分比是多少,也就是我想计算 (A / B) * 100。这个百分比必须是一个 float64 值。

我担心的是,当将 A 和 B 转换为 float64 再进行除法运算时,result := float64(A) / float64(B) * 100 可能会产生舍入误差。

这种担忧是否合理?根据你们的经验,我应该预期会有多大的精度损失?

4 回复

你说的是float,会有舍入误差。这是无法避免的。

如果B大于A,那么使用整数除法将始终得到0。这是一个巨大的错误率,可以认为是一个非常严重的舍入误差。

因此,通过尽早进行浮点数转换,你可能会减少舍入误差……

更多关于Golang中计算两个大int64数值百分比时遇到的精度问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这取决于您是否接受一定的精度损失,或者希望获得尽可能多小数位数的精确结果。

如果您接受精度损失,可以先将A和B预除以4096。这相当于12位,对应float64数字的符号位和指数位。这种除法确保了A和B的舍入方式相同。除以4096的操作会在A/B时被抵消。

虽然您不会得到精确的结果,但最终结果的精度可能足以满足您的需求。

我同意NobbZ的观点,但想补充说明,你或许可以通过使用 math/big 包中的 big.NewRat(*big.Rat).SetFrac64 来缓解部分舍入误差问题,然后调用 (*big.Rat).Float64。我怀疑这会比预先将 a 和 b 转换为 float64 明显更慢,但可能会得到更精确的结果?不过我不太确定。如有疑问,请测试并衡量它!

在 Go 中处理大 int64 值转换为 float64 时,精度损失是确实存在的,特别是当数值接近 math.MaxInt64 时。float64 类型使用 IEEE 754 双精度浮点数标准,其尾数部分有 53 位精度。而 int64 的范围是 -2^63 到 2^63-1,需要 64 位表示。当 int64 值超过 2^53(约 9 千万亿)时,转换为 float64 将无法精确表示所有整数,导致舍入误差。

对于你的情况,计算 (A / B) * 100,如果 A 和 B 都很大且接近 math.MaxInt64(约 9.2e18),转换到 float64 时可能丢失低位数字的精度。这会影响除法结果的准确性,尤其是当 A 远小于 B 时,百分比可能计算不精确。

为了最小化精度损失,可以先将数值转换为 float64,但注意在极端情况下误差可能显著。例如,如果 A 和 B 的差值很大,相对误差可能放大。以下是一个示例代码,演示了计算过程,并比较了直接转换与使用高精度方法(如 big.Rat)的差异:

package main

import (
    "fmt"
    "math"
    "math/big"
)

func main() {
    // 示例:A 和 B 为大的 int64 值,B 接近 math.MaxInt64
    A := int64(math.MaxInt64 - 1000)
    B := int64(math.MaxInt64)

    // 方法1: 直接使用 float64 转换
    resultFloat := float64(A) / float64(B) * 100
    fmt.Printf("使用 float64 计算的百分比: %.15f%%\n", resultFloat)

    // 方法2: 使用 math/big 库进行高精度计算
    aBig := big.NewInt(A)
    bBig := big.NewInt(B)
    hundred := big.NewInt(100)

    // 计算 (A * 100) / B
    numerator := new(big.Int).Mul(aBig, hundred)
    ratio := new(big.Rat).SetFrac(numerator, bBig)
    resultRat, _ := ratio.Float64()

    fmt.Printf("使用 big.Rat 计算的百分比: %.15f%%\n", resultRat)

    // 比较差异
    diff := math.Abs(resultFloat - resultRat)
    fmt.Printf("两种方法的差异: %e\n", diff)
}

运行此代码,你会看到 float64 直接转换与 big.Rat 高精度计算之间的差异。在大多数应用中,如果百分比不需要极高精度(例如,误差小于 0.001%),直接使用 float64 可能可接受。但如果需要更高精度,建议使用 math/big 库。

根据经验,当 B 接近 math.MaxInt64 时,精度损失通常在 1e-15 到 1e-12 相对误差范围内,具体取决于 A 和 B 的具体值。你可以通过测试你的实际数据来评估误差是否在可接受范围内。

回到顶部