浮点减法给我带来不准确的结果

时间:2018-08-31 16:50:58

标签: c++ floating-accuracy subtraction

我正在编写代码,其中需要从初始值中减去每半秒进行的测量,最终达到0。这两个值都是浮点数。初始值为1.4亿,测量范围为0.320000001至0.389999999。

    float batt = 140000000.00; //capacity 140M units
    float subtr;

    /.../
    while(1){
          batt = float(batt - subtr);
    /.../
    }
    

所以基本上我需要从148,000,000.00的循环的每个周期中减去0.3xxxxxxxx,但是似乎存在大小问题,因此当我对其进行调试时,每次仍然可以获得148M。

我尝试使用小1000倍的batt batt值148 000,并将测量值从0.3xxxxxxxx转换为0.0003xxxxxxxx。调试代码时,148000-0.000300005049(测量值)给我147999.469,与预期结果(147,999.999,699)相比差了0.530699。

float似乎不够准确,无法满足我的需要,我应该将值转换为其他类型,还是有其他方法可以获得准确的结果?正在考虑将度量转换为不带小数的值,但这也不起作用,因为初始值对于float(148 * 10 ^ 15)会变得太大。当我使用140,000,000.00时,我期望获得小数点后三位(.xxx)的精度;当我使用140,000.00时,期望获得六位小数点(.xxx,xxx)的精度。

1 个答案:

答案 0 :(得分:5)

当您执行140000000-0.389时,第二个操作数需要缩放以具有与第一个相同的指数:1.4e8 - 0.00000000389e8 = 1.39999999611e8。英特尔CPU当前以扩展精度80位格式进行浮点计算,但是当将结果存储回32位float1.39999999611e8会四舍五入为1.4e8,因为float具有精度大约为6个十进制数字。

存储十进制数字148000000.0003xxxxxxxx大约需要24个十进制数字的精度或80个二进制数字。 80位的long double可能会这样做:

int main() {
    float a = 140000000.f;
    float b = 0.389999999f;
    printf("%f\n", a);
    printf("%f\n", b);
    printf("float result:       %.16f\n", a - b); // Round the 80-bit extended precision result to 32-bit.
    printf("double result:      %.16f\n", static_cast<double>(a)); // Round the 80-bit extended precision result to 64-bit.
    printf("long double result: %.16Lf\n", static_cast<long double>(a) - b); // 80-bit extended precision result.
}

输出:

140000000.000000
0.390000
float result:       140000000.0000000000000000
double result:      140000000.0000000000000000
long double result: 139999999.6100000143051147