Nicolas Winkler 5 年 前
コミット
31f7a453ea

+ 1 - 1
Almond.pro

@@ -124,7 +124,7 @@ unix|win32: LIBS += -L$$PWD/../libs/ffmpeg-4.1.1-win32-dev/lib/ -lswscale
 
 RESOURCES += Almond.qrc
 
-unix|win32: LIBS += -L$$PWD/libmandel/ -lmandel
+unix|win32: LIBS += -L$$PWD/libmandel/ -lmandel -lqd
 
 INCLUDEPATH += $$PWD/libmandel/include
 DEPENDPATH += $$PWD/libmandel/include

+ 1 - 1
benchmarkdialog.cpp

@@ -106,7 +106,7 @@ void Benchmarker::start(void)
     mnd::Generator& cpuf = mndContext.getCpuGeneratorFloat();
     mnd::Generator& cpud = mndContext.getCpuGeneratorDouble();
     mnd::Generator* cpu128 = mndContext.getCpuGeneratorQuad();
-    mnd::Generator* cpu256 = mndContext.getCpuGenerator128();
+    mnd::Generator* cpu256 = mndContext.getCpuGeneratorDD();
 
     double nTests = 2;
 

+ 9 - 2
libmandel/CMakeLists.txt

@@ -1,7 +1,5 @@
 cmake_minimum_required(VERSION 3.9)
 
-
-
 set(ARCH "X86_64" CACHE STRING "Target Architecture")
 
 #message(CMAKE_SYSTEM_PROCESSOR)
