jjzjj

php - 在 PHP 中比较浮点相等性的公式

coder 2024-04-17 原文

如何比较 float 的问题has been answered here .这个问题的不同之处在于我问的是公式。两个投票最高的答案对问题的解决方案略有不同:

if (abs(($a-$b)/$b) < $epsilon) { … }

if (abs($a-$b) < $epsilon) { … }

为什么第一个答案包含除法?不会导致结果不准确吗?例如(使用简单的数字),让 $a 和 $b 都等于 0.01,并假设 $a - $b 的结果为 0.0001,$epsilon 为 0.001。

((((0.01 - 0.01) == 0.0001) / 0.01 == 0.01) < 0.001) : false

鉴于

(((0.01 - 0.01) == 0.0001) < 0.001) : true

我的数学可能有点生疏,但我错过了什么?

什么时候应该使用一个公式而不是另一个?

最佳答案

这可能允许使用相对错误而不是绝对错误检查 epsilon。

比较这两种情况:

function areEqual(float $a, float $b) : bool {
    return abs(($a - $b) / $b) < 0.00001;
}
areEqual(10000, 10000.01);
areEqual(0.0000001, 0);

Fact about the example values above: Our epsilon here is 0.00001 for convenience ‐ the smallest epsilon possible is much smaller than these values anyway, so let's ignore this fact. Our algorithm assumes that $a and $b are both similar, so it does not matter whether we divide by $a or $b. Actually, 10000 should be much larger than that (a very enormous exponent), and 0.0000001 can be much smaller, but for the sake of convenience, let's assume these are the values that may cause problems.

现在您已经可以看出区别了。

对于大数字:如果比较的 float 非常大,则 epsilon 可能太小。 float 内部只能存储一定数量的数字以确保精度,而指数可以远大于此。结果,浮点错误的来源,即 float 的最后一位,会出现在比单位数字更高的地方。换句话说,对于非常大的 float ,绝对误差可能大于 1,更不用说我们的 0.00001 了。

对于小数字:这更加明显。这两个数字都已经小于 epsilon。即使你将它们与 0 进行比较,当相对误差无限大时,你仍然认为它们是相等的。对于这种情况,您要么将两个操作数相乘,要么减少 epsilon。它们其实是一样的,但是在实现上,用其中一个操作数来除差更方便,对于小数会相乘(/0.0001等同于* 10000) 或对大数进行除法(/10000 而差异有望小于 10000)

此检查还有另一个名称。 abs($a - $b)称为绝对误差,我们通常使用相对误差,即绝对误差÷的近似值。由于值也可以是负数,我们 abs 整个事情 ($a - $b)/$b 代替。我们的“epsilon”,0.00001,在这种情况下,意味着我们容忍的相对误差是 0.00001,即 0.001% 的误差。


请记住,这仍然不是绝对安全的。在程序中进行多次转换后,例如,您可以将数字与一些大数字相加/相乘,然后再次减去,将大数字中的不纯误差留在人类仍然可以忽略不计但对您的 epsilon 值值得注意的地方。因此,在选择 epsilon 值或 float 比较算法之前,请务必三思。

作为最佳做法,请避免将大数字与小数字相加、减去或相乘。它们会增加出错的机会。在开发(特别是简化)您的算法时,请始终考虑到它们可能是您的 float 中的错误。这可能会把工作量增加到愚蠢的程度,但只要你意识到这一点,这种担心有时会让你免于被踢出团队。

关于php - 在 PHP 中比较浮点相等性的公式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39411672/

