问题描述
据我所知,在 Go 中可以将 int64 转换为 float64,该语言允许使用 float64(some_int64_variable)
进行转换,但我也知道并非所有 64 位有符号整数都可以用 double 表示(因为 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),那么这个计算就可以了。
回答“它安全吗”确实需要更好地了解您的需求,以及您对这些数字的确切用途。那么让我们问一个相关但更精确的问题,我们可以肯定地回答:
float64
不能准确表示的最小正整数值是多少?
对于 int64
,这个数字原来是 9007199254740993
。这是float64
“跳过”的第一个整数。
这可能看起来相当大,也许并不那么令人震惊。 (如果这些是“美分”,那么我相信大约是 90 万亿美元左右。)但是如果您使用单精度浮点数,答案可能会让您感到惊讶。如果您使用 float32
,则该数字为:16777217
。约 168,000 美元,如果解释为美分。还好你没有使用单精度浮点数!
根据经验,您永远不应该使用 float
类型(无论精度如何)来处理金钱。浮点数实际上不是为“金钱”而设计的,如离散量,而是处理科学应用中出现的小数值。舍入错误可能会逐渐增加,从而影响您的计算。改用大整数表示。大整数实现可能会更慢,因为它们主要是在软件中实现的,但是如果您正在处理货币计算,我会猜测您实际上并不需要硬件可以提供的浮点计算速度。