如何计算表达式的相对与绝对精度?对比float与double并选型适配公差
1. 如何计算指定类型表达式的相对精度与绝对精度?
要计算表达式的绝对精度和相对精度,核心是拿计算值和真实参考值做对比,步骤大概是这样:
- 第一步:先确定表达式的「真实值」——用比目标类型精度更高的类型(比如要算float的精度,就用long double来计算表达式的准确结果)作为参考基准,因为更高精度的类型能最大限度减少自身误差,接近数学上的真实结果。
- 第二步:用目标类型(比如float/double)计算表达式的「实际计算值」。
- 第三步:计算绝对误差:
|计算值 - 真实值|,这个值直接反映计算结果和真实值的绝对差距,就是绝对精度的量化指标。 - 第四步:计算相对误差:如果真实值不等于0,就用
绝对误差 / |真实值|,这个值是误差相对于真实值的比例,更适合衡量大数的精度。如果真实值接近0,相对误差会失去意义,这时候只看绝对误差就好。
举个简单例子:比如用float计算(1000000 + 1)/2,真实值是500000.5,float计算出来可能是500000,那绝对误差就是0.5,相对误差就是0.5 / 500000.5 ≈ 1e-6。
2. 对比float与double类型时,表达式(x+y)/k的相对精度与绝对精度?
先得明确float和double的基础差异:float是单精度32位浮点型,尾数占23位,有效数字大概6-7位;double是双精度64位,尾数占52位,有效数字大概15-17位。两者的机器epsilon(能表示的最小相对误差)分别是1.19e-7(float)和2.22e-16(double)。
回到表达式(x+y)/k,误差主要来自两个环节:
- x+y的加法误差:如果x和y的数值差距很大(比如x是1e6,y是1),float会出现「大数吃小数」的情况——y的数值会被x的精度覆盖,加出来的结果还是x;但double因为尾数位数多,能保留y的有效信息,加法误差极小。
- 除以k的误差:除法的相对误差大概是机器epsilon的量级,double的这个值远小于float。
对比两者的精度:
- 绝对精度:double的绝对误差普遍远小于float。比如刚才的例子,float算出来绝对误差0.5,double算出来几乎是0。即使是普通数值,double能表示的小数位数更多,绝对差距更小。
- 相对精度:double的相对误差上限(1e-16)比float(1e-7)小几个数量级,所以不管是加法还是除法,double的相对精度都碾压float。比如计算很大的数时,float的相对误差可能到1e-6级别,而double的相对误差几乎可以忽略不计。
3. 哪种类型能满足表达式的相对公差1e-05、绝对公差1e-08?
先拆解两个公差的要求:
- 相对公差1e-05:要求计算结果的相对误差≤1e-5;
- 绝对公差1e-08:要求计算结果的绝对误差≤1e-08。
先看float:
float的机器epsilon是~1.19e-7,远小于1e-5,哪怕是多次运算累积误差,也很难超过1e-5的相对公差。对于绝对公差,当计算结果的绝对值比较大时(比如≥1e-3),相对误差1e-5对应的绝对误差是1e-5 * |结果|,这时候可能会超过1e-08,但此时相对误差满足要求;当结果绝对值很小(比如<1e-3),float的绝对误差会远小于1e-08(比如结果是1e-4,绝对误差大概是1e-4 * 1e-7=1e-11),完全符合绝对公差。
再看double:
double的精度比float高得多,自然也能轻松满足这两个公差要求,甚至有很大的余量,适合更复杂的运算场景或者对精度要求更高的后续处理。
总结:float已经能满足这两个公差要求,如果只是针对这个简单表达式,用float足够;但如果你的场景还有其他复杂运算、更大的数值范围或者需要更高的冗余精度,double会是更稳妥的选择。
内容的提问来源于stack exchange,提问作者Yas




