迭代时浮点数不精确

我有一个函数,根据范围[0, 1]的值计算3d间距。 我面临的问题是,二进制浮点数不能正好代表1。

在函数中计算的数学表达式能够计算t=1.0的值,但该函数永远不会接受该值,因为它在计算之前检查是否为该范围。

 curves_error curves_bezier(curves_PointList* list, curves_Point* dest, curves_float t) { /* ... */ if (t  1) return curves_invalid_args; /* ... */ return curves_no_error; } 

如何使用此function计算t=1.0的3d点? 前段时间我听说过关于ELLIPSIS一些事情,我认为这与这个问题有关,但我不确定。

谢谢

编辑 :好的,对不起。 我假设浮动不能完全代表1,因为我面临的问题。 问题可能是因为我正在做这样的迭代:

 for (t=0; t <= 1.0; t += 0.1) { curves_error error = curves_bezier(points, point, t); if (error != curves_no_error) printf("Error with t = %f.\n", t); else printf("t = %f is ok.\n", t); } 

 for (t=0; t <= 1.0; t += 0.1) { 

你的问题是二进制浮点数不能精确地代表0.1

最接近的32位单精度IEEE754浮点数为0.100000001490116119384765625,最接近的64位双精度值为0.1000000000000000055511151231257827021181583404541015625。 如果严格按32位精度执行算术,则将0.1f0.1f的结果为0

 1.00000011920928955078125 

如果以比float更高的精度执行中间计算,则可能导致正好1.0或甚至略小的数字。

要解决您的问题,在这种情况下您可以使用

 for(k = 0; k <= 10; ++k) { t = k*0.1; 

因为10 * 0.1f正好是1.0

另一个选择是在curves_bezier函数中使用一个小容差,

 if (t > 1 && t < 1 + epsilon) { t = 1; } 

对于一个适当的小epsilon,可能float epsilon = 1e-6;

二进制浮点数不能正好代表1

certificate它可以在这里找到 。

最准确的表示= 1.0E0

可能有问题

  1. 在2的基数中具有无限小数位的小数
  2. 数字太小而无法精确表示而不会丢失精度
  3. 数字太大而无法在不失精度的情况下表示。

1.0不是他们!

但是 0.1是一个问题情况,违反第1点,看看这个 :

最准确的表示= 1.00000001490116119384765625E-1

因此,如果你加起来十次,你会得到1.00000001490116119384765625E-0 ,大于1.0

(例子是IEEE754单精度32位浮点数)

可能的方法:

 int i; for (i=0; i <= 10; i++) { t=i/10.0; curves_error error = curves_bezier(points, point, t); if (error != curves_no_error) { printf("Error with t = %f.\n", t); } else { printf("t = %f is ok.\n", t); } } 

这样,二进制格式的错误就不能总结了!

注意:我在ifelse语句中使用了额外的花括号。这样做,你会感谢自己有一天。)

比较浮点数时,你应该检查它们是否足够接近并不完全相等,原因如下:其他答案中提到的原因如下:

 #define EPSILON 0.000001f #define FEQUAL(a,b) (fabs((a) - (b)) < EPSILON)