了解 C# 和 Java 中的 IEEE-754 64 位定点表示

ser*_*0ne 2 c# java double ieee-754

考虑以下 Java 代码:

public class Program {
    public static void main(String args[]) {
      double number = Double.MAX_VALUE;
      String formattedNumber = String.format("%f", number);
      System.out.println(formattedNumber);
    }
}
Run Code Online (Sandbox Code Playgroud)

179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000.000000

考虑等效的 C# 代码:

public class Program
{
    public static void Main(string[] args)
    {
        double value = double.MaxValue;
        Console.WriteLine(value.ToString("F"));
    }
}
Run Code Online (Sandbox Code Playgroud)

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234 32132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334 8274797826204144723168738177180919299881250404026184124858368.000

鉴于 的最大值Double为 1.7976931348623157E+308,据我所知,Java 输出是正确的;即浮点值实际上表示一个整数,其中前 17 位数字为 17976931348623157,后跟 292 个零。

注意:在 C# 中转换doubleBigInteger会产生相同的结果:

BigInteger value = (BigInteger)double.MaxValue;
Console.WriteLine(value);
Run Code Online (Sandbox Code Playgroud)

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234 32132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334 8274797826204144723168738177180919299881250404026184124858368

问题

  • 为什么这些值差异很大,哪一个应该被认为是正确的?
  • 如果 C# 实际上不正确,我如何获得与 Java 生成的正确或相同的输出?

Eri*_*hil 6

\n

假设 Double 的最大值为 1.7976931348623157E+308\xe2\x80\xa6

\n
\n

这是不正确的。使用的格式Double是IEEE 754-2019标准中指定的binary64或\xe2\x80\x9c双精度\xe2\x80\x9d格式。在此格式中,有限数表示为 \xc2\xb1 f \xe2\x80\xa22 e,其中f是表示形式的小数部分,是由前面带有一位数字(0 或 1)的二进制数字表示的数字小数点及其后的 52 位和指数e是 [\xe2\x88\x921022, 1023] 中的整数。因此,最大可表示的有限值为 +1.11111111111111111111111111111111111111111111111111111 2 \xe2\x80\xa22 1023,等于 +(2 1 \ xe2\x88\x922 \xe2\x88\x9252 )\x e2\x80\xa22 1023 = 2 1024 \xe2\ x88\x922 971 , which is exactly 179,769,313,486,231,570,814,527,423,731,704,356,798,070,567,525,844,996,598,917,476,803,157,260,780,028,538,760,589,558,632,766,878,171,540,458,953,514,382,464,234,321,326,889,464,182,768,467,546,703,537,516,986,049,910,576,551,282,076,245,490,090,389,328,944,075,868,508,455,133,942,304,583,236,903,222,948,165,808,559,332,123,348,274,797,826,204,144,723,168,738,177,180,919,299,881,250,404,026,184,124,858,368, so the C# output is correct.

\n

Java 输出省略有效数字并隐藏真实值。这是因为 Java 规范规定,对于默认格式\xe2\x80\x9c ,必须至少有一位数字来表示小数部分,除此之外,还有尽可能多的数字来唯一区分来自类型double.\xe2\x80\x9d的相邻值的参数值

\n