迭代时浮点数不精确

Nik*_*s R 3 c floating-point floating-accuracy

我有一个函数,根据范围内的值计算3d间距的点[0, 1].我面临的问题是,二进制浮点数不能正好代表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;
}
Run Code Online (Sandbox Code Playgroud)

如何使用此功能计算3d点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);
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*her 8

for (t=0; t <= 1.0; t += 0.1) {
Run Code Online (Sandbox Code Playgroud)

你的问题是二进制浮点数不能准确表示0.1.

最接近的32位单精度IEEE754浮点数为0.100000001490116119384765625,最接近的64位双精度值为0.1000000000000000055511151231257827021181583404541015625.如果算术严格按32位精度执行,则添加结果0.1f向0十次为

1.00000011920928955078125
Run Code Online (Sandbox Code Playgroud)

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

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

for(k = 0; k <= 10; ++k) {
    t = k*0.1;
Run Code Online (Sandbox Code Playgroud)

因为10 * 0.1f确实如此1.0.

另一个选择是在你的curves_bezier功能中使用一个小容差,

if (t > 1 && t < 1 + epsilon) {
    t = 1;
}
Run Code Online (Sandbox Code Playgroud)

对于一个适当的小ε,也许float epsilon = 1e-6;.