浮点数的打印方式不同,因为打印是为了不同的目的而进行的,因此对于如何进行打印做出了不同的选择。
打印浮点数是一种转换操作:以内部格式编码的值被转换为十进制数字。但是,对于转换的细节有一些选择。
(A)如果你在做精确的数学运算,想看到内部格式表示的实际值,那么转换必须是精确的:它必须产生一个与输入值完全相同的十进制数字。(每个浮点数只代表一个数字。在 IEEE 754 标准中定义的浮点数不代表一个区间。)有时,这可能需要产生非常多的数字。
(B)如果您不需要确切的值,但确实需要在内部格式和十进制之间来回转换,那么您需要将其精确地(并且准确地)转换为十进制数字,以将其与任何其他结果区分开来。也就是说,您必须生成足够多的数字,以使结果与通过转换内部格式中相邻的数字所获得的结果不同。这可能需要产生大量的数字,但不能多到难以管理。
(C)如果您只想让读者了解数字,而不需要生成确切的值以使您的应用程序按需要运行,那么您只需要生成您的应用程序所需的尽可能多的数字特定的应用。
其中哪些应该转换?
不同的语言有不同的默认值,因为它们是为不同的目的而开发的,或者因为在开发过程中做所有必要的工作以产生准确的结果并不方便,或者出于各种其他原因。
(A) 需要仔细的代码,并且某些语言或它们的实现不提供或不保证提供这种行为。
我相信(B)是Java所要求的。但是,正如我们在最近的一个问题中看到的那样,它可能会有一些意想不到的行为。(65.12
打印为“65.12”,因为后者有足够的位数将其与附近的值区分开来,但65.12-2
打印为“63.120000000000005”,因为它和 63.12 之间还有另一个浮点值,因此您需要额外的数字来区分它们。 )
(C) 是某些语言默认使用的。从本质上讲,这是错误的,因为对于要打印的位数,没有一个值可以适用于所有应用程序。事实上,几十年来我们已经看到它助长了对浮点的持续误解,主要是通过隐藏所涉及的真实值。然而,它很容易实现,因此对一些实现者很有吸引力。理想情况下,语言应该默认打印浮点数的正确值。如果要显示的位数较少,则应仅由应用程序实施者选择位数,希望包括考虑适当的位数以产生所需的结果。
Worse, some languages, in addition to not displaying the actual value or enough digits to distinguish it, do not even guarantee that the digits produced are correct in some sense (such as being the value you would get by rounding the exact value to the number of digits shown). When programming in an implementation that does not provide a guarantee about this behavior, you are not doing engineering.