为了账号安全,请及时绑定邮箱和手机立即绑定

如何以正确的方式将 float64 数字更改为 uint64?

如何以正确的方式将 float64 数字更改为 uint64?

Go
三国纷争 2021-10-18 10:29:36
package mainfunc main() {    var n float64 = 6161047830682206209    println(uint64(n))}输出将是:6161047830682206208看起来,当float64更改为 时uint64,分数被丢弃。
查看完整描述

2 回答

?
月关宝盒

TA贡献1772条经验 获得超5个赞

这里的问题是常量和浮点数的表示。


常量以任意精度表示。浮点数使用IEEE 754标准表示。


规格:常数:


数字常量表示任意精度的值并且不会溢出。


规格:数字类型:


float64     the set of all IEEE-754 64-bit floating-point numbers

在 IEEE 754 中,使用 64 位(float64在 Go 中)的双精度53 位用于存储数字。这意味着可以表示的最大位数(max number)是其中的位数2<<52(1位用于符号):


2<<52        : 9007199254740992

Your constant: 6161047830682206209

准确地说是 15.95 位(16 位,但不是您可以用 16 位描述的所有值,最多只能是9007199254740992)。


您尝试放入类型变量的整数常量float64根本不适合 52 位,因此必须四舍五入并且数字(或位)将被截断(丢失)。


您可以通过打印原始n float64号码来验证这一点:


var n float64 = 6161047830682206209

fmt.Printf("%f\n", n)

fmt.Printf("%d\n", uint64(n))

输出:


6161047830682206208.000000

6161047830682206208

问题不在于转换,问题在于float64您尝试转换的值已经不等于您尝试分配给它的常量。


只是出于好奇:


尝试使用更大的数字:与第一个常量相比+500:


n = 6161047830682206709 // +500 compared to first!

fmt.Printf("%f\n", n2)

fmt.Printf("%d\n", uint64(n2))

输出仍然相同(最后一位数字/位被截断,包括+500!):


6161047830682206208.000000

6161047830682206208

尝试一个较小的数字,其数字可以使用 52 位(小于 ~16 位)精确表示:


n = 7830682206209

fmt.Printf("%f\n", n)

fmt.Printf("%d\n", uint64(n))

输出:


7830682206209.000000

7830682206209

在Go Playground上试一试。


查看完整回答
反对 回复 2021-10-18
?
慕运维8079593

TA贡献1876条经验 获得超5个赞

问题不在于转换,而在于数字太大,无法完全存储为float64. 分配给n导致一些意义的损失。

如果你仔细想想,你的数字(大约 6e18)非常接近最大的uint64(2^64-1 或大约 18e18)。Auint64使用全部 64 位来存储整数,但float64必须使用其 64 位中的一部分来存储指数,因此它可以使用更少的位来记住尾数。

总之,如果您将一个uint64大于 10^15的(或整数常量)分配给 afloat64并返回给 a,uint64您将获得一个接近但可能不完全相同的值。

[BTW Icza 的回答很好而且正确。我希望这个答案是简单的总结。]


查看完整回答
反对 回复 2021-10-18
  • 2 回答
  • 0 关注
  • 353 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信