当前位置: 首页 > 面试题库 >

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

宋博易
2023-03-14
问题内容

众所周知,(大多数)浮点数没有精确存储(使用IEEE-754格式时)。因此,不应这样做:

0.3 - 0.2 === 0.1; // very wrong

......因为它会导致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...


问题答案:

由于打印是出于不同的目的而进行的,因此浮点数的打印方式有所不同,因此如何进行浮点选择。

打印浮点数是一种转换操作:以内部格式编码的值将转换为十进制数字。但是,可以选择有关转换的详细信息。

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

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

(C) 如果您只想让读者理解数字,而无需产生确切的值以使您的应用程序按需运行,那么您只需要产生所需位数即可特定的应用程序。

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

不同的语言具有不同的默认值,这是因为它们是为不同的目的而开发的,或者因为在开发过程中不方便地进行所有操作以产生准确的结果,或者是由于其他各种原因。

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

我相信(B)是Java要求的。但是,正如我们在最近的问题中看到的那样,它可能会有一些意外的行为。(65.12被打印为“
65.12”,因为后者有足够的数字来将其与附近的值区分开,但65.12-2被打印为“
63.120000000000005”,因为它与63.12之间存在另一个浮点值,因此您需要额外的数字来将它们区分开。 )

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

更糟糕的是,某些语言除了不显示实际值或足够的数字以区别它之外,甚至不保证所产生的数字在某种意义上是正确的(例如,您可以通过将精确值四舍五入而得到的值)显示的位数)。在无法提供有关此行为保证的实现中进行编程时,您未在进行工程设计



 类似资料:
  • 问题内容: 我想知道当您尝试捕获StackOverflowError并提出以下方法时会发生什么: 现在我的问题是: 为什么此方法打印“ 4”? 我以为是因为在调用堆栈上需要3个段,但是我不知道3的来源。当您查看的源代码(和字节码)时,通常导致的方法调用要多于3(因此,调用堆栈上的3个段是不够的)。如果是由于优化而应用了Hotspot VM(方法内联),我想知道其他VM上的结果是否会有所不同。 编辑

  • 这样一个看似简单的数字怎么会“太大”而无法在64位内存中表达呢?

  • 问题内容: 我不明白为什么编译器从字典中打印值会有所不同?我使用的是Swift 3,Xcode8。这是错误还是优化内容的怪异方法? 编辑 更奇怪的是: 有些价值观过去了,有些则跌破了,有些则保持不变!1.1小于1.1000000000000001,而2.3大于2.2999999999999998,1.2仅为1.2 问题答案: 如注释中已经提到的,a 不能精确存储值。Swift根据IEEE 754

  • 问题内容: 文本文件中确实包含int和字符串。我可以从文本文件中打印单词,但不能打印数字。 文本文件包括以下内容: Michael 3000 7000 Bilbo 我喜欢2000号吗? 不,我喜欢9000 问题答案: 您的第一个值(“ Michael”) 不是 整数,因此它永远不会进入循环主体。 也许您想更改代码以使其循环播放,直到到达文件末尾,读取并打印整数,但使用(不打印)非整数值。所以像这样

  • 我可以用< code>System.out.print来做吗?

  • 问题内容: 我有一个以指数形式输出的数字: 如何使它以普通格式打印? 问题答案: 您可以将其格式化为定点数字。