@@ -57,6 +55,15 @@ if (LTO_SUPPORTED)
     set_property(TARGET mandel PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
 endif(LTO_SUPPORTED)
 
+FILE(GLOB QdSources qd-2.3.22/src/*.cpp)
+
+target_compile_definitions(mandel PUBLIC WITH_QD)
+add_library(qd STATIC ${QdSources})
+target_include_directories(qd PUBLIC qd-2.3.22/include)
+target_include_directories(qd PUBLIC qd-2.3.22)
+
+#target_include_directories(mandel PUBLI#C qd-2.3.22/include)
+target_link_libraries(mandel PUBLIC qd)
 
 if(MPFR_INCLUDES AND MPFR_LIBRARIES)
     set(MPFR_FOUND TRUE)

+ 9 - 5
libmandel/include/Mandel.h

@@ -7,6 +7,7 @@
 
 #include "MandelUtil.h"
 #include "Generators.h"
+#include "CpuGenerators.h"
 #include "Hardware.h"
 
 //#include "Fixedp.h"
@@ -54,7 +55,7 @@ public:
 class mnd::MandelContext
 {
 private:
-    friend MandelContext initializeContext(void);
+    friend MandelContext mnd::initializeContext(void);
 
     CpuInfo cpuInfo;
 
@@ -63,11 +64,13 @@ private:
     std::unique_ptr<Generator> cpuGeneratorQuad;
     std::unique_ptr<Generator> cpuGeneratorOct;
     std::unique_ptr<Generator> cpuGenerator128;
+    std::unique_ptr<Generator> cpuGeneratorDD;
 
     std::unique_ptr<Generator> cpuGeneratorFloatSmooth;
     std::unique_ptr<Generator> cpuGeneratorDoubleSmooth;
     std::unique_ptr<Generator> cpuGeneratorQuadSmooth;
     std::unique_ptr<Generator> cpuGenerator128Smooth;
+    std::unique_ptr<Generator> cpuGeneratorDDSmooth;
 
     std::unique_ptr<Generator> adaptiveGenerator;
     std::unique_ptr<Generator> adaptiveGeneratorSmooth;
@@ -83,10 +86,11 @@ public:
     const std::vector<MandelDevice>& getDevices(void);
 
     Generator& getCpuGeneratorFloat(void);
-    Generator& getCpuGeneratorDouble(void); 
-    Generator* getCpuGeneratorQuad(void); 
-    Generator* getCpuGeneratorOct(void); 
-    Generator* getCpuGenerator128(void); 
+    Generator& getCpuGeneratorDouble(void);
+    Generator* getCpuGeneratorQuad(void);
+    Generator* getCpuGeneratorOct(void);
+    Generator* getCpuGenerator128(void);
+    Generator* getCpuGeneratorDD(void);
 
     const CpuInfo& getCpuInfo(void) const { return cpuInfo; }
 };

+ 41 - 3
libmandel/include/Types.h

@@ -3,6 +3,7 @@
 
 #include <cinttypes>
 #include <cmath>
+#include <string>
 #include "Fixed.h"
 
 #ifdef WITH_BOOST
@@ -13,20 +14,24 @@
 #   include <boost/multiprecision/cpp_int.hpp>
 #endif
 
+#ifdef WITH_QD
+#   include <qd/dd_real.h>
+#endif
+
 namespace mnd
 {
 
 
 #ifdef WITH_BOOST
-#if 0//defined(__GNUC__) || defined(__INTEL_COMPILER)
+#   if 0//defined(__GNUC__) || defined(__INTEL_COMPILER)
     using Float128 = boost::multiprecision::float128;
-#else
+#   else
     //using Float128 = boost::multiprecision::cpp_bin_float_quad;
     using Float128 = boost::multiprecision::number<
         boost::multiprecision::backends::cpp_bin_float<
             112, boost::multiprecision::backends::digit_base_2, void, boost::int16_t, -16382, 16383>,
             boost::multiprecision::et_off>;
-#endif
+#   endif
     inline Float128 abs(const Float128& x) { return boost::multiprecision::abs(x); }
     inline Float128 floor(const Float128& x) { return boost::multiprecision::floor(x); }
     inline Float128 log(const Float128& x) { return boost::multiprecision::log(x); }
@@ -54,6 +59,17 @@ namespace mnd
     using Integer = int64_t;
 #endif
 
+
+#ifdef WITH_QD
+    using DoubleDouble = dd_real;
+
+    inline DoubleDouble abs(const DoubleDouble& x) { return ::abs(x); }
+    inline DoubleDouble floor(const DoubleDouble& x) { return ::floor(x); }
+    inline DoubleDouble log(const DoubleDouble& x) { return ::log(x); }
+    inline DoubleDouble log2(const DoubleDouble& x) { return ::log(x) / ::log(DoubleDouble(2.0)); }
+    inline DoubleDouble pow(const DoubleDouble& x, const DoubleDouble& y) { return ::pow(x, y); }
+#endif
+
     inline double abs(double x) { return ::abs(x); }
     inline float abs(float x) { return ::abs(x); }
     inline double floor(double x) { return ::floor(x); }
@@ -64,6 +80,28 @@ namespace mnd
     inline float log2(float x) { return ::log2f(x); }
     inline double pow(double x, double y) { return ::pow(x, y); }
     inline float pow(float x, float y) { return ::powf(x, y); }
+
+
+    template<typename T, typename U>
+    T convert(const U& x)
+    {
+        return static_cast<T>(x);
+    }
+
+#if defined(WITH_BOOST) && defined(WITH_QD)
+    template<>
+    inline DoubleDouble convert<DoubleDouble, Real>(const Real& x)
+    {
+        std::string s = x.str();
+        return DoubleDouble(s.c_str());
+    }
+
+    template<>
+    inline float convert<float, DoubleDouble>(const DoubleDouble& x)
+    {
+        return float(x.x[0] + x.x[1]);
+    }
+#endif
 }
 
 

+ 15 - 3
libmandel/src/CpuGenerators.cpp

@@ -43,6 +43,13 @@ namespace mnd
     template class CpuGenerator<mnd::Float256, mnd::NONE, true, false>;
     template class CpuGenerator<mnd::Float256, mnd::NONE, true, true>;
 #endif
+
+#ifdef WITH_QD
+    template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, false, false>;
+    template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, false, true>;
+    template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, true, false>;
+    template class CpuGenerator<mnd::DoubleDouble, mnd::NONE, true, true>;
+#endif
 }
 
 
@@ -51,14 +58,19 @@ void CpuGenerator<T, mnd::NONE, parallel, smooth>::generate(const mnd::MandelInf
 {
     const MandelViewport& view = info.view;
 
+    T viewx = mnd::convert<T>(view.x);
+    T viewy = mnd::convert<T>(view.y);
+    T wpp = mnd::convert<T>(view.width / info.bWidth);
+    T hpp = mnd::convert<T>(view.height / info.bHeight);
+
     if constexpr (parallel)
         omp_set_num_threads(2 * omp_get_num_procs());
 #pragma omp parallel for if (parallel)
     for (long j = 0; j < info.bHeight; j++) {
-        T y = T(view.y) + T(j) * T(view.height / info.bHeight);
+        T y = viewy + T(double(j)) * hpp;
         long i = 0;
         for (i; i < info.bWidth; i++) {
-            T x = T(view.x + T(i) * T(view.width / info.bWidth));
+            T x = viewx + T(double(i)) * wpp;
 
             T a = x;
             T b = y;
@@ -78,7 +90,7 @@ void CpuGenerator<T, mnd::NONE, parallel, smooth>::generate(const mnd::MandelInf
                 if (k >= info.maxIter)
                     data[i + j * info.bWidth] = info.maxIter;
                 else
-                    data[i + j * info.bWidth] = ((float) k) + 1 - ::logf(::logf(float(a * a + b * b)) / 2) / ::logf(2.0f);
+                    data[i + j * info.bWidth] = ((float) k) + 1 - ::logf(::logf(mnd::convert<float>(a * a + b * b)) / 2) / ::logf(2.0f);
             }
             else
                 data[i + j * info.bWidth] = k;

+ 13 - 2
libmandel/src/Mandel.cpp

@@ -112,6 +112,11 @@ MandelContext::MandelContext(void) :
     cpuGenerator128Smooth = std::make_unique<CpuGenerator<Fixed128, mnd::NONE, true, true>>();
 #endif // WITH_BOOST
 
+#ifdef WITH_QD
+    cpuGeneratorDD = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true, false>>();
+    cpuGeneratorDDSmooth = std::make_unique<CpuGenerator<DoubleDouble, mnd::NONE, true, true>>();
+#endif
+
     devices = createDevices();
     if (devices.empty()) {
 #ifdef WITH_BOOST
@@ -142,8 +147,8 @@ MandelContext::MandelContext(void) :
         if (doubleGeneratorSmooth == nullptr)
             doubleGeneratorSmooth = cpuGeneratorDoubleSmooth.get();
 #ifdef WITH_BOOST
-        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth, cpuGenerator128Smooth.get());
-        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator, cpuGenerator128.get());
+        adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth, cpuGeneratorDDSmooth.get());
+        adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator, cpuGeneratorDD.get());
 #else
         adaptiveGeneratorSmooth = std::make_unique<AdaptiveGenerator>(floatGeneratorSmooth, doubleGeneratorSmooth);
         adaptiveGenerator = std::make_unique<AdaptiveGenerator>(floatGenerator, doubleGenerator);
@@ -267,3 +272,9 @@ Generator* MandelContext::getCpuGenerator128(void)
 {
     return cpuGenerator128.get();
 }
+
+
+Generator* MandelContext::getCpuGeneratorDD(void)
+{
+    return cpuGeneratorDD.get();
+}