在着色器中自己的双精度cos()实现的结果是NaN,但在CPU上运行良好.出了什么问题?

Dan*_*gel 8 c++ opengl shader glsl

正如我所说,我想在GLSL的计算着色器中实现我自己的双精度cos()函数,因为只有一个内置的float版本.

这是我的代码:

double faculty[41];//values are calculated at the beginning of main()

double myCOS(double x)
{
    double sum,tempExp,sign;
    sum = 1.0;
    tempExp = 1.0;
    sign = -1.0;

    for(int i = 1; i <= 30; i++)
    {
        tempExp *= x;
        if(i % 2 == 0){
            sum = sum + (sign * (tempExp / faculty[i]));
            sign *= -1.0;
        }
    }
return sum;
}
Run Code Online (Sandbox Code Playgroud)

这段代码的结果是,着色器上的总和是NaN,但在CPU上,算法运行良好.我也尝试调试此代码,并获得以下信息:

  • 所有参赛作品都是正面的,而不是零
  • tempExp在每一步都是正面的
  • 在每个步骤中,其他变量都不是NaN
  • 第一次总和是NaN在i = 4的步骤

现在我的问题是:如果每个变量都是一个数字并且什么都没有被零除,那么究竟什么可能出错呢?特别是当算法在CPU上工作时?

fja*_*don 1

让我猜猜:

\n\n

首先,您确定问题出在循环中,并且仅使用以下操作:+, *, /

\n\n

NaN从这些操作生成的规则是:

\n\n
    \n
  • 各部门0/0\xc2\xb1\xe2\x88\x9e/\xc2\xb1\xe2\x88\x9e
  • \n
  • 乘法0\xc3\x97\xc2\xb1\xe2\x88\x9e\xc2\xb1\xe2\x88\x9e\xc3\x970
  • \n
  • 加法\xe2\x88\x9e + (\xe2\x88\x92\xe2\x88\x9e)(\xe2\x88\x92\xe2\x88\x9e) + \xe2\x88\x9e等价减法
  • \n
\n\n

您通过声明已正确初始化来排除0/0和的可能性。\xc2\xb1\xe2\x88\x9e/\xc2\xb1\xe2\x88\x9efaculty[]

\n\n

该变量sign始终是1.0这样,所以它不能通过操作-1.0生成。NaN*

\n\n

剩下的就是+操作(如果tempExp有的话)\xc2\xb1\xe2\x88\x9e

\n\n

因此,tempExp您的功能输入可能太高,并且变成\xc2\xb1\xe2\x88\x9e,这也会sum导致\xc2\xb1\xe2\x88\x9e。在下一次迭代中,您将NaN通过以下方式触发生成操作:\xe2\x88\x9e + (\xe2\x88\x92\xe2\x88\x9e)。这是因为您将加法的一侧乘以sign并且在每次迭代时符号在正负之间切换。

\n\n

你试图cos(x)近似0.0. 因此,您应该使用函数的属性cos()将输入值减少到接近 的值0.0。最好在范围内[0, pi/4]。比如去掉 的倍数,通过周围计算得到in2*pi的值等等。cos()[pi/4, pi/2]sin(x)0.0

\n