Nicolas Winkler 4 роки тому
батько
коміт
da738be33a

+ 13 - 0
libmandel/include/ClGenerators.h

@@ -33,6 +33,7 @@ namespace mnd
     class ClGenerator;
     class ClGeneratorFloat;
     class ClGeneratorDoubleFloat;
+    class ClGeneratorTripleFloat;
     class ClGeneratorDouble;
     class ClGeneratorDoubleDouble;
     class ClGeneratorTripleDouble;
@@ -85,6 +86,18 @@ protected:
 };
 
 
+class mnd::ClGeneratorTripleFloat : public ClGenerator
+{
+public:
+    ClGeneratorTripleFloat(MandelDevice& device);
+    virtual ~ClGeneratorTripleFloat(void) = default;
+
+    virtual void generate(const MandelInfo& info, float* data) override;
+protected:
+    virtual std::string getKernelCode(bool smooth) const;
+};
+
+
 class mnd::ClGeneratorDouble : public ClGenerator
 {
 public:

+ 1 - 0
libmandel/include/Generators.h

@@ -20,6 +20,7 @@ namespace mnd
     {
         FLOAT,
         DOUBLE_FLOAT,
+        TRIPLE_FLOAT,
         DOUBLE,
         DOUBLE_DOUBLE,
         TRIPLE_DOUBLE,

+ 2 - 1
libmandel/include/OpenClCode.h

@@ -7,9 +7,10 @@ namespace mnd
 {
     std::string getFloat_cl();
     std::string getDouble_cl();
-    std::string getDoubleFloat_cl();
     std::string getDoubleDouble_cl();
+    std::string getDoubleFloat_cl();
     std::string getTripleDouble_cl();
+    std::string getTripleFloat_cl();
     std::string getQuadDouble_cl();
     std::string getHexDouble_cl();
     std::string getFixed64_cl();

+ 9 - 0
libmandel/include/PolyfloatUtil.h

@@ -123,6 +123,15 @@ namespace mnd
             return { ahi, alo };
         }
 
+        inline Pair<float> split(float a)
+        {
+            static const float splitter = float((1ULL << 12) + 1);
+            float t = splitter * a;
+            float ahi = t - (t - a);
+            float alo = a - ahi;
+            return { ahi, alo };
+        }
+
         template<typename T>
         inline Pair<T> twoProd(T a, T b)
         {

+ 85 - 0
libmandel/include/TripleFloat.h

@@ -0,0 +1,85 @@
+#ifndef MANDEL_TRIPLEFLOAT_H
+#define MANDEL_TRIPLEFLOAT_H
+
+#include "PolyfloatUtil.h"
+
+namespace mnd
+{
+    struct TripleFloat;
+}
+
+struct mnd::TripleFloat
+{
+    float x[3];
+
+    inline TripleFloat(float val) :
+        x{ val, 0.0, 0.0 }
+    {}
+
+    inline TripleFloat(float a, float b, float c) :
+        x{ a, b, c }
+    {}
+
+    float operator[]           (int i) const   { return x[i]; }
+    const float& operator[]    (int i)         { return x[i]; }
+};
+
+
+inline mnd::TripleFloat operator+(const mnd::TripleFloat& a,
+    const mnd::TripleFloat& b)
+{
+    auto[r0, t0] = mnd::pfu::twoSum(a[0], b[0]);
+    auto[t1, t2] = mnd::pfu::twoSum(a[1], b[1]);
+    auto[r1, t3] = mnd::pfu::twoSum(t0, t1);
+    auto r2 = t2 + t3 + a[2] + b[2];
+
+    auto[re1, t4] = mnd::pfu::quickTwoSum(r0, r1);
+    auto[re2, re3] = mnd::pfu::quickTwoSum(t4, r2);
+    return { re1, re2, re3 };
+}
+
+
+inline bool operator>(const mnd::TripleFloat& a, const mnd::TripleFloat& b)
+{
+    if (a[0] > b[0])
+        return true;
+    if (a[0] < b[0])
+        return false;
+    if (a[1] > b[1])
+        return true;
+    if (a[1] < b[1])
+        return false;
+    return a[2] > b[2];
+}
+
+inline mnd::TripleFloat operator-(const mnd::TripleFloat& a,
+    const mnd::TripleFloat& b)
+{
+    auto[r0, t0] = mnd::pfu::twoSum(a[0], -b[0]);
+    auto[t1, t2] = mnd::pfu::twoSum(a[1], -b[1]);
+    auto[r1, t3] = mnd::pfu::twoSum(t0, t1);
+    auto r2 = t2 + t3 + a[2] - b[2];
+
+    auto[re1, t4] = mnd::pfu::quickTwoSum(r0, r1);
+    auto[re2, re3] = mnd::pfu::quickTwoSum(t4, r2);
+    return { re1, re2, re3 };
+}
+
+
+inline mnd::TripleFloat operator*(const mnd::TripleFloat& a,
+    const mnd::TripleFloat& b)
+{
+    auto[p1_0, p2_0] = mnd::pfu::twoProd(a[0], b[0]);
+    auto[p2_1, p3_0] = mnd::pfu::twoProd(a[0], b[1]);
+    auto[p2_2, p3_1] = mnd::pfu::twoProd(a[1], b[0]);
+
+    auto[t2, tl3] = mnd::pfu::threeTwoSum(p2_0, p2_1, p2_2);
+    auto t3 = tl3 + p3_0 + p3_1 + a[1] * b[1] + a[2] * b[0] + a[0] * b[2];
+    auto[re0, q2] = mnd::pfu::quickTwoSum(p1_0, t2);
+    auto[re1, re2] = mnd::pfu::quickTwoSum(q2, t3);
+    return { re0, re1, re2 };
+}
+
+
+#endif // MANDEL_TRIPLEFLOAT_H
+

+ 18 - 0
libmandel/include/Types.h

@@ -24,6 +24,7 @@
 
 #include "LightDoubleDouble.h"
 #include "TripleDouble.h"
+#include "TripleFloat.h"
 #include "HexDouble.h"
 
 namespace mnd
@@ -162,6 +163,23 @@ namespace mnd
     }
 
 #if defined(WITH_BOOST)
+
+    template<>
+    inline TripleFloat convert<TripleFloat, Real>(const Real& x)
+    {
+        float s = static_cast<float>(x);
+        Real t = x - s;
+        float e1 = static_cast<float>(t);
+        float e2 = static_cast<float>(t - e1);
+        return TripleFloat{ s, e1, e2 };
+    }
+
+    template<>
+    inline Real convert<Real, TripleFloat>(const TripleFloat& x)
+    {
+        return Real{ x[0] } + x[1] + x[2];
+    }
+    
     template<>
     inline DoubleDouble convert<DoubleDouble, Real>(const Real& x)
     {

+ 56 - 51
libmandel/src/ClGenerators.cpp

@@ -17,6 +17,7 @@ using namespace cl;
 using mnd::ClGenerator;
 using mnd::ClGeneratorFloat;
 using mnd::ClGeneratorDoubleFloat;
+using mnd::ClGeneratorTripleFloat;
 using mnd::ClGeneratorDouble;
 using mnd::ClGeneratorDoubleDouble;
 using mnd::ClGeneratorTripleDouble;
@@ -196,57 +197,6 @@ ClGeneratorDoubleFloat::ClGeneratorDoubleFloat(mnd::MandelDevice& device) :
 }
 
 
-std::pair<float, float> twoSum(float a, float b) {
-    float s = a + b;
-    float v = s - a;
-    float r = (a - (s - v)) + (b - v);
-    return { s, r };
-}
-
-std::pair<float, float> split(float a) {
-    float c = (4096 + 1) * a;
-    float abig = c - a;
-    float ahi = c - abig;
-    float alo = a - ahi;
-    return { ahi, alo };
-}
-
-std::pair<float, float> twoProd(float a, float b) {
-    float x = a * b;
-    auto aex = split(a);
-    auto bex = split(b);
-    float errx = x - (aex.first * bex.first);
-    float erry = errx - (aex.second * bex.first);
-    float errz = erry - (aex.first * bex.second);
-    float y = (aex.second * bex.second) - errz;
-    return { x, y };
-}
-
-std::pair<float, float> add(std::pair<float, float> a, std::pair<float, float> b) {
-    float r = a.first + b.first;
-    float s;
-    if (fabs(a.first) >= fabs(b.first)) {
-        s = (((a.first - r) + b.first) + b.second) + a.second;
-    }
-    else {
-        s = (((b.first - r) + a.first) + a.second) + b.second;
-    }
-    return twoSum(r, s);
-}
-
-std::pair<float, float> mul(std::pair<float, float> a, std::pair<float, float> b) {
-    auto t = twoProd(a.first, b.first);
-    t.second += ((a.first * b.second) + (a.second * b.first));
-    return twoSum(t.first, t.second);
-}
-
-std::pair<float, float> mulFloat(std::pair<float, float> a, float b) {
-    std::pair<float, float> t = twoProd(a.first, b);
-    float t3 = (a.second * b) + t.second;
-    return twoSum(t.first, t.second);
-}
-
-
 void ClGeneratorDoubleFloat::generate(const mnd::MandelInfo& info, float* data)
 {
     ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
@@ -289,6 +239,61 @@ std::string ClGeneratorDoubleFloat::getKernelCode(bool smooth) const
 }
 
 
+ClGeneratorTripleFloat::ClGeneratorTripleFloat(mnd::MandelDevice& device) :
+    ClGenerator{ device, this->getKernelCode(false), mnd::Precision::TRIPLE_FLOAT  }
+{
+    kernel = Kernel(program, "iterate");
+}
+
+
+void ClGeneratorTripleFloat::generate(const mnd::MandelInfo& info, float* data)
+{
+    ::size_t bufferSize = info.bWidth * info.bHeight * sizeof(float);
+
+    Buffer buffer_A(context, CL_MEM_WRITE_ONLY, bufferSize);
+    mnd::TripleFloat pixelScX = mnd::convert<mnd::TripleFloat>(info.view.width / info.bWidth);
+    mnd::TripleFloat pixelScY = mnd::convert<mnd::TripleFloat>(info.view.height / info.bHeight);
+
+    mnd::TripleFloat x = mnd::convert<mnd::TripleFloat>(info.view.x);
+    mnd::TripleFloat y = mnd::convert<mnd::TripleFloat>(info.view.y);
+    mnd::TripleFloat jx = mnd::convert<mnd::TripleFloat>(info.juliaX);
+    mnd::TripleFloat jy = mnd::convert<mnd::TripleFloat>(info.juliaY);
+
+    kernel.setArg(0, buffer_A);
+    kernel.setArg(1, int(info.bWidth));
+    kernel.setArg(2, x[0]);
+    kernel.setArg(3, x[1]);
+    kernel.setArg(4, x[2]);
+    kernel.setArg(5, y[0]);
+    kernel.setArg(6, y[1]);
+    kernel.setArg(7, y[2]);
+    kernel.setArg(8, pixelScX[0]);
+    kernel.setArg(9, pixelScX[1]);
+    kernel.setArg(10, pixelScX[2]);
+    kernel.setArg(11, pixelScY[0]);
+    kernel.setArg(12, pixelScY[1]);
+    kernel.setArg(13, pixelScY[2]);
+    kernel.setArg(14, int(info.maxIter));
+    kernel.setArg(15, int(info.smooth ? 1 : 0));
+    kernel.setArg(16, int(info.julia ? 1 : 0));
+    kernel.setArg(17, jx[0]);
+    kernel.setArg(18, jx[1]);
+    kernel.setArg(19, jx[2]);
+    kernel.setArg(20, jy[0]);
+    kernel.setArg(21, jy[1]);
+    kernel.setArg(22, jy[2]);
+
+    cl_int result = queue.enqueueNDRangeKernel(kernel, 0, NDRange(info.bWidth * info.bHeight));
+    queue.enqueueReadBuffer(buffer_A, CL_TRUE, 0, bufferSize, data);
+}
+
+
+std::string ClGeneratorTripleFloat::getKernelCode(bool smooth) const
+{
+    return getTripleFloat_cl();
+}
+
+
 ClGeneratorDouble::ClGeneratorDouble(mnd::MandelDevice& device, const std::string& source) :
     ClGenerator{ device, source, mnd::Precision::DOUBLE }
 {

+ 3 - 0
libmandel/src/Generators.cpp

@@ -126,6 +126,8 @@ namespace mnd
             return "float";
         case Precision::DOUBLE_FLOAT:
             return "double-float";
+        case Precision::TRIPLE_FLOAT:
+            return "triple-float";
         case Precision::DOUBLE:
             return "double";
         case Precision::DOUBLE_DOUBLE:
@@ -180,6 +182,7 @@ namespace mnd
         static const std::map<Precision, Real> precs {
             { Precision::FLOAT, getPrecision<float>() },
             { Precision::DOUBLE_FLOAT, Real("4.0e-15") },
+            { Precision::TRIPLE_FLOAT, Real("1.0e-21") },
             { Precision::DOUBLE, getPrecision<double>() },
             { Precision::DOUBLE_DOUBLE, Real("1.0e-29") },
             { Precision::TRIPLE_DOUBLE, Real("1.0e-47") },

+ 6 - 0
libmandel/src/Mandel.cpp

@@ -248,6 +248,12 @@ std::vector<std::unique_ptr<MandelDevice>> MandelContext::createDevices(void)
             catch (const std::string& err) {
                 printf("err: %s", err.c_str());
             }
+            try {
+                md.mandelGenerators.insert({ Precision::TRIPLE_FLOAT, std::make_unique<ClGeneratorTripleFloat>(md) });
+            }
+            catch (const std::string& err) {
+                printf("err: %s", err.c_str());
+            }
 
             if (supportsDouble) {
                 try {

+ 5 - 0
libmandel/src/OpenClCode.cpp

@@ -5,6 +5,7 @@
 #include "opencl/doublefloat.h"
 #include "opencl/doubledouble.h"
 #include "opencl/tripledouble.h"
+#include "opencl/triplefloat.h"
 #include "opencl/quaddouble.h"
 #include "opencl/hexdouble.h"
 
@@ -34,6 +35,10 @@ namespace mnd
         return std::string{ (char*) tripledouble_cl, tripledouble_cl_len };
     }
 
+    std::string getTripleFloat_cl() {
+        return std::string{ (char*) triplefloat_cl, triplefloat_cl_len };
+    }
+
     std::string getQuadDouble_cl() {
         return std::string{ (char*) quaddouble_cl, quaddouble_cl_len };
     }

+ 103 - 0
libmandel/src/opencl/triplefloat.cl

@@ -0,0 +1,103 @@
+#pragma OPENCL FP_CONTRACT OFF
+
+inline float2 twoSum(float a, float b) {
+    float s = a + b;
+    float bb = s - a;
+    float e = (a - (s - bb)) + (b - bb);
+    return (float2)(s, e);
+}
+
+inline float2 quickTwoSum(float a, float b) {
+    float s = a + b;
+    float e = b - (s - a);
+    return (float2)(s, e);
+}
+
+inline float2 twoProd(float a, float b) {
+    float p = a * b;
+    float e = fma(a, b, -p);
+    return (float2)(p, e);
+}
+
+inline float2 threeTwoSum(float a, float b, float c)
+{
+    float2 t = twoSum(a, b);
+    float2 rt = twoSum(t.s0, c);
+    return (float2)(rt.s0, t.s1 + rt.s1);
+}
+
+inline float3 mul(float3 a, float3 b) {
+    float2 p1 = twoProd(a.s0, b.s0);
+    float2 p2 = twoProd(a.s0, b.s1);
+    float2 p3 = twoProd(a.s1, b.s0);
+
+    float2 t12 = threeTwoSum(p1.s1, p2.s0, p3.s0);
+    float t3 = t12.s1 + p2.s1 + p3.s1 + a.s2 * b.s0 + a.s0 * b.s2 + a.s1 * b.s1;
+    float2 re0q = quickTwoSum(p1.s0, t12.s0);
+    float2 rer = quickTwoSum(re0q.s1, t3);
+    return (float3)(re0q.s0, rer.s0, rer.s1);
+}
+
+inline float3 sq(float3 a) {
+    // TODO: improve
+    return mul(a, a);
+}
+
+inline float3 add(float3 a, float3 b) {
+    float2 rt = twoSum(a.s0, b.s0);
+    float2 t12 = twoSum(a.s1, b.s1);
+    float2 t34 = twoSum(rt.s1, t12.s0);
+    float r2 = t12.s1 + t34.s1 + a.s2 + b.s2;
+
+    float2 re1t4 = quickTwoSum(rt.s0, t34.s0);
+    float2 re23 = twoSum(re1t4.s1, r2);
+    return (float3)(re1t4.s0, re23.s0, re23.s1);
+}
+
+inline float3 mulSingle(float3 a, float b) {
+    // TODO: improve
+    return mul(a, (float3)(b, 0.0, 0.0));
+}
+
+__kernel void iterate(__global float* A, const int width,
+                      float x1, float x2, float x3, float y1, float y2, float y3,
+                      float pw1, float pw2, float pw3, float ph1, float ph2, float ph3, int max, int smooth,
+                      int julia, float jx1, float jx2, float jx3, float jy1, float jy2, float jy3) {
+    int index = get_global_id(0);
+    int px = index % width;
+    int py = index / width;
+
+    float3 xl = (float3)(x1, x2, x3);
+    float3 yt = (float3)(y1, y2, y3);
+    float3 pixelScaleX = (float3)(pw1, pw2, pw3);
+    float3 pixelScaleY = (float3)(ph1, ph2, ph3);
+    float3 a = add(mulSingle(pixelScaleX, (float) px), xl); // pixelScaleX * px + xl
+    float3 b = add(mulSingle(pixelScaleY, (float) py), yt); // pixelScaleY * py + yt
+    float3 ca = julia != 0 ? ((float3) (jx1, jx2, jx3)) : a;
+    float3 cb = julia != 0 ? ((float3) (jy1, jy2, jy3)) : b;
+
+
+    int n = 0;
+    while (n < max - 1) {
+        float3 aa = mul(a, a);
+        float3 bb = mul(b, b);
+        float3 ab = mul(a, b);
+        float3 minusbb = (float3)(-bb.s0, -bb.s1, -bb.s2);
+        a = add(add(aa, minusbb), ca);
+        b = add(add(ab, ab), cb);
+        if (aa.s0 + bb.s0 > 16) break;
+        n++;
+    }
+
+    // N + 1 - log (log  |Z(N)|) / log 2
+    if (n >= max - 1)
+        A[index] = max;
+    else {
+        if (smooth != 0)
+            A[index] = ((float) n) + 1.0f - log2(log(a.s0 * a.s0 + b.s0 * b.s0) * 0.5f);
+        else
+            A[index] = ((float) n);
+    }
+    //               A[index] = ((float)n) + 1 - (a * a + b * b - 16) / (256 - 16);
+    //           A[get_global_id(0)] = 5;
+}

+ 268 - 0
libmandel/src/opencl/triplefloat.h

@@ -0,0 +1,268 @@
+unsigned char triplefloat_cl[] = {
+  0x23, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x20, 0x4f, 0x50, 0x45, 0x4e,
+  0x43, 0x4c, 0x20, 0x46, 0x50, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x41,
+  0x43, 0x54, 0x20, 0x4f, 0x46, 0x46, 0x0a, 0x0a, 0x69, 0x6e, 0x6c, 0x69,
+  0x6e, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x74, 0x77,
+  0x6f, 0x53, 0x75, 0x6d, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x61,
+  0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x62, 0x29, 0x20, 0x7b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73,
+  0x20, 0x3d, 0x20, 0x61, 0x20, 0x2b, 0x20, 0x62, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x62, 0x62, 0x20, 0x3d,
+  0x20, 0x73, 0x20, 0x2d, 0x20, 0x61, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x65, 0x20, 0x3d, 0x20, 0x28, 0x61,
+  0x20, 0x2d, 0x20, 0x28, 0x73, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x29, 0x29,
+  0x20, 0x2b, 0x20, 0x28, 0x62, 0x20, 0x2d, 0x20, 0x62, 0x62, 0x29, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
+  0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x29, 0x28, 0x73, 0x2c, 0x20,
+  0x65, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x69, 0x6e, 0x6c, 0x69, 0x6e,
+  0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x71, 0x75, 0x69,
+  0x63, 0x6b, 0x54, 0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x61, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x2b, 0x20, 0x62,
+  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x65, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x2d, 0x20, 0x28, 0x73, 0x20, 0x2d,
+  0x20, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
+  0x75, 0x72, 0x6e, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x29,
+  0x28, 0x73, 0x2c, 0x20, 0x65, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x69,
+  0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32,
+  0x20, 0x74, 0x77, 0x6f, 0x50, 0x72, 0x6f, 0x64, 0x28, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x61, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x70, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x2a, 0x20, 0x62,
+  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x65, 0x20, 0x3d, 0x20, 0x66, 0x6d, 0x61, 0x28, 0x61, 0x2c, 0x20, 0x62,
+  0x2c, 0x20, 0x2d, 0x70, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
+  0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x32, 0x29, 0x28, 0x70, 0x2c, 0x20, 0x65, 0x29, 0x3b, 0x0a, 0x7d, 0x0a,
+  0x0a, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x54, 0x77, 0x6f, 0x53,
+  0x75, 0x6d, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x61, 0x2c, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x62, 0x2c, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x63, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x74,
+  0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20,
+  0x72, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28,
+  0x74, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x63, 0x29, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x32, 0x29, 0x28, 0x72, 0x74, 0x2e, 0x73, 0x30, 0x2c,
+  0x20, 0x74, 0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x72, 0x74, 0x2e, 0x73,
+  0x31, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x69, 0x6e, 0x6c, 0x69, 0x6e,
+  0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x6d, 0x75, 0x6c,
+  0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x2c, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x62, 0x29, 0x20, 0x7b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x70, 0x31,
+  0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f, 0x50, 0x72, 0x6f, 0x64, 0x28, 0x61,
+  0x2e, 0x73, 0x30, 0x2c, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x29, 0x3b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x70,
+  0x32, 0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f, 0x50, 0x72, 0x6f, 0x64, 0x28,
+  0x61, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x62, 0x2e, 0x73, 0x31, 0x29, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20,
+  0x70, 0x33, 0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f, 0x50, 0x72, 0x6f, 0x64,
+  0x28, 0x61, 0x2e, 0x73, 0x31, 0x2c, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x29,
+  0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x32, 0x20, 0x74, 0x31, 0x32, 0x20, 0x3d, 0x20, 0x74, 0x68, 0x72, 0x65,
+  0x65, 0x54, 0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x70, 0x31, 0x2e, 0x73,
+  0x31, 0x2c, 0x20, 0x70, 0x32, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x70, 0x33,
+  0x2e, 0x73, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x74, 0x33, 0x20, 0x3d, 0x20, 0x74, 0x31, 0x32,
+  0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x70, 0x32, 0x2e, 0x73, 0x31, 0x20,
+  0x2b, 0x20, 0x70, 0x33, 0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x61, 0x2e,
+  0x73, 0x32, 0x20, 0x2a, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x20, 0x2b, 0x20,
+  0x61, 0x2e, 0x73, 0x30, 0x20, 0x2a, 0x20, 0x62, 0x2e, 0x73, 0x32, 0x20,
+  0x2b, 0x20, 0x61, 0x2e, 0x73, 0x31, 0x20, 0x2a, 0x20, 0x62, 0x2e, 0x73,
+  0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x32, 0x20, 0x72, 0x65, 0x30, 0x71, 0x20, 0x3d, 0x20, 0x71, 0x75, 0x69,
+  0x63, 0x6b, 0x54, 0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x70, 0x31, 0x2e,
+  0x73, 0x30, 0x2c, 0x20, 0x74, 0x31, 0x32, 0x2e, 0x73, 0x30, 0x29, 0x3b,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20,
+  0x72, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x54,
+  0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x72, 0x65, 0x30, 0x71, 0x2e, 0x73,
+  0x31, 0x2c, 0x20, 0x74, 0x33, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x33, 0x29, 0x28, 0x72, 0x65, 0x30, 0x71, 0x2e, 0x73, 0x30, 0x2c,
+  0x20, 0x72, 0x65, 0x72, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x72, 0x65, 0x72,
+  0x2e, 0x73, 0x31, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x69, 0x6e, 0x6c,
+  0x69, 0x6e, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x73,
+  0x71, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x29, 0x20,
+  0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x4f, 0x44,
+  0x4f, 0x3a, 0x20, 0x69, 0x6d, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x75,
+  0x6c, 0x28, 0x61, 0x2c, 0x20, 0x61, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a,
+  0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x33, 0x20, 0x61, 0x64, 0x64, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33,
+  0x20, 0x61, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x62,
+  0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x32, 0x20, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f, 0x53,
+  0x75, 0x6d, 0x28, 0x61, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x62, 0x2e, 0x73,
+  0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x32, 0x20, 0x74, 0x31, 0x32, 0x20, 0x3d, 0x20, 0x74, 0x77, 0x6f,
+  0x53, 0x75, 0x6d, 0x28, 0x61, 0x2e, 0x73, 0x31, 0x2c, 0x20, 0x62, 0x2e,
+  0x73, 0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x32, 0x20, 0x74, 0x33, 0x34, 0x20, 0x3d, 0x20, 0x74, 0x77,
+  0x6f, 0x53, 0x75, 0x6d, 0x28, 0x72, 0x74, 0x2e, 0x73, 0x31, 0x2c, 0x20,
+  0x74, 0x31, 0x32, 0x2e, 0x73, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x72, 0x32, 0x20, 0x3d, 0x20,
+  0x74, 0x31, 0x32, 0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x74, 0x33, 0x34,
+  0x2e, 0x73, 0x31, 0x20, 0x2b, 0x20, 0x61, 0x2e, 0x73, 0x32, 0x20, 0x2b,
+  0x20, 0x62, 0x2e, 0x73, 0x32, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x72, 0x65, 0x31, 0x74, 0x34,
+  0x20, 0x3d, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x54, 0x77, 0x6f, 0x53,
+  0x75, 0x6d, 0x28, 0x72, 0x74, 0x2e, 0x73, 0x30, 0x2c, 0x20, 0x74, 0x33,
+  0x34, 0x2e, 0x73, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x72, 0x65, 0x32, 0x33, 0x20, 0x3d,
+  0x20, 0x74, 0x77, 0x6f, 0x53, 0x75, 0x6d, 0x28, 0x72, 0x65, 0x31, 0x74,
+  0x34, 0x2e, 0x73, 0x31, 0x2c, 0x20, 0x72, 0x32, 0x29, 0x3b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x33, 0x29, 0x28, 0x72, 0x65, 0x31, 0x74, 0x34,
+  0x2e, 0x73, 0x30, 0x2c, 0x20, 0x72, 0x65, 0x32, 0x33, 0x2e, 0x73, 0x30,
+  0x2c, 0x20, 0x72, 0x65, 0x32, 0x33, 0x2e, 0x73, 0x31, 0x29, 0x3b, 0x0a,
+  0x7d, 0x0a, 0x0a, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x33, 0x20, 0x6d, 0x75, 0x6c, 0x53, 0x69, 0x6e, 0x67,
+  0x6c, 0x65, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x2c,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x62, 0x29, 0x20, 0x7b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x4f, 0x44, 0x4f, 0x3a,
+  0x20, 0x69, 0x6d, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x75, 0x6c, 0x28,
+  0x61, 0x2c, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x29, 0x28,
+  0x62, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x2c, 0x20, 0x30, 0x2e, 0x30, 0x29,
+  0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x5f, 0x5f, 0x6b, 0x65, 0x72, 0x6e,
+  0x65, 0x6c, 0x20, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x69, 0x74, 0x65, 0x72,
+  0x61, 0x74, 0x65, 0x28, 0x5f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x2a, 0x20, 0x41, 0x2c, 0x20, 0x63,
+  0x6f, 0x6e, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x64,
+  0x74, 0x68, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x78, 0x31, 0x2c, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x78, 0x32, 0x2c, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x78, 0x33, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x79, 0x31, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x79, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x79, 0x33,
+  0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x70, 0x77, 0x31, 0x2c, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x70, 0x77, 0x32, 0x2c, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x70, 0x77, 0x33, 0x2c, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x70, 0x68, 0x31, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x70, 0x68, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x70, 0x68, 0x33, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6d, 0x61,
+  0x78, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x6d, 0x6f, 0x6f, 0x74,
+  0x68, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x69, 0x6e, 0x74, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x61, 0x2c, 0x20,
+  0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6a, 0x78, 0x31, 0x2c, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6a, 0x78, 0x32, 0x2c, 0x20, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x6a, 0x78, 0x33, 0x2c, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x6a, 0x79, 0x31, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x6a, 0x79, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x6a, 0x79, 0x33, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x69, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20,
+  0x67, 0x65, 0x74, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x69,
+  0x64, 0x28, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e,
+  0x74, 0x20, 0x70, 0x78, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x64, 0x65, 0x78,
+  0x20, 0x25, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x70, 0x79, 0x20, 0x3d, 0x20, 0x69,
+  0x6e, 0x64, 0x65, 0x78, 0x20, 0x2f, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68,
+  0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x33, 0x20, 0x78, 0x6c, 0x20, 0x3d, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x33, 0x29, 0x28, 0x78, 0x31, 0x2c, 0x20, 0x78, 0x32, 0x2c, 0x20,
+  0x78, 0x33, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x33, 0x20, 0x79, 0x74, 0x20, 0x3d, 0x20, 0x28, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x33, 0x29, 0x28, 0x79, 0x31, 0x2c, 0x20, 0x79, 0x32,
+  0x2c, 0x20, 0x79, 0x33, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x53,
+  0x63, 0x61, 0x6c, 0x65, 0x58, 0x20, 0x3d, 0x20, 0x28, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x33, 0x29, 0x28, 0x70, 0x77, 0x31, 0x2c, 0x20, 0x70, 0x77,
+  0x32, 0x2c, 0x20, 0x70, 0x77, 0x33, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x70, 0x69, 0x78, 0x65,
+  0x6c, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x59, 0x20, 0x3d, 0x20, 0x28, 0x66,
+  0x6c, 0x6f, 0x61, 0x74, 0x33, 0x29, 0x28, 0x70, 0x68, 0x31, 0x2c, 0x20,
+  0x70, 0x68, 0x32, 0x2c, 0x20, 0x70, 0x68, 0x33, 0x29, 0x3b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x61, 0x20,
+  0x3d, 0x20, 0x61, 0x64, 0x64, 0x28, 0x6d, 0x75, 0x6c, 0x53, 0x69, 0x6e,
+  0x67, 0x6c, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63, 0x61,
+  0x6c, 0x65, 0x58, 0x2c, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x29,
+  0x20, 0x70, 0x78, 0x29, 0x2c, 0x20, 0x78, 0x6c, 0x29, 0x3b, 0x20, 0x2f,
+  0x2f, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63, 0x61, 0x6c, 0x65,
+  0x58, 0x20, 0x2a, 0x20, 0x70, 0x78, 0x20, 0x2b, 0x20, 0x78, 0x6c, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x62,
+  0x20, 0x3d, 0x20, 0x61, 0x64, 0x64, 0x28, 0x6d, 0x75, 0x6c, 0x53, 0x69,
+  0x6e, 0x67, 0x6c, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63,
+  0x61, 0x6c, 0x65, 0x59, 0x2c, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x29, 0x20, 0x70, 0x79, 0x29, 0x2c, 0x20, 0x79, 0x74, 0x29, 0x3b, 0x20,
+  0x2f, 0x2f, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x53, 0x63, 0x61, 0x6c,
+  0x65, 0x59, 0x20, 0x2a, 0x20, 0x70, 0x79, 0x20, 0x2b, 0x20, 0x79, 0x74,
+  0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20,
+  0x63, 0x61, 0x20, 0x3d, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x61, 0x20, 0x21,
+  0x3d, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x33, 0x29, 0x20, 0x28, 0x6a, 0x78, 0x31, 0x2c, 0x20, 0x6a, 0x78,
+  0x32, 0x2c, 0x20, 0x6a, 0x78, 0x33, 0x29, 0x29, 0x20, 0x3a, 0x20, 0x61,
+  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33,
+  0x20, 0x63, 0x62, 0x20, 0x3d, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x61, 0x20,
+  0x21, 0x3d, 0x20, 0x30, 0x20, 0x3f, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x33, 0x29, 0x20, 0x28, 0x6a, 0x79, 0x31, 0x2c, 0x20, 0x6a,
+  0x79, 0x32, 0x2c, 0x20, 0x6a, 0x79, 0x33, 0x29, 0x29, 0x20, 0x3a, 0x20,
+  0x62, 0x3b, 0x0a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74,
+  0x20, 0x6e, 0x20, 0x3d, 0x20, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x6e, 0x20, 0x3c, 0x20, 0x6d,
+  0x61, 0x78, 0x20, 0x2d, 0x20, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33,
+  0x20, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c, 0x28, 0x61, 0x2c,
+  0x20, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x62, 0x62, 0x20, 0x3d,
+  0x20, 0x6d, 0x75, 0x6c, 0x28, 0x62, 0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61,
+  0x74, 0x33, 0x20, 0x61, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x75, 0x6c, 0x28,
+  0x61, 0x2c, 0x20, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x6d, 0x69,
+  0x6e, 0x75, 0x73, 0x62, 0x62, 0x20, 0x3d, 0x20, 0x28, 0x66, 0x6c, 0x6f,
+  0x61, 0x74, 0x33, 0x29, 0x28, 0x2d, 0x62, 0x62, 0x2e, 0x73, 0x30, 0x2c,
+  0x20, 0x2d, 0x62, 0x62, 0x2e, 0x73, 0x31, 0x2c, 0x20, 0x2d, 0x62, 0x62,
+  0x2e, 0x73, 0x32, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x64, 0x28, 0x61, 0x64,
+  0x64, 0x28, 0x61, 0x61, 0x2c, 0x20, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x62,
+  0x62, 0x29, 0x2c, 0x20, 0x63, 0x61, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x64,
+  0x28, 0x61, 0x64, 0x64, 0x28, 0x61, 0x62, 0x2c, 0x20, 0x61, 0x62, 0x29,
+  0x2c, 0x20, 0x63, 0x62, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x61, 0x61, 0x2e, 0x73, 0x30,
+  0x20, 0x2b, 0x20, 0x62, 0x62, 0x2e, 0x73, 0x30, 0x20, 0x3e, 0x20, 0x31,
+  0x36, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x2b, 0x2b, 0x3b, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f,
+  0x20, 0x4e, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x6c, 0x6f, 0x67,
+  0x20, 0x28, 0x6c, 0x6f, 0x67, 0x20, 0x20, 0x7c, 0x5a, 0x28, 0x4e, 0x29,
+  0x7c, 0x29, 0x20, 0x2f, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x32, 0x0a, 0x20,
+  0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20, 0x3e, 0x3d, 0x20,
+  0x6d, 0x61, 0x78, 0x20, 0x2d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78,
+  0x5d, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x6d, 0x6f, 0x6f,
+  0x74, 0x68, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69,
+  0x6e, 0x64, 0x65, 0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c,
+  0x6f, 0x61, 0x74, 0x29, 0x20, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x2e,
+  0x30, 0x66, 0x20, 0x2d, 0x20, 0x6c, 0x6f, 0x67, 0x32, 0x28, 0x6c, 0x6f,
+  0x67, 0x28, 0x61, 0x2e, 0x73, 0x30, 0x20, 0x2a, 0x20, 0x61, 0x2e, 0x73,
+  0x30, 0x20, 0x2b, 0x20, 0x62, 0x2e, 0x73, 0x30, 0x20, 0x2a, 0x20, 0x62,
+  0x2e, 0x73, 0x30, 0x29, 0x20, 0x2a, 0x20, 0x30, 0x2e, 0x35, 0x66, 0x29,
+  0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
+  0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5d, 0x20,
+  0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x29, 0x20, 0x6e,
+  0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x5b, 0x69, 0x6e, 0x64, 0x65,
+  0x78, 0x5d, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74,
+  0x29, 0x6e, 0x29, 0x20, 0x2b, 0x20, 0x31, 0x20, 0x2d, 0x20, 0x28, 0x61,
+  0x20, 0x2a, 0x20, 0x61, 0x20, 0x2b, 0x20, 0x62, 0x20, 0x2a, 0x20, 0x62,
+  0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x20, 0x2f, 0x20, 0x28, 0x32, 0x35,
+  0x36, 0x20, 0x2d, 0x20, 0x31, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20,
+  0x20, 0x2f, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x41, 0x5b, 0x67, 0x65, 0x74, 0x5f, 0x67, 0x6c, 0x6f, 0x62,
+  0x61, 0x6c, 0x5f, 0x69, 0x64, 0x28, 0x30, 0x29, 0x5d, 0x20, 0x3d, 0x20,
+  0x35, 0x3b, 0x0a, 0x7d, 0x0a
+};
+unsigned int triplefloat_cl_len = 3173;