双精度(IEEE754双精度 64 位)二进制表示形式

Double (IEEE754 Double precision 64-bit) binary representation

提问人:CoderGuy 提问时间:9/22/2022 更新时间:9/24/2022 访问量:190

问:

我想将 Java 双精度(IEEE754 双精度 64 位)转换为二进制表示形式,修改 21 个最低有效位以将一些元数据嵌入到双精度中,将其转换回双精度,并保持 6 位小数精度。

约束:我将要处理的双精度值将始终在 [-180, 180] 范围内。

例:

Double value: -145.88160204733163

IEEE754 Double precision 64-bit binary:

1100 0000 0110 0010 0011 1100 0011 0110 0001 0101 0111 1111 0010 1100 0000 1000

IEEE754 Double precision 64-bit binary with 21 least significant bits modified:

1100 0000 0110 0010 0011 1100 0011 0110 0001 0101 0110 0010 1001 1000 0110 0101

Double value with 21 least significant bits modified:
-145.88160199410336

我知道符号需要保持 1 位,指数需要保持 11 位,-180 到 180 之间的整数需要保留 7 位。由于我需要保持 6 位小数位的精度,我认为额外的 24 位有效数字足以保持 6 位小数位的精度(因为每个数字需要 3.32 位,我在这里的理解可能不正确),所以我可以使用 21 位最低有效位来嵌入元数据。

我想知道我在哪里误解了 64 位双精度是如何以二进制表示的,以及是否有任何其他方法可以在不损失所需精度的情况下修改双精度的位。

任何意见都非常感谢!

Java 浮点 精度

评论

0赞 Tim Roberts 9/22/2022
你的计算基本上是正确的。尾数是 52 位,所以砍掉 21 叶 31,或大约 9 位。您显然保留了 8 位精度 (145.88160)。请记住,“6 位小数位”并不意味着“小数点后 6 位”。它从第一个有效数字开始。
0赞 Dawood ibn Kareem 9/22/2022
对我来说看起来不错。您的“之前”和“之后”数字相同,精确到小数点后 7 位。使用您的策略,您可以稍微增加或略微减少数字,当您这样做时,它总是有可能超过 0.000001 的倍数。因此,打印的前六位小数总是有可能不同(就像这里发生的那样),但“之前”和“之后”数字之间的差异将始终远小于 0.000001。
1赞 Dawood ibn Kareem 9/23/2022
正如我之前所解释的,更改最低有效 21 位可以非常轻微地增加或减少数字,使其超过 0.0000001 的倍数。换句话说,它可以更改数字小数点后扩展的前 7 位中的任何一位;你对此绝对无能为力。
1赞 chux - Reinstate Monica 9/23/2022
@CoderGuy 是否可以“修改超过 21 个最低有效位以将指定的 21 位元数据嵌入到双精度中,将其转换回双精度,并保持小数点后 6 位的精度”?示例:使 x a 1/1100 0000 0110 0010 0011 1100 0011 0110 0001 0101 x110 0010 1001 1000 0110 0101。
1赞 chux - Reinstate Monica 9/23/2022
@CoderGuy IOW 中,取您的值并以十进制形式形成中点 sddd.dddddd5,然后调整该值的下 21 位。取中点可降低有效负载影响 sddd.dddddd 十进制值的几率。我认为它可能适用于所有的地方,但尚未进行分析。知道你为什么要这样做也会有所帮助。是否需要很难检测到值是否发生了变化?double x|x| < 256

答:

1赞 chux - Reinstate Monica 9/24/2022 #1

当 OP 代码更改 IEEE754 双精度 64 位值的 21 个最低有效位时,结果是大于或小于原始值的值。有时,即使只有 1 个最低有效位的变化就足以在打印到 6 个小数位时更改输出。Double


考虑十进制值 ddd.dddddd5,其中数字为 0-9。我们有一个介于两个 ddd.dddddd 值之间的值。该值很少可以精确编码为 *1。使用附近,当打印有 6 位小数时,四舍五入到最接近的 0.000001。输出是 ddd.dddddd 或 0.000001 以上,具体取决于最接近的值是比 ddd.dddddd5 多一点还是少一点。dDoubleDoubleDouble

如果它打印为 ddd.dddddd,并且有效负载大于原始 21 位 - 即使只是 1 个最低有效位,该值也会多打印 0.000001。同样,如果它打印为 ddd.dddddd + 0.000001 并且有效负载较小,则打印为 dddd.dddddd。

为了实现 OP 的目标,我们可以将值四舍五入到最接近的 0.000001,以使它们远离 ddd.dddddd5 边界。然后,我们可以成功地替换 OP 所描述和推理的至少 21 位。

倒圆角很棘手,因为许多倒圆角技术无法正确处理边缘条件,例如较差的 .这里的问题是并不总是形成一个精确的产品——这对于边缘情况至关重要。round(x*1000000.0)/1000000.0x * 1000000.0

我不精通 java,但打印到 6 位小数并转换回可以解决问题。Double


请注意,这个答案与我的评论不同。在这种情况下,我专注于不更改值 ddd.ddddddxxxxxx 的数字(如果打印到许多小数位)。正如我现在所看到的,OP 在打印到小数点后 6 位时想要相同的输出。d

*1所有 ,当精确表示时,都具有 0.0、0.5、0.25、0.75、0.125、0.375、0.625、0.875 等小数分数。不是 0.1、0.2、0.3、0.4、0.6、......Double

评论

0赞 CoderGuy 9/24/2022
澄清一下,我想“如果打印到所有小数位,请不要更改值 ddd.ddddddxxxxxx 的 d 位”。当我尝试设置 sddd.dddddd5 时,这导致 d 位发生变化,但是当我使用 sddd.dddddd555555555 然后替换最低有效位时,d 位没有改变
0赞 chux - Reinstate Monica 9/24/2022
@CoderGuy 请考虑将值四舍五入到最接近的 ddd.dddddd25 或 ddd.dddddd75,使其远离最接近的 ddd.dddddd5 和 ddd.dddddd0。