我有一个函数,它根据range [0, 1]中的值计算3d中的一个点。我面临的问题是,二进制浮点数不能精确表示1。
在函数中求值的数学表达式能够计算t=1.0的值,但是该值永远不会被函数接受,因为它在计算之前检查范围。
curves_error curves_bezier(curves_PointList* list, curves_Point* dest, curves_float t) {
/* ... */
if (t < 0 || t > 1)
return curves_invalid_args;
/* ... */
return curves_no_error;
}使用这个函数,我如何计算t=1.0的三维点?不久前,我听说了一些关于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);
}发布于 2012-11-22 12:56:13
for (t=0; t <= 1.0; t += 0.1) {您的问题是二进制浮点数不能准确地表示0.1。
最接近的32位单精度0.1000000000000000055511151231257827021181583404541015625.浮点数为0.10000000149011119384765625,最接近64位双精度IEEE754浮点数。如果算法严格以32位精度执行,则将0.1f添加10次至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;。
发布于 2012-11-22 12:55:09
二进制浮点数不能精确表示1。
证明它可以在这里找到。
最精确表示= 1.0E0
可能会有问题
但1.0不是他们中的一员!
然而,0.1 是一个问题案例,违反了第1点,看看这:
最精确表示法= 1.00000001490116119384765625E-1
所以,如果你加起来0.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);
}
}这样,二进制格式的错误就不会被总结了!
(注意:,我在if和else语句中使用了额外的大括号。这样做,总有一天你会感谢自己的。)
发布于 2012-11-22 13:00:01
在比较浮点数时,您应该检查它们是否足够接近,不完全相等,因为其他答案中提到的原因如下:
#define EPSILON 0.000001f
#define FEQUAL(a,b) (fabs((a) - (b)) < EPSILON)https://stackoverflow.com/questions/13512986
复制相似问题