【问题标题】:Double (IEEE754 Double precision 64-bit) binary representationDouble(IEEE754 双精度 64 位)二进制表示
【发布时间】:2022-09-24 05:10:37
【问题描述】:

我想将 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 位双精度如何用二进制表示,以及是否有任何其他方法可以修改双精度位而不丢失所需的精度。

非常感谢任何输入!

  • 你的计算基本上是正确的。尾数是 52 位,因此砍掉 21 会留下 31 位,即大约 9 位。您清楚地保留了 8 位精度(145.88160)。请记住,“6 位小数”并不意味着“小数点后 6 位”。它从第一个有效数字开始。
  • 在我看来很好。您的 \"before\" 和 \"after\" 数字是相同的,保留 7 个小数位。使用您的策略,您可以稍微增加或减少数字,当您这样做时,它总是有可能超过 0.000001 的倍数。所以总是有可能打印的前六位小数会不同(就像这里发生的那样),但是“之前”和“之后”数字之间的差异总是远远小于 0.000001。
  • 正如我之前解释的,更改最低有效 21 位可以非常轻微地增加或减少数字,使其超过 0.0000001 的倍数。换句话说,它可以改变数字的小数扩展的前 7 位中的任何一个;你绝对无能为力。
  • @CoderGuy 可以“修改”吗多于要嵌入的 21 个最低有效位指定的 21 位元数据转换为双精度,将其转换回双精度,并保持 6 位小数的精度\"?示例将 x 设为 1 in 1100 0000 0110 0010 0011 1100 0011 0110 0001 0101 x110 0010 1001 1000 0110 0101。
  • @CoderGuy IOWs,取您的值并以十进制形式 sddd.dddddd5 形成中点,并调整该值的低 21 位。取中点可以减少有效负载影响 sddd.dddddd 十进制值的机会。我思考它可能适用于|x| < 256 的所有double x,但尚未完成分析。会心为什么你想这样做也会有帮助。有必要难吗探测值改变了吗?

标签: java floating-point double precision floating-accuracy


【解决方案1】:

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


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

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

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

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

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


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

*1全部Double,表达时确切地小数部分为 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, ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 2010-10-19
    相关资源
    最近更新 更多