我在 OpenGL 中实现了一个 mandelbrot-explorer。对于更深的缩放,我正在尝试实现双双算术。我在 C++ 中有工作代码,但是 - 如果我没有忽略某些东西 - 完全相同的代码只会在 GLSL 中产生双精度。
乘法的 C++ 代码:
igdd quickTwoSum(double a, double b)
{
igdd Temp;
Temp.hi = a + b;
Temp.lo = b - (Temp.hi - a);
return Temp;
}
igdd Split64(double d)
{
const double SPLITTER = (1 << 29) + 1;
double t = d * SPLITTER;
igdd Temp;
Temp.hi = t - (t - d);
Temp.lo = d - Temp.hi;
return Temp;
}
igdd twoProd(double a, double b)
{
igdd p;
p.hi = a * b;
igdd aS = Split64(a);
igdd bS = Split64(b);
p.lo = ((aS.hi * bS.hi - p.hi) + aS.hi * bS.lo + aS.lo * bS.hi + aS.lo * bS.lo);
return p;
}
igdd operator*(igdd a)
{
igdd Temp;
Temp = twoProd(a.hi, this->hi);
Temp.lo += a.hi * this->lo + a.lo * this->hi;
Temp = quickTwoSum(Temp.hi, Temp.lo);
return Temp;
}
开放 GL 代码:
dvec2 Split64(double d)
{
const double SPLITTER = (1 << 29) + 1;
double t = d * SPLITTER;
dvec2 result;
result.x = t - (t - d);
result.y = d - result.x;
return result;
}
dvec2 quickTwoSum(double a, double b)
{
dvec2 result;
result.x = a + b;
result.y = b - (result.x - a);
return result;
}
dvec2 twoProd(double a, double b)
{
dvec2 p;
p.x = a * b;
dvec2 aS = Split64(a);
dvec2 bS = Split64(b);
p.y = (aS.x * bS.x - p.x) + aS.x * bS.y + aS.y * bS.x + aS.y * bS.y;
return p;
}
dvec2 df128_mul(dvec2 a, dvec2 b)
{
dvec2 p;
p = twoProd(a.x, b.x);
p.y += a.x * b.y + a.y * b.x;
p = quickTwoSum(p.x, p.y);
return p;
}
出于测试目的,我在 C++ 中都这样做了
igdd Testdd; // The double-double class in C++
Testdd.lo = 0.0000000000000000000000001;
Testdd.hi = 1.0;
std::cout.precision(17);
for (int i = 0; i < 95; i++)
{
Testdd = Testdd * Testdd;
std::cout << std::fixed << Testdd.hi << std::endl;
}
...和OpenGL
dvec2 XR;
XR.y = 0.0000000000000000000000001;
XR.x = 1.0;
for (i = 0; i < 95; i++) // I tried different values for 95 here
{
XR = df128_mul(XR, XR);
}
如果我继续对数字进行平方,在 C++ 中,你会看到它变得越来越大(最初它是太多的零)。GLSL 总是产生一个(或零 - 我在输出之前做了 number-1)。
那么 GLSL 中的双打(或可能)有什么奇怪的地方,dvec2
还是我忽略了一些东西?另外:当计算带有双打的 mandelbrot-set 时,CPU 真的很慢。GPU 产生了完全正确的图片(直到我放大到大约 10^-14)并且速度非常快......