HSV转换中的浮点错误

时间:2013-11-07 20:03:39

标签: c++ floating-point

我有一个将RGB色彩空间中的矢量转换为HSV的功能 - 例程通过了所有测试并且在绝大多数时间都可以工作。但是,崩溃报告表明它偶尔会失败(0.0001%的呼叫或更少。)但是,由于此功能被调用太多,这占软件总崩溃的很大一部分。

代码的相关部分如下:

glm::vec4 RGBtoHSV(glm::vec4 rgb)
{
    vec4 hsv = vec4(0,0,0,rgb.w);

    float r = rgb.x;
    float g = rgb.y;
    float b = rgb.z;
    float M = std::max(std::max(r,g),b);
    float m = std::min(std::min(r,g),b);
    float c = M - m;

    //calc hue
    float hp = 0;
    if (c == 0)
        hp = 0;
    else if (M == r)
        hp = glm::mod(((g-b)/c), 6.0f);
    else if (M == g)
        hp = ((b-r)/c) + 2;
    else if (M == b)
        hp = ((r-g)/c) + 4;
    else
        EXPECT(false);
    float h = hp * 60;

    ...

glm :: vec4是对GLM库的引用,但类型基本上就是这样:

struct vec4 {
    union {
        struct { float x, y, z, w; }
        struct { float r, g, b, a; }
    }
}

失败的行是EXPECT(false); - 这只是断言我们总是达到其中一个上层案例,问题是如何控制到达那里?

1 个答案:

答案 0 :(得分:2)

假设这些是IEEE-754浮点数,那么与NaN相比可能会遇到问题。如果您使用不同的浮点表示,那么我的答案的其余部分可能不相关。

听起来有点奇怪但NaN的任何比较都会返回False。所以即使你试图做NaN == Nan,你也会变得虚假。 MSDN link

如果在代码中引发断言的部分中测试NaN,则可能是问题所在。您可以使用isnan()中的<cmath> #include <iostream> #include <cmath> int main(){ float r = 0.0/0; std::cout << "r = " << r << std::endl; float g = 7.0; float b = 0.0; float M = std::max(std::max(r,g),b); float m = std::min(std::min(r,g),b); float c = M - m; //calc hue float hp = 0; if (c == 0) std::cout << "c == 0" << std::endl; else if (M == r) std::cout << "M == r" << std::endl; else if (M == g) std::cout << "M == g" << std::endl; else if (M == b) std::cout << "M == b" << std::endl; else std::cout << "oops" << std::endl; if(std::isnan(M)) std::cout << "NaN encountered" << std::endl; } 来查看http://en.cppreference.com/w/cpp/numeric/math/isnan

我快速汇总了一些代码以进行演示,如果您的系统发生同样的情况,请告诉我们:

r = -nan
oops
NaN encountered

在我用gcc编译的机器上,这给出了以下输出:

0.0/0

所以似乎有可能代码中的其他地方有{{1}}。