为什么浮点数打印得如此不同?

rai*_*7ow 12 javascript php ruby floating-point ieee-754

大多数浮点数都没有精确存储(使用IEEE-754格式时),这是一种常见的知识.所以不应该这样做:

0.3 - 0.2 === 0.1; // very wrong
Run Code Online (Sandbox Code Playgroud)

......因为它会导致false,除非使用一些特定的任意精度的类型/类(BigDecimal的中的Java/Ruby的,bcmath时在PHP中,数学:: BigInt有/数学:: BigFloat在Perl,仅举几例)来代替.

但我想知道为什么当一个人尝试打印这个表达式的结果时0.3 - 0.2,脚本语言(PerlPHP)给出了0.1,但是"虚拟机"(Java,JavaScriptErlang)提供了更类似的东西0.09999999999999998呢?

为什么它在Ruby中也不一致?版本1.8.6(键盘)给出0.1,版本1.9.3(ideone)给出了0.0999...

dev*_*ler 7

至于php,输出与精度的ini设置有关:

ini_set('precision', 15);
print 0.3 - 0.2; // 0.1

ini_set('precision', 17);
print 0.3 - 0.2; //0.099999999999999978 
Run Code Online (Sandbox Code Playgroud)

这也可能是其他语言的原因

  • 我的善意......转换为FP号码的字符串是由INI设置控制的?他们吸烟的是什么? (10认同)
  • 地方问题的全球背景至少是无用的,最糟糕的灾难处方.如果它是一个未知的设置,代码将盲目地写入默认值,并且只要有人更改它就会中断.相反,如果它经常在不同的安装上设置为不同的值,那么只要需要不同的东西(`magic_quotes_gpc`,任何人?),你的代码就必须解决这些问题.所以,它只会使代码复杂化.解决问题的常规方法是使用固定的默认值(由语言规范保证)并提供一些方法来*本地*调整它. (7认同)
  • 在每次要显示FP编号时,让用户能够在一个地方执行此操作而不是使用`round/ceil/floor/number_format`会有什么问题? (2认同)
  • @Hiroto:然后你的脚本使用的库将停止工作,因为它预计几乎未知的设置是默认设置.解?在每次调用库之前,您必须将设置恢复为默认值 - 或者首先避免将其设置为自定义,因为它比使用更加痛苦.同样,语言功能的全球状态几乎总是一个坏主意,我被这些东西咬了很多次. (2认同)

Eri*_*hil 4

浮点数的打印方式不同,因为打印的目的不同,因此对如何打印做出了不同的选择。

\n\n

打印浮点数是一种转换操作:以内部格式编码的值转换为十进制数字。然而,关于转换的细节是有选择的。

\n\n

(A)如果您正在进行精确的数学计算并希望查看内部格式表示的实际值,则转换必须精确:它必须生成与输入值完全相同的十进制数字。(每个浮点数恰好代表一个数字。IEEE 754 标准中定义的浮点数并不代表区间。)有时,这可能需要生成大量数字。

\n\n

(B)如果您不需要精确的值,但确实需要在内部格式和小数之间来回转换,那么您需要将其足够精确地(准确地)转换为十进制数字,以将其与任何其他结果区分开。也就是说,您必须产生足够的数字,使得结果与转换内部格式中相邻的数字所得到的结果不同。这可能需要产生大量的数字,但又不能多到难以管理。

\n\n

(C)如果您只想让读者了解数字,并且不需要生成准确的值以使您的应用程序按预期运行,那么您只需生成您的应用程序所需的数字即可特定应用。

\n\n

转换应该执行以下哪些操作?

\n\n

不同的语言有不同的默认值,因为它们是为不同的目的而开发的,或者因为在开发过程中不方便完成产生精确结果所需的所有工作,或者由于各种其他原因。

\n\n

(A) 需要仔细的代码,并且某些语言或其实现不提供或不保证提供这种行为。

\n\n

我相信 (B) 是 Java 所要求的。然而,正如我们在最近的一个问题中看到的,它可能会出现一些意想不到的行为。(65.12打印为 \xe2\x80\x9c65.12\xe2\x80\x9d 因为后者有足够的数字来区分它与附近的值,但65.12-2打印为 \xe2\x80\x9c63.120000000000005\xe2\x80\x9d 因为它和 63.12 之间还有另一个浮点值,因此您需要额外的数字来区分它们。)

\n\n

(C) 是某些语言默认使用的。从本质上讲,这是错误的,因为没有一个关于要打印的位数的单一值可以适合所有应用程序。事实上,几十年来我们已经看到它助长了对浮点的持续误解,主要是通过隐藏所涉及的真实值来实现的。然而,它很容易实现,因此对一些实现者很有吸引力。理想情况下,语言应该默认打印正确的浮点数值。如果要显示较少的数字,则数字的数量应仅由应用程序实现者选择,希望包括考虑适当的数字数量以产生所需的结果。

\n\n

更糟糕的是,某些语言除了不显示实际值或足够的数字来区分它之外,甚至不保证生成的数字在某种意义上是正确的(例如将精确值四舍五入到数字后得到的值)显示的数字)。当在不提供此行为保证的实现中进行编程时,您并不是在进行工程。

\n