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,脚本语言(Perl和PHP)给出了0.1,但是"虚拟机"(Java,JavaScript和Erlang)提供了更类似的东西0.09999999999999998呢?
为什么它在Ruby中也不一致?版本1.8.6(键盘)给出0.1,版本1.9.3(ideone)给出了0.0999...
至于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)
这也可能是其他语言的原因
浮点数的打印方式不同,因为打印的目的不同,因此对如何打印做出了不同的选择。
\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 之间还有另一个浮点值,因此您需要额外的数字来区分它们。)
(C) 是某些语言默认使用的。从本质上讲,这是错误的,因为没有一个关于要打印的位数的单一值可以适合所有应用程序。事实上,几十年来我们已经看到它助长了对浮点的持续误解,主要是通过隐藏所涉及的真实值来实现的。然而,它很容易实现,因此对一些实现者很有吸引力。理想情况下,语言应该默认打印正确的浮点数值。如果要显示较少的数字,则数字的数量应仅由应用程序实现者选择,希望包括考虑适当的数字数量以产生所需的结果。
\n\n更糟糕的是,某些语言除了不显示实际值或足够的数字来区分它之外,甚至不保证生成的数字在某种意义上是正确的(例如将精确值四舍五入到数字后得到的值)显示的数字)。当在不提供此行为保证的实现中进行编程时,您并不是在进行工程。
\n| 归档时间: |
|
| 查看次数: |
1163 次 |
| 最近记录: |