有关php - 在 PHP 中比较浮点相等性的公式的更多相关文章

  1. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  2. ruby-on-rails - ActiveRecord 对象相等 - 2

    根据ActiveRecord::Base的文档:==(comparison_object)Returnstrueifcomparison_objectisthesameexactobject,orcomparison_objectisofthesametypeandselfhasanIDanditisequaltocomparison_object.id.Notethatnewrecordsaredifferentfromanyotherrecordbydefinition,unlesstheotherrecordisthereceiveritself.Besides,ifyoufet

  3. ruby-on-rails - ruby on rails 模型验证中的浮点精度 - 2

    我正在尝试使用正则表达式验证美元金额:^[0-9]+\.[0-9]{2}$这工作正常,但每当用户提交表单并且美元金额以0(零)结尾时,ruby(或rails?)将0砍掉。所以500.00变成500.0,因此正则表达式验证失败。有没有办法让ruby​​/rails保持用户输入的格式,而不管尾随零? 最佳答案 我假设您的美元金额是小数类型。因此,用户在字段中输入的任何值在保存到数据库之前都会从字符串转换为适当的类型。验证适用于已转换为数字类型的值,因此在您的情况下,正则表达式并不是真正合适的验证过滤器。不过,您有几种可能性可以解决这个问

  4. ruby - 在 Ruby 中比较序列 - 2

    假设我必须(小型到中型)阵列:tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]如何确定tokens是否以相同的顺序包含template的所有条目?(请注意,在上面的示例中,应忽略第一个“ccc”,从而由于最后一个“ccc”而导致匹配。) 最佳答案 这适用于您的示例数据。tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]po

  5. ruby-on-rails - 浮点乘法的 Ruby 奇怪问题 - 2

    有没有人用ruby​​解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby​​1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi

  6. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  7. Ruby:检查所有数组元素是否相等 - 2

    我在使用Ruby代码时遇到了一些“问题”。我想检查数组的所有元素是否相等。例如,假设我有一个只有5的数组:arr=[5,5,5,5,5]我知道我可以做类似的事情arr[0]==arr[1]==arr[2]==arr[3]#==arr[4]==...但这对于巨大的数组来说是不可能的,而且在我看来也不是很像Ruby。我们可以通过做这样的事情来改进它:defall_equal?(arr)foriin0..(arr.size-2)ifarr[i]!=arr[i+1]thenreturnfalseendendtrueend但我也认为这很丑陋。那么是否有任何内置/更好/更短(更像Ruby风格)的方

  8. ruby - 为什么我的 rspec 测试在 Ruby 1.9.2 中比在 1.8.7 中运行得慢? - 2

    我正在使用spork测试Sinatra应用程序,使用Ruby1.9.2,测试运行时间约为3.5秒,但在Ruby1.8.7中,平均运行时间为1.2秒。我确实尝试过Ruby1.9.3甚至JRuby,但它们在我使用的gems上有一些错误。有没有办法将Ruby1.9.2的rspec性能提高到1.8.7的水平?我的gem文件:source:rubygemsgem'sinatra','1.3.1'gem'thin','1.3.1'gem'haml','3.1.4'gem'datamapper','1.2.0'gem'dm-postgres-adapter','1.2.0'gem'carrierwa

  9. ruby - Ruby 中的 "=="是否总是值相等? - 2

    抱歉,如果重复(我没找到)这只是为了确认Ruby的运算符==始终执行相等比较。IE。a==b将a的值与b的值进行比较,而不是像Java那样比较它们是否指向内存中的同一个对象(对于后者,在Ruby中,您应该使用a.object_id==b.object_id).因此,在Ruby中将字符串值与==进行比较是安全的(而在Java中这样做并不安全)谢谢编辑:问题在于任何Ruby对象的默认==行为,因为它会误导Java-C-C++程序员假设a==b比较引用本身,而不是引用内容。无论如何,你可以检查这段代码,使用字符串one="hello"two="he"two编辑2。所以,在Ruby中,比较a=

  10. ruby - Ruby 的数组如何。比较元素是否相等? - 2

    下面是一些示例代码:classObjattr:c,truedef==thatp'=='that.c==self.cenddefthatp''that.cself.cenddefequal?thatp'equal?'that.c.equal?self.cenddefeql?thatp'eql?'that.c.eql?self.cendenda=Obj.newb=Obj.newa.c=1b.c=1p[a]|[b]它打印2个对象,但它应该打印1个对象。没有调用任何比较方法。阵列如何。|比较平等? 最佳答案 Array#|是使用散列实现的。

随机推荐