如何检查两个数字是否在“x”浮点型精度极限的有效数字? [英] How can I check whether two numbers are within "x" significant figures of the precision limits of the floating point type?

查看:126
本文介绍了如何检查两个数字是否在“x”浮点型精度极限的有效数字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以假设我们有一个float类型XType,其中有两个数字:

  XType const a = 1.2345 
XType const b = 1.2300


$ b $ p

然后我想要一个函数IsClose(XType const f1,XType const f2, unsigned const truncated_figures),使得

  //如果忽略最后两个数字,则数字相等(1.23 == 1.23)
IsClose< XType>(a,b,2)== true

//如果仅忽略最后一个,则数字不相等(1.234!= 1.230)
IsClose< XType>(a,b,1)== false

到目前为止我有一个丑陋的混乱,我还不能说服自己是正确的:

  //检查两个浮点数是否接近figures_tolerance适用类型的精度
模板< typename FloatType>
bool const IsClose(FloatType const f1,FloatType const f2,unsigned const figures_tolerance)
{
FloatType const tolerance_exponent = std :: pow(10.0,figures_tolerance);
FloatType const tolerance =
std :: pow(tolerance_exponent,std :: log10(f1))*
std :: numeric_limits< FloatType> :: epsilon()
;
return std :: abs(f1 - f2)<公差;
}

我的推理是,公差应该是epsilon提高到数量级数字超过或后续1.0(epsilon基于的有效数字)。这有意义吗?有更好的,更可靠的方法吗?



编辑:我的解决方案使用模板功能如下(它是基于user763305的答案下面)

  //检查两个浮点数是否在
的最后n位精度内//最大的两个被比较的数字。
template< typename FloatType>
bool const IsWithinPrecision(FloatType const f1,FloatType const f2,unsigned const n = 1U)
{
FloatType const f_ref = std :: max(std :: abs(f1),std: :abs(f2));
FloatType const distance = std :: abs(f1 - f2);
FloatType const e = std :: numeric_limits< FloatType> :: epsilon();

返回距离< std :: pow((FloatType)10.0,(FloatType)n)* e * f_ref;
}


解决方案

n 彼此的有效数字,使用不等式

  abs a-b)然而,这种方法不适用于任何一种方法,因为它们可以用于处理数据库中的所有数据,我通常发现更有用的是测试有效数字的数量是否至少是有效数字的最大可能数量(给定浮点类型的精度)减去 n 。这可以使用不等式来完成

  abs(a-b) pow(10.0,n)* std :: numeric_limits< ...> :: epsilon()* max(abs(a),abs(b))

换句话说, n 是我们通过舍入而丢失的有效数字个数错误。 n = 2 3 通常可以在实践中使用。



这个原因的原因是浮点数 a 和下一个可表示浮点数之间的距离 a 之间

  0.5 * std :: numeric_limits< ...> :: epsilon a)

  std :: numeric_limits< ...> :: epsilon()* abs(a)

此外,上述不等式不起作用,如果你处理非常小,或更精确地,非正规数字。那么你应该使用不等式

  abs(a  -  b) pow(10.0,n)* max(
std :: numeric_limits< ...> :: epsilon()* max(abs(a),abs(b)),
std :: denorm_min ; ...>()


So suppose we have a float type XType in which we have two numbers:

XType const a = 1.2345
XType const b = 1.2300

Then I want a function IsClose(XType const f1,XType const f2,unsigned const truncated_figures) such that

// the numbers are equal if the last two figures are ignored (1.23 == 1.23)
IsClose<XType>(a,b,2) == true

// the numbers are not equal if only the last is ignored (1.234 != 1.230)
IsClose<XType>(a,b,1) == false

So far I have this ugly mess, but I'm yet to convince myself it's correct:

// check if two floating point numbers are close to within "figures_tolerance" figures of precision for the applicable type
template <typename FloatType>
bool const IsClose(FloatType const f1, FloatType const f2, unsigned const figures_tolerance)
{
  FloatType const tolerance_exponent = std::pow(10.0,figures_tolerance);
  FloatType const tolerance = 
    std::pow(tolerance_exponent,std::log10(f1)) * 
    std::numeric_limits<FloatType>::epsilon()
  ;
  return std::abs(f1 - f2) < tolerance;
}

My reasoning is that the tolerance should be the epsilon raised to the order of magnitude that the number exceeds or subseeds 1.0 (the significant figures for which the epsilon is based). Does this make sense? Is there a better, more reliable way?

EDIT: My solution using the template function is below (it is based on user763305's answer below)

// check if two floating point numbers are within the last n digits of precision for the
// largest of the two numbers being compared.
template <typename FloatType>
bool const IsWithinPrecision(FloatType const f1, FloatType const f2, unsigned const n = 1U)
{
    FloatType const f_ref = std::max(std::abs(f1), std::abs(f2));
    FloatType const distance = std::abs(f1 - f2);
    FloatType const e = std::numeric_limits<FloatType>::epsilon();

    return distance < std::pow((FloatType) 10.0, (FloatType) n) * e * f_ref;
}

解决方案

To test whether two numbers are within n significant digits of each other, use the inequality

abs(a - b) < pow(0.1, n) * max(abs(a), abs(b))

However, I usually find it more useful to test if the number of significant digits is at least the maximum possible number of significant digits (given the precision of the floating point type) minus n. This can be done using the inequality

abs(a - b) < pow(10.0, n) * std::numeric_limits<...>::epsilon() * max(abs(a), abs(b))

In other words, n is the number of significant digits we have lost through rounding errors. Something like n = 2 or 3 usually works in practice.

The reason this works is that the distances between a floating point number a and the next representable floating point numbers below and above a lie between

0.5 * std::numeric_limits<...>::epsilon() * abs(a)

and

std::numeric_limits<...>::epsilon() * abs(a)

Also, the above inequality does not work if you are dealing with very small, or more precisely, denormal numbers. Then you should instead use the inequality

abs(a - b) < pow(10.0, n) * max(
    std::numeric_limits<...>::epsilon() * max(abs(a), abs(b)),
    std::denorm_min<...>()
)

这篇关于如何检查两个数字是否在“x”浮点型精度极限的有效数字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