i <- 0.1
i <- i + 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
4 回答
305
添加到Brian的评论(这是原因),您可以通过使用 all.equal 代替:
# i <- 0.1
# i <- i + 0.05
# i
#if(all.equal(i, .15)) cat("i equals 0.15\n") else cat("i does not equal 0.15\n")
#i equals 0.15
Per Joshua's warning here is the updated code (Thanks Joshua):
i <- 0.1
i <- i + 0.05
i
if(isTRUE(all.equal(i, .15))) { #code was getting sloppy &went to multiple lines
cat("i equals 0.15\n")
} else {
cat("i does not equal 0.15\n")
}
#i equals 0.15
?.Machine
#....
#double.eps the smallest positive floating-point number x
#such that 1 + x != 1. It equals base^ulp.digits if either
#base is 2 or rounding is 0; otherwise, it is
#(base^ulp.digits) / 2. Normally 2.220446e-16.
#....
.Machine$double.eps
#[1] 2.220446e-16
sprintf("%a",.Machine$double.eps)
#[1] "0x1p-52"
?all.equal
#....
#all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
#....
#all.equal(target, current,
# tolerance = .Machine$double.eps ^ 0.5,
# scale = NULL, check.attributes = TRUE, ...)
#....
tolerance = .Machine$double.eps^0.5
# this is the default tolerance used in all.equal,
# but you can pick a different tolerance to match your needs
abs(a - b) < tolerance
#[1] TRUE TRUE TRUE FALSE
4 回答
添加到Brian的评论(这是原因),您可以通过使用
all.equal
代替:Per Joshua's warning here is the updated code (Thanks Joshua):
dplyr::near()
是测试两个浮点数向量是否相等的选项 . 这是docs中的示例:该功能具有内置公差参数:
tol = .Machine$double.eps^0.5
可以调整 . 默认参数与all.equal()
的默认参数相同 .这是hackish,但很快:
一般(语言不可知)的原因
由于并非所有数字都可以在IEEE floating point arithmetic(几乎所有计算机用来表示十进制数字并使用它们进行数学运算的标准)中准确表示,因此您并不总是得到您期望的结果 . 这尤其正确,因为一些简单的有限小数值(例如0.1和0.05)在计算机中没有完全表示,因此对它们的算术结果可能不会给出与"known"的直接表示相同的结果 . 回答 .
这是众所周知的计算机算术限制,并在以下几个地方进行了讨论:
R常见问题专门讨论它:R FAQ 7.31
The R Inferno by Patrick Burns将第一个"Circle"用于此问题(从第9页开始)
David Goldberg,2077778 ACM Computing Surveys 23 ,1(1991-03),5-48 doi>10.1145/103162.103163(revision also available)
The Floating-Point Guide - What Every Programmer Should Know About Floating-Point Arithmetic
0.30000000000000004.com比较跨编程语言的浮点运算
几个Stack Overflow问题包括
Why Are Floating Point Numbers Inaccurate?
Why can't decimal numbers be represented exactly in binary?
Is floating point math broken?
Canonical duplicate for "floating point is inaccurate"(关于此问题的规范答案的元讨论)
比较标量
R
中的标准解决方案不是使用==,而是使用all.equal函数 . 或者更确切地说,因为all.equal
提供了很多有关差异的细节,如果有的话,isTRUE(all.equal(...))
.产量
使用
all.equal
而不是==
的更多示例(最后一个示例应该表明这将正确显示差异) .更多细节,直接从answer to a similar question复制:
您遇到的问题是浮点在大多数情况下不能完全表示小数分数,这意味着您经常会发现完全匹配失败 .
当你说:当你说:
您可以通过十进制找出它的真实想法:
您可以看到这些数字不同,但表示有点笨拙 . 如果我们用二进制(嗯,十六进制,相当)来看它们,我们会得到更清晰的图像:
您可以看到它们的区别在于
2^-53
,这很重要,因为这个数字是两个数值之间的最小可表示差异,其值接近1,因为这是 .通过查看R的machine字段,我们可以找出任何给定的计算机这个最小的可表示数字是什么:
您可以使用此事实创建'nearly equals'函数,该函数检查差异是否接近浮点中的最小可表示数字 . 实际上这已经存在:
all.equal
.所以all.equal函数实际上是检查数字之间的差异是两个尾数之间最小差异的平方根 .
这个算法在称为非正规数的极小数字附近有点滑稽,但你不必担心这一点 .
比较矢量
上面的讨论假设了两个单值的比较 . 在R中,没有标量,只是向量和隐式向量化是语言的强项 . 为了比较元素的向量值,先前的原则成立,但实现略有不同 .
==
是矢量化的(进行逐元素比较),而all.equal
将整个矢量作为单个实体进行比较 .使用前面的例子
==
未给出"expected"结果,all.equal
不执行元素相反,必须使用循环两个向量的版本
如果需要它的功能版本,可以编写它
这可以称为公正
或者,您可以只复制
all.equal.numeric
的相关内部并使用隐式向量化,而不是将all.equal
包装在更多函数调用中: