C/C++中如何判断浮点类型相等?

1. 浮点类型在计算中的存储格式

1.1. 小数的科学计数法

科学记数法是一种记数的方法。把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,a不为分数形式,n为整数),这种记数法叫做科学记数法。例如:19971400000000=1.99714×10^13。计算器或电脑表达10的幂是一般是用E或e,也就是1.99714E13=19971400000000。

1.2. 计算机中小数的存储格式

计算机中小数的存储格式依据IEEE 745标准制定,其有三种精度标准。分别为单精度、双精度以及扩展精度。C/C++中主要用到单精度和双精度类型,即float和double类型。
在这里插入图片描述
科学计数法中指数的底数是10,但是计算机存储中默认的指数底数为2.
例如,19.625,其float类型的2进制表达为:0 - 10000011 - 001 1101 0000 0000 0000 0000
尾数:

  1. 整数部分的二进制形式为:19 = 124 + 023 + 022 + 121 + 1*20 = 10011
  2. 小数部分的二进制形式为:
    0.625 * 2 = 1.250 取整 1
    0.250 * 2 = 0.5 取整0
    0.5 * 2 = 1.0 取整1
    0.0 * 2 = 0
    0.625 = 12-1 + 02-2 + 1*2-3 = 101
    101反向:(((1/2 + 0)/2 + 1)/2 = 0.625
  3. 整数加小数2进制10011.101
  4. 尾数 val 必须 1 ≤ val< 2,所以还需要再将小数点向左移动4位:1.0011101*24

指数部分
24,指数4即为指数部分。
符号位
正数0,负数1。

2. 浮点类型比较

示例1
0.5的float浮点存储格式为:1*2-1
0.1的float浮点存储格式为:因为0.1乘以2,永远无法凑整,所以0.1的尾数只能取近似值,而不是完整存储。
示例2
double a = 10000000000.000011;
double b = 10000000000.000008;
绝对误差:d1 = abs(a - b) = 0.000003
相对误差:d2 = abs(a - b ) / abs(a); (值非常小)
示例3
double a = 0.000011;
double b = 0.000008;
绝对误差:d1 = abs(a - b) = 0.000003
相对误差:d2 = abs(a - b ) / abs(a)=0.272

根据上面的示例,我们发现,

  1. 浮点类型是可以表示部分准确的实数,单独列出来,可以提高判断执行效率。
    所以:
    if (a == b) return true;
  2. 如果绝对误差在允许的范围内,那么也是肯定认为是相等的。
    if (abs(a - b) < absTh) return true;
  3. 其他情况则判断相对误差。
    if (abs(a - b) < relTh*max(abs(a), abs(b)) return true;
  4. other
    return false;

3. 完整代码

bool AlmostEquel(double _left, double _right, double _absTh = FLT_EPSILON, double _relTh = FLT_MIN)
{
	if (_left == _right)
	{
		return true;
	}

	double dev = abs(_left - _right); 
	if (dev < _absTh)
	{
		return true;
	}
	else 
	{
		return (dev < _relTh * std::max(_right, _left));
	}
}

4. 参考

  1. https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
  2. https://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison/66750064#66750064
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值