从 int64 转换为 float64 安全吗?

It it safe to convert from int64 to float64?

据我所知,int64 可以在 Go 中转换为 float64,该语言允许使用 float64(some_int64_variable),但我也知道并非所有 64 位有符号整数都可以用双精度表示(因为 IEE754近似值)。

我们有一些代码可以使用 int64 接收以美分为单位的商品价格,并执行类似

的操作
const TB                    = 1 << 40

func ComputeSomething(numBytes int64) {
    Terabytes := float64(numBytes) / float64(TB)

我想知道这有多安全,因为并非所有整数都可以用双精度表示。

取决于你所说的“安全”是什么意思。

是的,在某些情况下这里可能会丢失精度。 float64 不能精确表示 int64 的所有值(因为它只有 53 位尾数)。所以如果你需要一个完全准确的结果,这个功能是不“安全”的;如果你想在 float64 中代表金钱,你 may get into trouble.

另一方面,您真的需要绝对精度的 TB 数吗? numBytes 实际上会准确地除以 TB 吗?这不太可能,但这完全取决于您的规格和需求。如果您的代码有一个字节计数器,并且您想显示大约有多少 TB(例如 0.05 TB 或 2.124 TB),那么这个计算就可以了。

回答“安全吗”确实需要更好地了解您的需求,以及您对这些数字的确切用途。那么让我们问一个相关但更精确的问题,我们可以肯定地回答:

What is the minimum positive integer value that float64 cannot exactly represent?

对于int64,这个数字原来是9007199254740993。这是 float64“跳过”的第一个整数。

这可能看起来很大,也许并不那么令人担忧。 (如果这些是“分”,那么我相信大约是 90 万亿美元左右。)但是如果你使用单精度浮点数,答案可能会让你大吃一惊。如果您使用 float32,则该数字为:16777217。约 16.8 万美元,如果解释为美分。还好你没有使用单精度浮点数!

根据经验,您永远不应使用 float 类型(无论其精度如何)来处理金钱。浮点数实际上不是像离散量那样为“金钱”设计的,而是处理科学应用中出现的分数值。舍入误差可能会逐渐增加,从而影响您的计算。改用大整数表示。大整数的实现可能会更慢,因为它们主要是在软件中实现的,但如果你正在处理货币计算,我猜你并不真的需要硬件可以提供的浮点计算速度。