简体   繁体   English

迭代时浮点数不精确

[英]floating point number imprecision while iterating

I have a function that computes a point in 3d spaced based on a value in range [0, 1] . 我有一个函数,根据范围[0, 1]的值计算3d间距。 The problem I'm facing is, that a binary floating-point number cannot represent exactly 1. 我面临的问题是,二进制浮点数不能正好代表1。

The mathematical expression that is evaluated in the function is able to compute a value for t=1.0 , but the value will never be accepted by the function because it checks if for the range before computing. 在函数中计算的数学表达式能够计算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;
}

How can I, with this function, compute the 3d point at t=1.0 ? 如何使用此功能计算t=1.0的3d点? I heard something about an ELLIPSIS some time ago that I think had to do with such an issue, but I'm not sure. 前段时间我听说过关于ELLIPSIS一些事情,我认为这与这个问题有关,但我不确定。

Thanks 谢谢

EDIT : Ok, I'm sorry. 编辑 :好的,对不起。 I assumed a float cannot represent exactly 1, because of the issue I'm facing. 我假设一个浮点数不能正好代表1,因为我面临的问题。 The problem may be because I was doing an iteration like this: 问题可能是因为我正在做这样的迭代:

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) {

your problem is that a binary floating point number cannot exactly represent 0.1 . 你的问题是二进制浮点数不能精确地代表0.1

The closest 32-bit single precision IEEE754 floating point number is 0.100000001490116119384765625 and the closest 64-bit double precision one 0.1000000000000000055511151231257827021181583404541015625. 最接近的32位单精度IEEE754浮点数为0.100000001490116119384765625,最接近的64位双精度值为0.1000000000000000055511151231257827021181583404541015625。 If the arithmetic is performed strictly at 32-bit precision, the result of adding 0.1f ten times to 0 is 如果严格按32位精度执行算术,则将0.1f0.1f的结果为0

1.00000011920928955078125

If intermediate computations are performed at greater precision than float has, it could result in exactly 1.0 or even slightly smaller numbers. 如果以比float更高的精度执行中间计算,则可能导致正好1.0或甚至略小的数字。

To fix your problem, in this case you could use 要解决您的问题,在这种情况下您可以使用

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

because 10 * 0.1f is exactly 1.0 . 因为10 * 0.1f正好是1.0

Another option is to use a small tolerance in your curves_bezier function, 另一个选择是在curves_bezier函数中使用一个小容差,

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

for a suitably small epsilon, maybe float epsilon = 1e-6; 对于一个适当的小epsilon, float epsilon = 1e-6; .

binary floating-point number cannot represent exactly 1 二进制浮点数不能正好代表1

Proof that it can can be found here . 证明它可以在这里找到

Most accurate representation = 1.0E0 最准确的表示= 1.0E0

There could be problems with 可能有问题

  1. fractional numbers that would have infinite fractional digits in radix of 2 在2的基数中具有无限小数位的小数
  2. numbers that are too small to exactly represent without losing precision 数字太小而无法准确表示而不会丢失精度
  3. numbers that are too large to represent without losing precision. 数字太大而无法在不失精度的情况下表示。

But 1.0 is none of them! 1.0不是他们!

However 0.1 is a problem case, violating point number 1, look at this : 但是 0.1是一个问题情况,违反第1点,看看这个

Most accurate representation = 1.00000001490116119384765625E-1 最准确的表示= 1.00000001490116119384765625E-1

So if you add up 0.1 ten times, you will get 1.00000001490116119384765625E-0 which is greater than 1.0 . 因此,如果你加起来十次,你会得到1.00000001490116119384765625E-0 ,大于1.0

(examples are in IEEE754 single precision 32 bit floating point numbers) (例子是IEEE754单精度32位浮点数)

Possible solution: 可能的方法:

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);
    }
}

This way, the error of the binary format does not get summed up! 这样,二进制格式的错误就不能总结了!

( Note: I used extra curly braces for the if and else statements. Do that, you'll thank yourself one day.) 注意:我在ifelse语句中使用了额外的花括号。这样做,有一天你会感谢自己。)

When comparing floating point numbers you should check if they are close enough not exactly equal, for the reasons mentioned in other answers, something like: 比较浮点数时,你应检查它们是否足够接近不完全相等,原因如下:其他答案中提到的原因如下:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM