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

不同编程语言中的浮点数学

吕永寿
2023-03-14
问题内容

我知道浮点数学充其量可能很难看,但我想知道是否有人可以解释以下怪癖。在大多数编程语言中,我测试了0.4到0.2的添加会产生轻微的错误,而0.4 + 0.1
+ 0.1会给出非错误。

计算不均的原因是什么,人们可以在相应的编程语言中采取什么措施以获得正确的结果。

在python2 / 3中

.4 + .2
0.6000000000000001
.4 + .1 + .1
0.6

在Julia 0.3中也是如此

julia> .4 + .2
0.6000000000000001

julia> .4 + .1 + .1
0.6

和Scala:

scala> 0.4 + 0.2
res0: Double = 0.6000000000000001

scala> 0.4 + 0.1 + 0.1
res1: Double = 0.6

和Haskell:

Prelude> 0.4 + 0.2
0.6000000000000001    
Prelude> 0.4 + 0.1 + 0.1
0.6

但是R v3正确了:

> .4 + .2
[1] 0.6
> .4 + .1 + .1
[1] 0.6

问题答案:

所有这些语言都使用系统提供的浮点格式,该格式以 二进制 而非 十进制
表示值。像0.20.4不能完全以这种格式表示的值,因此存储了最接近的可表示值,从而导致较小的错误。例如,数字文字会0.2产生一个浮点数,其精确值为0.200000000000000011102230246251565404236316680908203125。同样,对浮点数进行任何给定的算术运算都可能导致无法精确表示的值,因此,将实际的数学结果替换为最接近的可表示值。这些是您所看到的错误的根本原因。

但是,这并不能解释语言之间的差异:在所有示例中,都进行了完全相同的计算,并且得出了完全相同的结果。区别在于各种语言选择 显示 结果的方式。

严格来说,您显示的答案 都不 正确。使用舍入到最近舍入模式进行IEEE 754二进制64算法的(相当安全)假设,第一个和的确切值为:

0.600000000000000088817841970012523233890533447265625

而第二和的确切值是:

0.59999999999999997779553950749686919152736663818359375

但是,这些输出都不是特别用户友好的,显然您测试的所有语言都做出了明智的决定,即在打印时缩写输出。但是,它们并非全部采用相同的格式来格式化输出,这就是为什么您会看到差异的原因。

格式化有多种可能的策略,但是三种特别常见的策略是:

  1. 计算并显示17个正确舍入的有效数字,可能会去除出现的尾随零。17位数字的输出保证了不同的binary64浮点数将具有不同的表示形式,因此可以从其表示形式中明确地恢复浮点值;17是具有此属性的最小整数。例如,这就是Python 2.6使用的策略。

  2. 计算并显示最短的十进制字符串,该字符串在通常的“从四舍五入到四舍五入”舍入模式下会四舍五入到给定的binary64值。它的实现比策略1复杂得多,但是保留了不同的float具有不同表示形式的特性,并且倾向于提供更令人愉悦的输出。这似乎是您测试的所有语言(R除外)都使用的策略。

  3. 计算并显示15个(或更少)正确舍入的有效数字。这样可以隐藏十进制到二进制转换中涉及的错误,从而给人以精确十进制算术的错觉。它的缺点是不同的浮点数可以具有相同的表示形式。这似乎是R在做什么。(感谢@hadley在注释中指出,有一个R设置可以控制用于显示的数字位数;默认设置是使用7个有效数字。)



 类似资料:
  • 问题内容: 我知道浮点数学充其量可能很难看,但我想知道是否有人可以解释以下怪癖。在大多数编程语言中,我测试了0.4到0.2的添加会产生轻微的错误,而0.4 + 0.1 + 0.1会给出非错误。 计算不均的原因是什么,人们可以在相应的编程语言中采取什么措施以获得正确的结果。 在python2 / 3中 在Julia 0.3中也是如此 和Scala: 和Haskell: 但是R v3正确了: 问题答案

  • null 他们解释“如何”。我想知道为什么这些语言之间的差异。我期望在相同的输入下得到相似的结果。 test.js test.java 结果: 要旨:https://gist.github.com/reklis/6694AD5FB01991A79A1A

  • Go语言提供了两种精度的浮点数 float32 和 float64,它们的算术规范由 IEEE754 浮点数国际标准定义,该浮点数规范被所有现代的 CPU 支持。 这些浮点数类型的取值范围可以从很微小到很巨大。浮点数取值范围的极限值可以在 math 包中找到: 常量 math.MaxFloat32 表示 float32 能取到的最大数值,大约是 3.4e38; 常量 math.MaxFloat64

  • VB程序专用断点 bp __vbaStrCmp 比较字符串是否相等 bp __vbaStrComp 比较字符串是否相等 bp __vbaVarTstNe 比较变量是否不相等 bp __vbaVarTstEq 比较变量是否相等 bp __vbaStrCopy 复制字符串 bp __vbaStrMove 移动字符串 bp MultiByteToWideChar ANSI字符串转换成Unicode字符串

  • 1.1.4 汇编语言的主要特点 一方面,汇编语言指令是用一些具有相应含义的助忆符来表达的,所以,它要比机器语言容易掌握和运用,但另一方面,它要直接使用CPU的资源,相对高级程序设计语言来说,它又显得难掌握。 汇编语言程序归纳起来大概有以下几个主要特性。 1、与机器相关性 汇编语言指令是机器指令的一种符号表示,而不同类型的CPU有不同的机器指令系统,也就有不同的汇编语言,所以,汇编语言程序与机器有着

  • 问题内容: 我正在尝试使用包含大量16位浮点数的javascript读取二进制文件。可以肯定的是它是IEEE标准,低位字节序。将两个字节读入一个int非常简单,但是从那里将其扩展为一个完整的浮点数并没有太大的成功。有什么线索吗? 问题答案: 我最终根据Wikipedia页面上的信息实现了自己的解析器。它可能不是最快的,但是我对此不太担心。这里是那些好奇的人: