【发布时间】:2021-03-06 23:13:54
【问题描述】:
浮点舍入有问题。我想计算浮点数并将它们四舍五入到(给定)N 个小数。在这个例子中,我想四舍五入到小数点后 1 位。
计算 37.1-28.75 将得到浮点 8.349998(而不是 8.35),这将导致 printf 舍入为 8.3 而不是 8.4 小数点后 1 位。
数学上的实际结果是 37.10-28.75=8.35000000,但由于浮点不精确,它被转换为 8.349998,然后在使用 1 个小数位四舍五入时转换为 8.3 而不是 8.4。
最小可重现示例:
float a = 37.10;
float b = 28.75;
//a-b = 8.35 = 8.4
printf("%.1f\n", a - b); //outputs 8.3 instead of 8.4
在结果中添加以下内容是否有效:
float result = a - b;
if (result > 0.0f)
{
result += powf(10, -nr_of_decimals - 1) / 2;
}
else
{
result -= powf(10, -nr_of_decimals - 1) / 2;
}
编辑:更正我想要 1 个小数位的舍入输出,而不是 2 个小数位
EDIT2:也需要负面结果 (28.75-37.1 = -8.4)
【问题讨论】:
-
听起来你需要
roundf。 -
@user3386109 抱歉,添加了示例!这实际上揭示了我的问题中的严重错误。
-
是的,现在说得通了。该减法产生的数字 (8.35) 正好是两个可能的数字之间的一半,小数点后有一位数字(8.3 和 8.4)。所以计算中最轻微的错误都会影响数字的四舍五入方式。
-
关于“计算 37.1-28.75”:在基于二进制的
float格式中不可能进行这样的计算,因为 37.1 无法以该格式表示。 在您的计算甚至开始之前,float a = 37.10;导致a被设置为 37.09999847412109375,采用float常用的格式。除了以 .00、.25、.50 和 .75 结尾的数字以外,不可能在二进制浮点中用两位十进制数字表示数字,因此基于二进制的浮点数是不是用于此类工作的正确格式。