├── .gitattributes ├── .gitignore ├── C ├── BSD-LBNL-License.doc ├── BuildAndroid.bat ├── BuildIOS.sh ├── BuildMacOS.sh ├── BuildX64.bat ├── BuildX86.bat ├── c_dd.cpp ├── c_dd.h ├── c_qd.cpp ├── c_qd.h ├── dd_const.cpp ├── dd_inline.h ├── dd_real.cpp ├── dd_real.h ├── inline.h ├── jni │ ├── Android.mk │ └── Application.mk ├── qd.pdf ├── qd_config.h ├── qd_const.cpp ├── qd_inline.h ├── qd_real.cpp ├── qd_real.h └── readme.txt ├── License.txt ├── Neslib.MultiPrecision.pas ├── Obj ├── dd32-accurate.obj ├── dd32.obj ├── dd64-accurate.obj ├── dd64.obj ├── qd32-accurate.obj ├── qd32.obj ├── qd64-accurate.obj └── qd64.obj ├── Samples └── Mandelbrot │ ├── AndroidManifest.template.xml │ ├── Entitlement.TemplateOSX.xml │ ├── Entitlement.TemplateiOS.xml │ ├── FMain.fmx │ ├── FMain.pas │ ├── LaunchScreen.TemplateiOS │ ├── Assets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── LaunchScreenBackgroundColor.colorset │ │ │ └── Contents.json │ │ └── LaunchScreenImage.imageset │ │ │ └── Contents.json │ └── LaunchScreen.storyboard │ ├── Mandelbrot.dpr │ ├── Mandelbrot.dproj │ ├── Mandelbrot.res │ ├── MandelbrotGenerator.pas │ ├── info.plist.TemplateOSX.xml │ ├── info.plist.TemplateiOS.xml │ ├── palette.raw │ ├── palette.rc │ └── palette.res ├── UnitTests ├── AndroidManifest.template.xml ├── Entitlement.TemplateOSX.xml ├── Entitlement.TemplateiOS.xml ├── FMain.fmx ├── FMain.pas ├── LaunchScreen.TemplateiOS │ ├── Assets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── LaunchScreenBackgroundColor.colorset │ │ │ └── Contents.json │ │ └── LaunchScreenImage.imageset │ │ │ └── Contents.json │ └── LaunchScreen.storyboard ├── MPTests.dpr ├── MPTests.dproj ├── MPTests.res ├── Tests │ ├── MultiPrecision.DoubleDouble.Tests.pas │ ├── MultiPrecision.QuadDouble.Tests.pas │ └── UnitTest.pas ├── info.plist.TemplateOSX.xml └── info.plist.TemplateiOS.xml ├── libmp-accurate_android32.a ├── libmp-accurate_android64.a ├── libmp_android32.a ├── libmp_android64.a ├── mp-accurate_ios64.a ├── mp-accurate_mac64.a ├── mp_ios64.a ├── mp_mac64.a ├── readme.md ├── readme1.png └── readme2.png /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # Pascal source files should use CRLF line endings to keep the Delphi IDE happy 4 | *.pas eol=crlf 5 | *.dpr eol=crlf 6 | *.dpk eol=crlf 7 | 8 | # iOS Entitlement Files MUST use LF endings or app won't run on device 9 | Entitlement.TemplateiOS.xml eol=lf 10 | 11 | # macOS shell scripts MUST use LF too 12 | *.sh eol=lf 13 | 14 | # customize language stats 15 | *.inc linguist-language=Pascal -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #OS X meta data 2 | ._* 3 | #ignore thumbnails created by windows 4 | Thumbs.db 5 | #ignore Delphi build directories 6 | Android/ 7 | iOSDevice/ 8 | iOSDevice32/ 9 | iOSDevice64/ 10 | iOSSimulator/ 11 | OSX32/ 12 | Win32/ 13 | Win64/ 14 | #ignore Delphi build files 15 | *.exe 16 | *.dcu 17 | *.map 18 | *.deployproj 19 | #ignore Delphi temp and backup files 20 | *.~* 21 | #ignore Delphi local files 22 | *.dsk 23 | *.dproj.local 24 | *.identcache 25 | *.groupproj.local 26 | #ignore temporary Android files 27 | *.d 28 | #ignore temporary help files 29 | HtmlHelp/ 30 | Html/ 31 | #ignore unit test results 32 | dunitx-results.xml 33 | #include C object files 34 | !Obj/ 35 | !Obj/*.obj -------------------------------------------------------------------------------- /C/BSD-LBNL-License.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/C/BSD-LBNL-License.doc -------------------------------------------------------------------------------- /C/BuildAndroid.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Set this variable to the location of ndk-build.cmd 4 | REM Tested with NDK version 17c. 5 | set NDK_BUILD=e:\android-ndk-r17c\ndk-build.cmd 6 | 7 | REM Name of generated static library 8 | set LIB32=obj\local\armeabi-v7a\libmp-android.a 9 | set LIB64=obj\local\arm64-v8a\libmp-android.a 10 | 11 | if not exist %NDK_BUILD% ( 12 | echo Cannot find ndk-build. Check the NDK_BUILD variable. 13 | exit /b 14 | ) 15 | 16 | REM Build "normal" version 17 | REM ====================== 18 | 19 | REM Run ndk-build to build static library 20 | call %NDK_BUILD% -B 21 | 22 | if not exist %LIB32% ( 23 | echo Cannot find static library %LIB32% 24 | exit /b 25 | ) 26 | 27 | if not exist %LIB64% ( 28 | echo Cannot find static library %LIB64% 29 | exit /b 30 | ) 31 | 32 | REM Copy static library to directory with Delphi source code 33 | copy %LIB32% ..\libmp_android32.a 34 | if %ERRORLEVEL% NEQ 0 ( 35 | echo Cannot copy static library. Make sure it is not write protected 36 | ) 37 | 38 | copy %LIB64% ..\libmp_android64.a 39 | if %ERRORLEVEL% NEQ 0 ( 40 | echo Cannot copy static library. Make sure it is not write protected 41 | ) 42 | 43 | REM Build "accurate" version 44 | REM ======================== 45 | 46 | REM Run ndk-build to build static library 47 | set MP_ACCURATE=true 48 | call %NDK_BUILD% -B 49 | set MP_ACCURATE= 50 | 51 | if not exist %LIB32% ( 52 | echo Cannot find static library %LIB32% 53 | exit /b 54 | ) 55 | 56 | REM Copy static library to directory with Delphi source code 57 | copy %LIB32% ..\libmp-accurate_android32.a 58 | if %ERRORLEVEL% NEQ 0 ( 59 | echo Cannot copy static library. Make sure it is not write protected 60 | ) 61 | 62 | copy %LIB64% ..\libmp-accurate_android64.a 63 | if %ERRORLEVEL% NEQ 0 ( 64 | echo Cannot copy static library. Make sure it is not write protected 65 | ) 66 | 67 | del %LIB32% 68 | del %LIB64% -------------------------------------------------------------------------------- /C/BuildIOS.sh: -------------------------------------------------------------------------------- 1 | PLATFORM="iPhoneOS" 2 | 3 | DEVELOPER_DIR=`xcode-select -print-path` 4 | if [ ! -d $DEVELOPER_DIR ]; then 5 | echo "Please set up Xcode correctly. '$DEVELOPER_DIR' is not a valid developer tools folder." 6 | exit 1 7 | fi 8 | 9 | SDK_ROOT=$DEVELOPER_DIR/Platforms/$PLATFORM.platform/Developer/SDKs/$PLATFORM.sdk 10 | if [ ! -d $SDK_ROOT ]; then 11 | echo "The iOS SDK was not found in $SDK_ROOT." 12 | exit 1 13 | fi 14 | 15 | rm *.o 16 | clang -c -DHP_ARM -O3 -arch arm64 -Wno-absolute-value -isysroot $SDK_ROOT -I . c_dd.cpp c_qd.cpp 17 | ar rcs ../mp_ios64.a *.o 18 | ranlib ../mp_ios64.a 19 | 20 | rm *.o 21 | clang -c -DHP_ARM -DHP_ACCURATE -O3 -arch arm64 -Wno-absolute-value -isysroot $SDK_ROOT -I . c_dd.cpp c_qd.cpp 22 | ar rcs ../mp-accurate_ios64.a *.o 23 | ranlib ../mp-accurate_ios64.a -------------------------------------------------------------------------------- /C/BuildMacOS.sh: -------------------------------------------------------------------------------- 1 | PLATFORM="MacOSX" 2 | 3 | DEVELOPER_DIR=`xcode-select -print-path` 4 | if [ ! -d $DEVELOPER_DIR ]; then 5 | echo "Please set up Xcode correctly. '$DEVELOPER_DIR' is not a valid developer tools folder." 6 | exit 1 7 | fi 8 | 9 | SDK_ROOT=$DEVELOPER_DIR/Platforms/$PLATFORM.platform/Developer/SDKs/$PLATFORM.sdk 10 | if [ ! -d $SDK_ROOT ]; then 11 | echo "The MacOSX SDK was not found in $SDK_ROOT." 12 | exit 1 13 | fi 14 | 15 | rm *.o 16 | clang -c -fPIC -O3 -Wno-absolute-value -isysroot $SDK_ROOT -I . -Xassembler -L c_dd.cpp c_qd.cpp 17 | ar rcs ../mp_mac64.a *.o 18 | ranlib ../mp_mac64.a 19 | 20 | rm *.o 21 | clang -c -fPIC -DHP_ACCURATE -O3 -Wno-absolute-value -isysroot $SDK_ROOT -I . -Xassembler -L c_dd.cpp c_qd.cpp 22 | ar rcs ../mp-accurate_mac64.a *.o 23 | ranlib ../mp-accurate_mac64.a 24 | 25 | rm *.o -------------------------------------------------------------------------------- /C/BuildX64.bat: -------------------------------------------------------------------------------- 1 | gcc -m64 -c -o ..\Obj\dd64.obj -I . -Wno-attributes -msse2 -O3 -Xassembler -L c_dd.cpp 2 | gcc -m64 -c -o ..\Obj\dd64-accurate.obj -I . -Wno-attributes -msse2 -DHP_ACCURATE -O3 -Xassembler -L c_dd.cpp 3 | 4 | gcc -m64 -c -o ..\Obj\qd64.obj -I . -Wno-attributes -msse2 -O3 -Xassembler -L c_qd.cpp 5 | gcc -m64 -c -o ..\Obj\qd64-accurate.obj -I . -Wno-attributes -msse2 -DHP_ACCURATE -O3 -Xassembler -L c_qd.cpp -------------------------------------------------------------------------------- /C/BuildX86.bat: -------------------------------------------------------------------------------- 1 | gcc -m32 -c -o ..\Obj\dd32.obj -I . -Wno-attributes -mfpmath=sse -msse2 -O3 -mincoming-stack-boundary=2 -Xassembler -L c_dd.cpp 2 | gcc -m32 -c -o ..\Obj\dd32-accurate.obj -I . -Wno-attributes -mfpmath=sse -msse2 -DHP_ACCURATE -O3 -mincoming-stack-boundary=2 -Xassembler -L c_dd.cpp 3 | 4 | gcc -m32 -c -o ..\Obj\qd32.obj -I . -Wno-attributes -mfpmath=sse -msse2 -O3 -mincoming-stack-boundary=2 -Xassembler -L c_qd.cpp 5 | gcc -m32 -c -o ..\Obj\qd32-accurate.obj -I . -Wno-attributes -mfpmath=sse -msse2 -DHP_ACCURATE -O3 -mincoming-stack-boundary=2 -Xassembler -L c_qd.cpp -------------------------------------------------------------------------------- /C/c_dd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * src/c_dd.cc 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains the C wrapper functions for double-double precision arithmetic. 11 | * This can be used from Fortran code. 12 | */ 13 | #include "qd_config.h" 14 | #include "dd_real.h" 15 | #include "c_dd.h" 16 | #include "dd_real.cpp" 17 | #include "dd_const.cpp" 18 | 19 | extern "C" { 20 | 21 | void c_dd_init() { 22 | qd::_d_nan = qd_nan(); 23 | qd::_d_inf = qd_inf(); 24 | 25 | dd_real::_2pi = dd_real(6.283185307179586232e+00, 26 | 2.449293598294706414e-16); 27 | dd_real::_pi = dd_real(3.141592653589793116e+00, 28 | 1.224646799147353207e-16); 29 | dd_real::_pi2 = dd_real(1.570796326794896558e+00, 30 | 6.123233995736766036e-17); 31 | dd_real::_pi4 = dd_real(7.853981633974482790e-01, 32 | 3.061616997868383018e-17); 33 | dd_real::_3pi4 = dd_real(2.356194490192344837e+00, 34 | 9.1848509936051484375e-17); 35 | dd_real::_e = dd_real(2.718281828459045091e+00, 36 | 1.445646891729250158e-16); 37 | dd_real::_log2 = dd_real(6.931471805599452862e-01, 38 | 2.319046813846299558e-17); 39 | dd_real::_log10 = dd_real(2.302585092994045901e+00, 40 | -2.170756223382249351e-16); 41 | dd_real::_nan = dd_real(qd::_d_nan, qd::_d_nan); 42 | dd_real::_inf = dd_real(qd::_d_inf, qd::_d_inf); 43 | 44 | dd_real::_max = 45 | dd_real(1.79769313486231570815e+308, 9.97920154767359795037e+291); 46 | dd_real::_safe_max = 47 | dd_real(1.7976931080746007281e+308, 9.97920154767359795037e+291); 48 | 49 | dd_real::_pi16 = dd_real(1.963495408493620697e-01, 50 | 7.654042494670957545e-18); 51 | } 52 | 53 | /* add */ 54 | void c_dd_add(const dd_real *a, const dd_real *b, dd_real *c) { 55 | *c = *a + *b; 56 | } 57 | void c_dd_add_d_d(const double *a, const double *b, dd_real *c) { 58 | *c = dd_real::add(*a, *b); 59 | } 60 | void c_dd_add_dd_d(const dd_real *a, const double *b, dd_real *c) { 61 | *c = *a + *b; 62 | } 63 | void c_dd_add_d_dd(const double *a, const dd_real *b, dd_real *c) { 64 | *c = *a + *b; 65 | } 66 | 67 | 68 | /* sub */ 69 | void c_dd_sub(const dd_real *a, const dd_real *b, dd_real *c) { 70 | *c = *a - *b; 71 | } 72 | void c_dd_sub_d_d(const double *a, const double *b, dd_real *c) { 73 | *c = dd_real::sub(*a, *b); 74 | } 75 | void c_dd_sub_dd_d(const dd_real *a, const double *b, dd_real *c) { 76 | *c = *a - *b; 77 | } 78 | void c_dd_sub_d_dd(const double *a, const dd_real *b, dd_real *c) { 79 | *c = *a - *b; 80 | } 81 | 82 | 83 | /* mul */ 84 | void c_dd_mul(const dd_real *a, const dd_real *b, dd_real *c) { 85 | *c = *a * *b; 86 | } 87 | void c_dd_mul_d_d(const double *a, const double *b, dd_real *c) { 88 | *c = dd_real::mul(*a, *b); 89 | } 90 | void c_dd_mul_dd_d(const dd_real *a, const double *b, dd_real *c) { 91 | *c = *a * *b; 92 | } 93 | void c_dd_mul_d_dd(const double *a, const dd_real *b, dd_real *c) { 94 | *c = *a * *b; 95 | } 96 | void c_dd_mul_pot(const dd_real *a, const double *b, dd_real *c) { 97 | *c = mul_pwr2(*a, *b); 98 | } 99 | 100 | /* div */ 101 | void c_dd_div(const dd_real *a, const dd_real *b, dd_real *c) { 102 | *c = *a / *b; 103 | } 104 | void c_dd_div_d_d(const double *a, const double *b, dd_real *c) { 105 | *c = dd_real::div(*a, *b); 106 | } 107 | void c_dd_div_dd_d(const dd_real *a, const double *b, dd_real *c) { 108 | *c = *a / *b; 109 | } 110 | void c_dd_div_d_dd(const double *a, const dd_real *b, dd_real *c) { 111 | *c = *a / *b; 112 | } 113 | 114 | void c_dd_rem(const dd_real *a, const dd_real *b, dd_real *c) { 115 | *c = drem(*a, *b); 116 | } 117 | void c_dd_divrem(const dd_real *a, const dd_real *b, dd_real_pair *c) { 118 | c->v2 = divrem(*a, *b, c->v1); 119 | } 120 | void c_dd_fmod(const dd_real *a, const dd_real *b, dd_real *c) { 121 | *c = fmod(*a, *b); 122 | } 123 | 124 | 125 | void c_dd_sqrt(const dd_real *a, dd_real *b) { 126 | *b = sqrt(*a); 127 | } 128 | void c_dd_sqrt_d(const double *a, dd_real *b) { 129 | *b = sqrt(*a); 130 | } 131 | void c_dd_sqr(const dd_real *a, dd_real *b) { 132 | *b = sqr(*a); 133 | } 134 | void c_dd_sqr_d(const double *a, dd_real *b) { 135 | *b = sqr(*a); 136 | } 137 | 138 | void c_dd_abs(const dd_real *a, dd_real *b) { 139 | *b = abs(*a); 140 | } 141 | 142 | void c_dd_npwr(const dd_real *a, int n, dd_real *b) { 143 | *b = npwr(*a, n); 144 | } 145 | void c_dd_pow(const dd_real *a, const dd_real *b, dd_real *c) { 146 | *c = pow(*a, *b); 147 | } 148 | 149 | void c_dd_nroot(const dd_real *a, int n, dd_real *b) { 150 | *b = nroot(*a, n); 151 | } 152 | 153 | void c_dd_ldexp(const dd_real *a, int b, dd_real *c) { 154 | *c = ldexp(*a, b); 155 | } 156 | 157 | void c_dd_nint(const dd_real *a, dd_real *b) { 158 | *b = nint(*a); 159 | } 160 | void c_dd_aint(const dd_real *a, dd_real *b) { 161 | *b = aint(*a); 162 | } 163 | void c_dd_floor(const dd_real *a, dd_real *b) { 164 | *b = floor(*a); 165 | } 166 | void c_dd_ceil(const dd_real *a, dd_real *b) { 167 | *b = ceil(*a); 168 | } 169 | 170 | void c_dd_log(const dd_real *a, dd_real *b) { 171 | *b = log(*a); 172 | } 173 | void c_dd_log10(const dd_real *a, dd_real *b) { 174 | *b = log10(*a); 175 | } 176 | void c_dd_exp(const dd_real *a, dd_real *b) { 177 | *b = exp(*a); 178 | } 179 | 180 | void c_dd_sin(const dd_real *a, dd_real *b) { 181 | *b = sin(*a); 182 | } 183 | void c_dd_cos(const dd_real *a, dd_real *b) { 184 | *b = cos(*a); 185 | } 186 | void c_dd_tan(const dd_real *a, dd_real *b) { 187 | *b = tan(*a); 188 | } 189 | 190 | void c_dd_asin(const dd_real *a, dd_real *b) { 191 | *b = asin(*a); 192 | } 193 | void c_dd_acos(const dd_real *a, dd_real *b) { 194 | *b = acos(*a); 195 | } 196 | void c_dd_atan(const dd_real *a, dd_real *b) { 197 | *b = atan(*a); 198 | } 199 | 200 | void c_dd_atan2(const dd_real *a, const dd_real *b, dd_real *c) { 201 | *c = atan2(*a, *b); 202 | } 203 | 204 | void c_dd_sinh(const dd_real *a, dd_real *b) { 205 | *b = sinh(*a); 206 | } 207 | void c_dd_cosh(const dd_real *a, dd_real *b) { 208 | *b = cosh(*a); 209 | } 210 | void c_dd_tanh(const dd_real *a, dd_real *b) { 211 | *b = tanh(*a); 212 | } 213 | 214 | void c_dd_asinh(const dd_real *a, dd_real *b) { 215 | *b = asinh(*a); 216 | } 217 | void c_dd_acosh(const dd_real *a, dd_real *b) { 218 | *b = acosh(*a); 219 | } 220 | void c_dd_atanh(const dd_real *a, dd_real *b) { 221 | *b = atanh(*a); 222 | } 223 | 224 | void c_dd_sincos(const dd_real *a, dd_real *s, dd_real *c) { 225 | sincos(*a, *s, *c); 226 | } 227 | 228 | void c_dd_sincosh(const dd_real *a, dd_real *s, dd_real *c) { 229 | sincosh(*a, *s, *c); 230 | } 231 | 232 | void c_dd_neg(const dd_real *a, dd_real *b) { 233 | b->x[0] = -a->x[0]; 234 | b->x[1] = -a->x[1]; 235 | } 236 | 237 | void c_dd_inv(const dd_real *a, dd_real *b) { 238 | *b = inv(*a); 239 | } 240 | 241 | int c_dd_comp(const dd_real *a, const dd_real *b) { 242 | if (*a < *b) 243 | return -1; 244 | 245 | if (*a > *b) 246 | return 1; 247 | 248 | return 0; 249 | } 250 | 251 | int c_dd_comp_dd_d(const dd_real *a, const double *b) { 252 | dd_real bb(*b); 253 | if (*a < bb) 254 | return -1; 255 | 256 | if (*a > bb) 257 | return 1; 258 | 259 | return 0; 260 | } 261 | 262 | int c_dd_comp_d_dd(const double *a, const dd_real *b) { 263 | dd_real aa(*a); 264 | if (aa < *b) 265 | return -1; 266 | 267 | if (aa > *b) 268 | return 1; 269 | 270 | return 0; 271 | } 272 | 273 | } -------------------------------------------------------------------------------- /C/c_dd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/c_dd.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains C wrapper function prototypes for double-double precision 11 | * arithmetic. This can also be used from fortran code. 12 | */ 13 | #ifndef _QD_C_DD_H 14 | #define _QD_C_DD_H 15 | 16 | #include "qd_config.h" 17 | #include "dd_real.h" 18 | 19 | struct dd_real_pair { 20 | dd_real v1; 21 | dd_real v2; 22 | }; 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | QD_API void c_dd_init(); 29 | 30 | /* add */ 31 | QD_API void c_dd_add(const dd_real *a, const dd_real *b, dd_real *c); 32 | QD_API void c_dd_add_d_d(const double *a, const double *b, dd_real *c); 33 | QD_API void c_dd_add_d_dd(const double *a, const dd_real *b, dd_real *c); 34 | QD_API void c_dd_add_dd_d(const dd_real *a, const double *b, dd_real *c); 35 | 36 | /* sub */ 37 | QD_API void c_dd_sub(const dd_real *a, const dd_real *b, dd_real *c); 38 | QD_API void c_dd_sub_d_d(const double *a, const double *b, dd_real *c); 39 | QD_API void c_dd_sub_d_dd(const double *a, const dd_real *b, dd_real *c); 40 | QD_API void c_dd_sub_dd_d(const dd_real *a, const double *b, dd_real *c); 41 | 42 | /* mul */ 43 | QD_API void c_dd_mul(const dd_real *a, const dd_real *b, dd_real *c); 44 | QD_API void c_dd_mul_d_d(const double *a, const double *b, dd_real *c); 45 | QD_API void c_dd_mul_d_dd(const double *a, const dd_real *b, dd_real *c); 46 | QD_API void c_dd_mul_dd_d(const dd_real *a, const double *b, dd_real *c); 47 | QD_API void c_dd_mul_pot(const dd_real *a, const double *b, dd_real *c); 48 | 49 | /* div */ 50 | QD_API void c_dd_div(const dd_real *a, const dd_real *b, dd_real *c); 51 | QD_API void c_dd_div_d_d(const double *a, const double *b, dd_real *c); 52 | QD_API void c_dd_div_d_dd(const double *a, const dd_real *b, dd_real *c); 53 | QD_API void c_dd_div_dd_d(const dd_real *a, const double *b, dd_real *c); 54 | 55 | QD_API void c_dd_rem(const dd_real *a, const dd_real *b, dd_real *c); 56 | QD_API void c_dd_divrem(const dd_real *a, const dd_real *b, dd_real_pair *c); 57 | QD_API void c_dd_fmod(const dd_real *a, const dd_real *b, dd_real *c); 58 | 59 | QD_API void c_dd_sqrt(const dd_real *a, dd_real *b); 60 | QD_API void c_dd_sqrt_d(const double *a, dd_real *b); 61 | QD_API void c_dd_sqr(const dd_real *a, dd_real *b); 62 | QD_API void c_dd_sqr_d(const double *a, dd_real *b); 63 | 64 | QD_API void c_dd_abs(const dd_real *a, dd_real *b); 65 | 66 | QD_API void c_dd_npwr(const dd_real *a, int b, dd_real *c); 67 | QD_API void c_dd_pow(const dd_real *a, const dd_real *b, dd_real *c); 68 | QD_API void c_dd_nroot(const dd_real *a, int b, dd_real *c); 69 | QD_API void c_dd_ldexp(const dd_real *a, int b, dd_real *c); 70 | 71 | QD_API void c_dd_nint(const dd_real *a, dd_real *b); 72 | QD_API void c_dd_aint(const dd_real *a, dd_real *b); 73 | QD_API void c_dd_floor(const dd_real *a, dd_real *b); 74 | QD_API void c_dd_ceil(const dd_real *a, dd_real *b); 75 | 76 | QD_API void c_dd_exp(const dd_real *a, dd_real *b); 77 | QD_API void c_dd_log(const dd_real *a, dd_real *b); 78 | QD_API void c_dd_log10(const dd_real *a, dd_real *b); 79 | 80 | QD_API void c_dd_sin(const dd_real *a, dd_real *b); 81 | QD_API void c_dd_cos(const dd_real *a, dd_real *b); 82 | QD_API void c_dd_tan(const dd_real *a, dd_real *b); 83 | 84 | QD_API void c_dd_asin(const dd_real *a, dd_real *b); 85 | QD_API void c_dd_acos(const dd_real *a, dd_real *b); 86 | QD_API void c_dd_atan(const dd_real *a, dd_real *b); 87 | QD_API void c_dd_atan2(const dd_real *a, const dd_real *b, dd_real *c); 88 | 89 | QD_API void c_dd_sinh(const dd_real *a, dd_real *b); 90 | QD_API void c_dd_cosh(const dd_real *a, dd_real *b); 91 | QD_API void c_dd_tanh(const dd_real *a, dd_real *b); 92 | 93 | QD_API void c_dd_asinh(const dd_real *a, dd_real *b); 94 | QD_API void c_dd_acosh(const dd_real *a, dd_real *b); 95 | QD_API void c_dd_atanh(const dd_real *a, dd_real *b); 96 | 97 | QD_API void c_dd_sincos(const dd_real *a, dd_real *s, dd_real *c); 98 | QD_API void c_dd_sincosh(const dd_real *a, dd_real *s, dd_real *c); 99 | 100 | QD_API void c_dd_neg(const dd_real *a, dd_real *b); 101 | QD_API void c_dd_inv(const dd_real *a, dd_real *b); 102 | QD_API int c_dd_comp(const dd_real *a, const dd_real *b); 103 | QD_API int c_dd_comp_dd_d(const dd_real *a, const double *b); 104 | QD_API int c_dd_comp_d_dd(const double *a, const dd_real *b); 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | #endif /* _QD_C_DD_H */ 111 | -------------------------------------------------------------------------------- /C/c_qd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * src/c_qd.cc 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains C wrapper function for quad-double precision arithmetic. 11 | * This can be used from fortran code. 12 | */ 13 | #include 14 | 15 | #include "qd_config.h" 16 | #include "qd_real.h" 17 | #include "c_qd.h" 18 | #include "qd_real.cpp" 19 | #include "qd_const.cpp" 20 | 21 | extern "C" { 22 | 23 | void c_qd_init() { 24 | qd::_d_nan = qd_nan(); 25 | qd::_d_inf = qd_inf(); 26 | 27 | qd_real::_2pi = qd_real(6.283185307179586232e+00, 28 | 2.449293598294706414e-16, 29 | -5.989539619436679332e-33, 30 | 2.224908441726730563e-49); 31 | qd_real::_pi = qd_real(3.141592653589793116e+00, 32 | 1.224646799147353207e-16, 33 | -2.994769809718339666e-33, 34 | 1.112454220863365282e-49); 35 | qd_real::_pi2 = qd_real(1.570796326794896558e+00, 36 | 6.123233995736766036e-17, 37 | -1.497384904859169833e-33, 38 | 5.562271104316826408e-50); 39 | qd_real::_pi4 = qd_real(7.853981633974482790e-01, 40 | 3.061616997868383018e-17, 41 | -7.486924524295849165e-34, 42 | 2.781135552158413204e-50); 43 | qd_real::_3pi4 = qd_real(2.356194490192344837e+00, 44 | 9.1848509936051484375e-17, 45 | 3.9168984647504003225e-33, 46 | -2.5867981632704860386e-49); 47 | qd_real::_e = qd_real(2.718281828459045091e+00, 48 | 1.445646891729250158e-16, 49 | -2.127717108038176765e-33, 50 | 1.515630159841218954e-49); 51 | qd_real::_log2 = qd_real(6.931471805599452862e-01, 52 | 2.319046813846299558e-17, 53 | 5.707708438416212066e-34, 54 | -3.582432210601811423e-50); 55 | qd_real::_log10 = qd_real(2.302585092994045901e+00, 56 | -2.170756223382249351e-16, 57 | -9.984262454465776570e-33, 58 | -4.023357454450206379e-49); 59 | qd_real::_nan = qd_real(qd::_d_nan, qd::_d_nan, 60 | qd::_d_nan, qd::_d_nan); 61 | qd_real::_inf = qd_real(qd::_d_inf, qd::_d_inf, 62 | qd::_d_inf, qd::_d_inf); 63 | 64 | qd_real::_max = qd_real( 65 | 1.79769313486231570815e+308, 9.97920154767359795037e+291, 66 | 5.53956966280111259858e+275, 3.07507889307840487279e+259); 67 | qd_real::_safe_max = qd_real( 68 | 1.7976931080746007281e+308, 9.97920154767359795037e+291, 69 | 5.53956966280111259858e+275, 3.07507889307840487279e+259); 70 | 71 | qd_real::_pi1024 = qd_real( 72 | 3.067961575771282340e-03, 1.195944139792337116e-19, 73 | -2.924579892303066080e-36, 1.086381075061880158e-52); 74 | 75 | } 76 | 77 | 78 | /* add */ 79 | void c_qd_add(const qd_real *a, const qd_real *b, qd_real *c) { 80 | *c = *a + *b; 81 | } 82 | void c_qd_add_qd_dd(const qd_real *a, const dd_real *b, qd_real *c) { 83 | *c = *a + *b; 84 | } 85 | void c_qd_add_dd_qd(const dd_real *a, const qd_real *b, qd_real *c) { 86 | *c = *a + *b; 87 | } 88 | void c_qd_add_qd_d(const qd_real *a, const double *b, qd_real *c) { 89 | *c = *a + *b; 90 | } 91 | void c_qd_add_d_qd(const double *a, const qd_real *b, qd_real *c) { 92 | *c = *a + *b; 93 | } 94 | 95 | 96 | 97 | /* sub */ 98 | void c_qd_sub(const qd_real *a, const qd_real *b, qd_real *c) { 99 | *c = *a - *b; 100 | } 101 | void c_qd_sub_qd_dd(const qd_real *a, const dd_real *b, qd_real *c) { 102 | *c = *a - *b; 103 | } 104 | void c_qd_sub_dd_qd(const dd_real *a, const qd_real *b, qd_real *c) { 105 | *c = *a - *b; 106 | } 107 | void c_qd_sub_qd_d(const qd_real *a, const double *b, qd_real *c) { 108 | *c = *a - *b; 109 | } 110 | void c_qd_sub_d_qd(const double *a, const qd_real *b, qd_real *c) { 111 | *c = *a - *b; 112 | } 113 | 114 | 115 | 116 | /* mul */ 117 | void c_qd_mul(const qd_real *a, const qd_real *b, qd_real *c) { 118 | *c = *a * *b; 119 | } 120 | void c_qd_mul_qd_dd(const qd_real *a, const dd_real *b, qd_real *c) { 121 | *c = *a * *b; 122 | } 123 | void c_qd_mul_dd_qd(const dd_real *a, const qd_real *b, qd_real *c) { 124 | *c = *a * *b; 125 | } 126 | void c_qd_mul_qd_d(const qd_real *a, const double *b, qd_real *c) { 127 | *c = *a * *b; 128 | } 129 | void c_qd_mul_d_qd(const double *a, const qd_real *b, qd_real *c) { 130 | *c = *a * *b; 131 | } 132 | 133 | void c_qd_mul_pot(const qd_real *a, const double *b, qd_real *c) { 134 | *c = mul_pwr2(*a, *b); 135 | } 136 | 137 | 138 | 139 | /* div */ 140 | void c_qd_div(const qd_real *a, const qd_real *b, qd_real *c) { 141 | *c = *a / *b; 142 | } 143 | void c_qd_div_qd_dd(const qd_real *a, const dd_real *b, qd_real *c) { 144 | *c = *a / *b; 145 | } 146 | void c_qd_div_dd_qd(const dd_real *a, const qd_real *b, qd_real *c) { 147 | *c = *a / *b; 148 | } 149 | void c_qd_div_qd_d(const qd_real *a, const double *b, qd_real *c) { 150 | *c = *a / *b; 151 | } 152 | void c_qd_div_d_qd(const double *a, const qd_real *b, qd_real *c) { 153 | *c = *a / *b; 154 | } 155 | 156 | void c_qd_rem(const qd_real *a, const qd_real *b, qd_real *c) { 157 | *c = drem(*a, *b); 158 | } 159 | void c_qd_divrem(const qd_real *a, const qd_real *b, qd_real_pair *c) { 160 | c->v2 = divrem(*a, *b, c->v1); 161 | } 162 | void c_qd_fmod(const qd_real *a, const qd_real *b, qd_real *c) { 163 | *c = fmod(*a, *b); 164 | } 165 | 166 | 167 | 168 | /* selfadd */ 169 | void c_qd_selfadd(const qd_real *a, qd_real *b) { 170 | *b += *a; 171 | } 172 | void c_qd_selfadd_dd(const dd_real *a, qd_real *b) { 173 | *b += *a; 174 | } 175 | void c_qd_selfadd_d(const double *a, qd_real *b) { 176 | *b += *a; 177 | } 178 | 179 | 180 | 181 | /* selfsub */ 182 | void c_qd_selfsub(const qd_real *a, qd_real *b) { 183 | *b -= *a; 184 | } 185 | void c_qd_selfsub_dd(const dd_real *a, qd_real *b) { 186 | *b -= *a; 187 | } 188 | void c_qd_selfsub_d(const double *a, qd_real *b) { 189 | *b -= *a; 190 | } 191 | 192 | 193 | 194 | /* selfmul */ 195 | void c_qd_selfmul(const qd_real *a, qd_real *b) { 196 | *b *= *a; 197 | } 198 | void c_qd_selfmul_dd(const dd_real *a, qd_real *b) { 199 | *b *= *a; 200 | } 201 | void c_qd_selfmul_d(const double *a, qd_real *b) { 202 | *b *= *a; 203 | } 204 | 205 | 206 | 207 | /* selfdiv */ 208 | void c_qd_selfdiv(const qd_real *a, qd_real *b) { 209 | *b /= *a; 210 | } 211 | void c_qd_selfdiv_dd(const dd_real *a, qd_real *b) { 212 | *b /= *a; 213 | } 214 | void c_qd_selfdiv_d(const double *a, qd_real *b) { 215 | *b /= *a; 216 | } 217 | 218 | 219 | 220 | /* copy */ 221 | void c_qd_copy(const qd_real *a, qd_real *b) { 222 | b->x[0] = a->x[0]; 223 | b->x[1] = a->x[1]; 224 | b->x[2] = a->x[2]; 225 | b->x[3] = a->x[3]; 226 | } 227 | void c_qd_copy_dd(const dd_real *a, qd_real *b) { 228 | b->x[0] = a->x[0]; 229 | b->x[1] = a->x[1]; 230 | b->x[2] = 0.0; 231 | b->x[3] = 0.0; 232 | } 233 | void c_qd_copy_d(const double *a, qd_real *b) { 234 | b->x[0] = *a; 235 | b->x[1] = 0.0; 236 | b->x[2] = 0.0; 237 | b->x[3] = 0.0; 238 | } 239 | 240 | 241 | void c_qd_sqrt(const qd_real *a, qd_real *b) { 242 | *b = sqrt(*a); 243 | } 244 | void c_qd_sqr(const qd_real *a, qd_real *b) { 245 | *b = sqr(*a); 246 | } 247 | 248 | void c_qd_abs(const qd_real *a, qd_real *b) { 249 | *b = abs(*a); 250 | } 251 | 252 | void c_qd_npwr(const qd_real *a, int n, qd_real *b) { 253 | *b = npwr(*a, n); 254 | } 255 | 256 | void c_qd_pow(const qd_real *a, const qd_real *b, qd_real *c) { 257 | *c = pow(*a, *b); 258 | } 259 | 260 | void c_qd_nroot(const qd_real *a, int n, qd_real *b) { 261 | *b = nroot(*a, n); 262 | } 263 | 264 | void c_qd_ldexp(const qd_real *a, int b, qd_real *c) { 265 | *c = ldexp(*a, b); 266 | } 267 | 268 | void c_qd_nint(const qd_real *a, qd_real *b) { 269 | *b = nint(*a); 270 | } 271 | void c_qd_aint(const qd_real *a, qd_real *b) { 272 | *b = aint(*a); 273 | } 274 | void c_qd_floor(const qd_real *a, qd_real *b) { 275 | *b = floor(*a); 276 | } 277 | void c_qd_ceil(const qd_real *a, qd_real *b) { 278 | *b = ceil(*a); 279 | } 280 | 281 | void c_qd_log(const qd_real *a, qd_real *b) { 282 | *b = log(*a); 283 | } 284 | void c_qd_log10(const qd_real *a, qd_real *b) { 285 | *b = log10(*a); 286 | } 287 | void c_qd_exp(const qd_real *a, qd_real *b) { 288 | *b = exp(*a); 289 | } 290 | 291 | void c_qd_sin(const qd_real *a, qd_real *b) { 292 | *b = sin(*a); 293 | } 294 | void c_qd_cos(const qd_real *a, qd_real *b) { 295 | *b = cos(*a); 296 | } 297 | void c_qd_tan(const qd_real *a, qd_real *b) { 298 | *b = tan(*a); 299 | } 300 | 301 | void c_qd_asin(const qd_real *a, qd_real *b) { 302 | *b = asin(*a); 303 | } 304 | void c_qd_acos(const qd_real *a, qd_real *b) { 305 | *b = acos(*a); 306 | } 307 | void c_qd_atan(const qd_real *a, qd_real *b) { 308 | *b = atan(*a); 309 | } 310 | 311 | void c_qd_atan2(const qd_real *a, const qd_real *b, qd_real *c) { 312 | *c = atan2(*a, *b); 313 | } 314 | 315 | void c_qd_sinh(const qd_real *a, qd_real *b) { 316 | *b = sinh(*a); 317 | } 318 | void c_qd_cosh(const qd_real *a, qd_real *b) { 319 | *b = cosh(*a); 320 | } 321 | void c_qd_tanh(const qd_real *a, qd_real *b) { 322 | *b = tanh(*a); 323 | } 324 | 325 | void c_qd_asinh(const qd_real *a, qd_real *b) { 326 | *b = asinh(*a); 327 | } 328 | void c_qd_acosh(const qd_real *a, qd_real *b) { 329 | *b = acosh(*a); 330 | } 331 | void c_qd_atanh(const qd_real *a, qd_real *b) { 332 | *b = atanh(*a); 333 | } 334 | 335 | void c_qd_sincos(const qd_real *a, qd_real *s, qd_real *c) { 336 | sincos(*a, *s, *c); 337 | } 338 | 339 | void c_qd_sincosh(const qd_real *a, qd_real *s, qd_real *c) { 340 | sincosh(*a, *s, *c); 341 | } 342 | 343 | void c_qd_neg(const qd_real *a, qd_real *b) { 344 | b->x[0] = -a->x[0]; 345 | b->x[1] = -a->x[1]; 346 | b->x[2] = -a->x[2]; 347 | b->x[3] = -a->x[3]; 348 | } 349 | 350 | void c_qd_inv(const qd_real *a, qd_real *b) { 351 | *b = inv(*a); 352 | } 353 | 354 | int c_qd_comp(const qd_real *a, const qd_real *b) { 355 | if (*a < *b) 356 | return -1; 357 | 358 | if (*a > *b) 359 | return 1; 360 | 361 | return 0; 362 | } 363 | 364 | int c_qd_comp_qd_d(const qd_real *a, const double *b) { 365 | qd_real bb(*b); 366 | if (*a < bb) 367 | return -1; 368 | 369 | if (*a > bb) 370 | return 1; 371 | 372 | return 0; 373 | } 374 | 375 | int c_qd_comp_d_qd(const double *a, const qd_real *b) { 376 | qd_real aa(*a); 377 | if (aa < *b) 378 | return -1; 379 | 380 | if (aa > *b) 381 | return 1; 382 | 383 | return 0; 384 | } 385 | 386 | } -------------------------------------------------------------------------------- /C/c_qd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/c_qd.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains C wrapper function prototypes for quad-double precision 11 | * arithmetic. This can also be used from fortran code. 12 | */ 13 | #ifndef _QD_C_QD_H 14 | #define _QD_C_QD_H 15 | 16 | #include "c_dd.h" 17 | #include "qd_config.h" 18 | #include "dd_real.h" 19 | #include "qd_real.h" 20 | 21 | struct qd_real_pair { 22 | qd_real v1; 23 | qd_real v2; 24 | }; 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | QD_API void c_qd_init(); 31 | 32 | /* add */ 33 | QD_API void c_qd_add(const qd_real *a, const qd_real *b, qd_real *c); 34 | QD_API void c_qd_add_dd_qd(const dd_real *a, const qd_real *b, qd_real *c); 35 | QD_API void c_qd_add_qd_dd(const qd_real *a, const dd_real *b, qd_real *c); 36 | QD_API void c_qd_add_d_qd(const double *a, const qd_real *b, qd_real *c); 37 | QD_API void c_qd_add_qd_d(const qd_real *a, const double *b, qd_real *c); 38 | QD_API void c_qd_selfadd(const qd_real *a, qd_real *b); 39 | QD_API void c_qd_selfadd_dd(const dd_real *a, qd_real *b); 40 | QD_API void c_qd_selfadd_d(const double *a, qd_real *b); 41 | 42 | /* sub */ 43 | QD_API void c_qd_sub(const qd_real *a, const qd_real *b, qd_real *c); 44 | QD_API void c_qd_sub_dd_qd(const dd_real *a, const qd_real *b, qd_real *c); 45 | QD_API void c_qd_sub_qd_dd(const qd_real *a, const dd_real *b, qd_real *c); 46 | QD_API void c_qd_sub_d_qd(const double *a, const qd_real *b, qd_real *c); 47 | QD_API void c_qd_sub_qd_d(const qd_real *a, const double *b, qd_real *c); 48 | QD_API void c_qd_selfsub(const qd_real *a, qd_real *b); 49 | QD_API void c_qd_selfsub_dd(const dd_real *a, qd_real *b); 50 | QD_API void c_qd_selfsub_d(const double *a, qd_real *b); 51 | 52 | /* mul */ 53 | QD_API void c_qd_mul(const qd_real *a, const qd_real *b, qd_real *c); 54 | QD_API void c_qd_mul_dd_qd(const dd_real *a, const qd_real *b, qd_real *c); 55 | QD_API void c_qd_mul_qd_dd(const qd_real *a, const dd_real *b, qd_real *c); 56 | QD_API void c_qd_mul_d_qd(const double *a, const qd_real *b, qd_real *c); 57 | QD_API void c_qd_mul_qd_d(const qd_real *a, const double *b, qd_real *c); 58 | QD_API void c_qd_selfmul(const qd_real *a, qd_real *b); 59 | QD_API void c_qd_selfmul_dd(const dd_real *a, qd_real *b); 60 | QD_API void c_qd_selfmul_d(const double *a, qd_real *b); 61 | QD_API void c_qd_mul_pot(const qd_real *a, const double *b, qd_real *c); 62 | 63 | /* div */ 64 | QD_API void c_qd_div(const qd_real *a, const qd_real *b, qd_real *c); 65 | QD_API void c_qd_div_dd_qd(const dd_real *a, const qd_real *b, qd_real *c); 66 | QD_API void c_qd_div_qd_dd(const qd_real *a, const dd_real *b, qd_real *c); 67 | QD_API void c_qd_div_d_qd(const double *a, const qd_real *b, qd_real *c); 68 | QD_API void c_qd_div_qd_d(const qd_real *a, const double *b, qd_real *c); 69 | QD_API void c_qd_selfdiv(const qd_real *a, qd_real *b); 70 | QD_API void c_qd_selfdiv_dd(const dd_real *a, qd_real *b); 71 | QD_API void c_qd_selfdiv_d(const double *a, qd_real *b); 72 | 73 | QD_API void c_qd_rem(const qd_real *a, const qd_real *b, qd_real *c); 74 | QD_API void c_qd_divrem(const qd_real *a, const qd_real *b, qd_real_pair *c); 75 | QD_API void c_qd_fmod(const qd_real *a, const qd_real *b, qd_real *c); 76 | 77 | /* copy */ 78 | QD_API void c_qd_copy(const qd_real *a, qd_real *b); 79 | QD_API void c_qd_copy_dd(const dd_real *a, qd_real *b); 80 | QD_API void c_qd_copy_d(const double *a, qd_real *b); 81 | 82 | QD_API void c_qd_sqrt(const qd_real *a, qd_real *b); 83 | QD_API void c_qd_sqr(const qd_real *a, qd_real *b); 84 | 85 | QD_API void c_qd_abs(const qd_real *a, qd_real *b); 86 | 87 | QD_API void c_qd_npwr(const qd_real *a, int b, qd_real *c); 88 | QD_API void c_qd_pow(const qd_real *a, const qd_real *b, qd_real *c); 89 | QD_API void c_qd_nroot(const qd_real *a, int b, qd_real *c); 90 | QD_API void c_qd_ldexp(const qd_real *a, int b, qd_real *c); 91 | 92 | QD_API void c_qd_nint(const qd_real *a, qd_real *b); 93 | QD_API void c_qd_aint(const qd_real *a, qd_real *b); 94 | QD_API void c_qd_floor(const qd_real *a, qd_real *b); 95 | QD_API void c_qd_ceil(const qd_real *a, qd_real *b); 96 | 97 | QD_API void c_qd_exp(const qd_real *a, qd_real *b); 98 | QD_API void c_qd_log(const qd_real *a, qd_real *b); 99 | QD_API void c_qd_log10(const qd_real *a, qd_real *b); 100 | 101 | QD_API void c_qd_sin(const qd_real *a, qd_real *b); 102 | QD_API void c_qd_cos(const qd_real *a, qd_real *b); 103 | QD_API void c_qd_tan(const qd_real *a, qd_real *b); 104 | 105 | QD_API void c_qd_asin(const qd_real *a, qd_real *b); 106 | QD_API void c_qd_acos(const qd_real *a, qd_real *b); 107 | QD_API void c_qd_atan(const qd_real *a, qd_real *b); 108 | QD_API void c_qd_atan2(const qd_real *a, const qd_real *b, qd_real *c); 109 | 110 | QD_API void c_qd_sinh(const qd_real *a, qd_real *b); 111 | QD_API void c_qd_cosh(const qd_real *a, qd_real *b); 112 | QD_API void c_qd_tanh(const qd_real *a, qd_real *b); 113 | 114 | QD_API void c_qd_asinh(const qd_real *a, qd_real *b); 115 | QD_API void c_qd_acosh(const qd_real *a, qd_real *b); 116 | QD_API void c_qd_atanh(const qd_real *a, qd_real *b); 117 | 118 | QD_API void c_qd_sincos(const qd_real *a, qd_real *s, qd_real *c); 119 | QD_API void c_qd_sincosh(const qd_real *a, qd_real *s, qd_real *c); 120 | 121 | QD_API void c_qd_neg(const qd_real *a, qd_real *b); 122 | QD_API void c_qd_inv(const qd_real *a, qd_real *b); 123 | QD_API int c_qd_comp(const qd_real *a, const qd_real *b); 124 | QD_API int c_qd_comp_qd_d(const qd_real *a, const double *b); 125 | QD_API int c_qd_comp_d_qd(const double *a, const qd_real *b); 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* _QD_C_QD_H */ 131 | -------------------------------------------------------------------------------- /C/dd_const.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * src/dd_const.cc 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2007 9 | */ 10 | #include "qd_config.h" 11 | #include "dd_real.h" 12 | 13 | dd_real dd_real::_2pi; 14 | dd_real dd_real::_pi; 15 | dd_real dd_real::_pi2; 16 | dd_real dd_real::_pi4; 17 | dd_real dd_real::_3pi4; 18 | dd_real dd_real::_e; 19 | dd_real dd_real::_log2; 20 | dd_real dd_real::_log10; 21 | dd_real dd_real::_nan; 22 | dd_real dd_real::_inf; 23 | dd_real dd_real::_max; 24 | dd_real dd_real::_safe_max; 25 | dd_real dd_real::_pi16; 26 | const double dd_real::_eps = 4.93038065763132e-32; // 2^-104 27 | const double dd_real::_min_normalized = 2.0041683600089728e-292; // = 2^(-1022 + 53) 28 | const int dd_real::_ndigits = 31; 29 | 30 | 31 | -------------------------------------------------------------------------------- /C/dd_inline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/dd_inline.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains small functions (suitable for inlining) in the double-double 11 | * arithmetic package. 12 | */ 13 | #ifndef _QD_DD_INLINE_H 14 | #define _QD_DD_INLINE_H 15 | 16 | #include "inline.h" 17 | 18 | #ifndef QD_INLINE 19 | #define inline 20 | #endif 21 | 22 | 23 | /*********** Additions ************/ 24 | /* double-double = double + double */ 25 | inline dd_real dd_real::add(double a, double b) { 26 | double s, e; 27 | s = qd::two_sum(a, b, e); 28 | return dd_real(s, e); 29 | } 30 | 31 | /* double-double + double */ 32 | inline dd_real operator+(const dd_real &a, double b) { 33 | double s1, s2; 34 | s1 = qd::two_sum(a.x[0], b, s2); 35 | s2 += a.x[1]; 36 | s1 = qd::quick_two_sum(s1, s2, s2); 37 | return dd_real(s1, s2); 38 | } 39 | 40 | /* double-double + double-double */ 41 | inline dd_real dd_real::ieee_add(const dd_real &a, const dd_real &b) { 42 | /* This one satisfies IEEE style error bound, 43 | due to K. Briggs and W. Kahan. */ 44 | double s1, s2, t1, t2; 45 | 46 | s1 = qd::two_sum(a.x[0], b.x[0], s2); 47 | t1 = qd::two_sum(a.x[1], b.x[1], t2); 48 | s2 += t1; 49 | s1 = qd::quick_two_sum(s1, s2, s2); 50 | s2 += t2; 51 | s1 = qd::quick_two_sum(s1, s2, s2); 52 | return dd_real(s1, s2); 53 | } 54 | 55 | inline dd_real dd_real::sloppy_add(const dd_real &a, const dd_real &b) { 56 | /* This is the less accurate version ... obeys Cray-style 57 | error bound. */ 58 | double s, e; 59 | 60 | s = qd::two_sum(a.x[0], b.x[0], e); 61 | e += (a.x[1] + b.x[1]); 62 | s = qd::quick_two_sum(s, e, e); 63 | return dd_real(s, e); 64 | } 65 | 66 | inline dd_real operator+(const dd_real &a, const dd_real &b) { 67 | #ifndef QD_IEEE_ADD 68 | return dd_real::sloppy_add(a, b); 69 | #else 70 | return dd_real::ieee_add(a, b); 71 | #endif 72 | } 73 | 74 | /* double + double-double */ 75 | inline dd_real operator+(double a, const dd_real &b) { 76 | return (b + a); 77 | } 78 | 79 | 80 | /*********** Self-Additions ************/ 81 | /* double-double += double */ 82 | inline dd_real &dd_real::operator+=(double a) { 83 | double s1, s2; 84 | s1 = qd::two_sum(x[0], a, s2); 85 | s2 += x[1]; 86 | x[0] = qd::quick_two_sum(s1, s2, x[1]); 87 | return *this; 88 | } 89 | 90 | /* double-double += double-double */ 91 | inline dd_real &dd_real::operator+=(const dd_real &a) { 92 | #ifndef QD_IEEE_ADD 93 | double s, e; 94 | s = qd::two_sum(x[0], a.x[0], e); 95 | e += x[1]; 96 | e += a.x[1]; 97 | x[0] = qd::quick_two_sum(s, e, x[1]); 98 | return *this; 99 | #else 100 | double s1, s2, t1, t2; 101 | s1 = qd::two_sum(x[0], a.x[0], s2); 102 | t1 = qd::two_sum(x[1], a.x[1], t2); 103 | s2 += t1; 104 | s1 = qd::quick_two_sum(s1, s2, s2); 105 | s2 += t2; 106 | x[0] = qd::quick_two_sum(s1, s2, x[1]); 107 | return *this; 108 | #endif 109 | } 110 | 111 | /*********** Subtractions ************/ 112 | /* double-double = double - double */ 113 | inline dd_real dd_real::sub(double a, double b) { 114 | double s, e; 115 | s = qd::two_diff(a, b, e); 116 | return dd_real(s, e); 117 | } 118 | 119 | /* double-double - double */ 120 | inline dd_real operator-(const dd_real &a, double b) { 121 | double s1, s2; 122 | s1 = qd::two_diff(a.x[0], b, s2); 123 | s2 += a.x[1]; 124 | s1 = qd::quick_two_sum(s1, s2, s2); 125 | return dd_real(s1, s2); 126 | } 127 | 128 | /* double-double - double-double */ 129 | inline dd_real operator-(const dd_real &a, const dd_real &b) { 130 | #ifndef QD_IEEE_ADD 131 | double s, e; 132 | s = qd::two_diff(a.x[0], b.x[0], e); 133 | e += a.x[1]; 134 | e -= b.x[1]; 135 | s = qd::quick_two_sum(s, e, e); 136 | return dd_real(s, e); 137 | #else 138 | double s1, s2, t1, t2; 139 | s1 = qd::two_diff(a.x[0], b.x[0], s2); 140 | t1 = qd::two_diff(a.x[1], b.x[1], t2); 141 | s2 += t1; 142 | s1 = qd::quick_two_sum(s1, s2, s2); 143 | s2 += t2; 144 | s1 = qd::quick_two_sum(s1, s2, s2); 145 | return dd_real(s1, s2); 146 | #endif 147 | } 148 | 149 | /* double - double-double */ 150 | inline dd_real operator-(double a, const dd_real &b) { 151 | double s1, s2; 152 | s1 = qd::two_diff(a, b.x[0], s2); 153 | s2 -= b.x[1]; 154 | s1 = qd::quick_two_sum(s1, s2, s2); 155 | return dd_real(s1, s2); 156 | } 157 | 158 | /*********** Self-Subtractions ************/ 159 | /* double-double -= double */ 160 | inline dd_real &dd_real::operator-=(double a) { 161 | double s1, s2; 162 | s1 = qd::two_diff(x[0], a, s2); 163 | s2 += x[1]; 164 | x[0] = qd::quick_two_sum(s1, s2, x[1]); 165 | return *this; 166 | } 167 | 168 | /* double-double -= double-double */ 169 | inline dd_real &dd_real::operator-=(const dd_real &a) { 170 | #ifndef QD_IEEE_ADD 171 | double s, e; 172 | s = qd::two_diff(x[0], a.x[0], e); 173 | e += x[1]; 174 | e -= a.x[1]; 175 | x[0] = qd::quick_two_sum(s, e, x[1]); 176 | return *this; 177 | #else 178 | double s1, s2, t1, t2; 179 | s1 = qd::two_diff(x[0], a.x[0], s2); 180 | t1 = qd::two_diff(x[1], a.x[1], t2); 181 | s2 += t1; 182 | s1 = qd::quick_two_sum(s1, s2, s2); 183 | s2 += t2; 184 | x[0] = qd::quick_two_sum(s1, s2, x[1]); 185 | return *this; 186 | #endif 187 | } 188 | 189 | /*********** Unary Minus ***********/ 190 | inline dd_real dd_real::operator-() const { 191 | return dd_real(-x[0], -x[1]); 192 | } 193 | 194 | /*********** Multiplications ************/ 195 | /* double-double = double * double */ 196 | inline dd_real dd_real::mul(double a, double b) { 197 | double p, e; 198 | p = qd::two_prod(a, b, e); 199 | return dd_real(p, e); 200 | } 201 | 202 | /* double-double * (2.0 ^ exp) */ 203 | inline dd_real ldexp(const dd_real &a, int exp) { 204 | return dd_real(qd_ldexp(a.x[0], exp), qd_ldexp(a.x[1], exp)); 205 | } 206 | 207 | /* double-double * double, where double is a power of 2. */ 208 | inline dd_real mul_pwr2(const dd_real &a, double b) { 209 | return dd_real(a.x[0] * b, a.x[1] * b); 210 | } 211 | 212 | /* double-double * double */ 213 | inline dd_real operator*(const dd_real &a, double b) { 214 | double p1, p2; 215 | 216 | p1 = qd::two_prod(a.x[0], b, p2); 217 | p2 += (a.x[1] * b); 218 | p1 = qd::quick_two_sum(p1, p2, p2); 219 | return dd_real(p1, p2); 220 | } 221 | 222 | /* double-double * double-double */ 223 | inline dd_real operator*(const dd_real &a, const dd_real &b) { 224 | double p1, p2; 225 | 226 | p1 = qd::two_prod(a.x[0], b.x[0], p2); 227 | p2 += (a.x[0] * b.x[1] + a.x[1] * b.x[0]); 228 | p1 = qd::quick_two_sum(p1, p2, p2); 229 | return dd_real(p1, p2); 230 | } 231 | 232 | /* double * double-double */ 233 | inline dd_real operator*(double a, const dd_real &b) { 234 | return (b * a); 235 | } 236 | 237 | /*********** Self-Multiplications ************/ 238 | /* double-double *= double */ 239 | inline dd_real &dd_real::operator*=(double a) { 240 | double p1, p2; 241 | p1 = qd::two_prod(x[0], a, p2); 242 | p2 += x[1] * a; 243 | x[0] = qd::quick_two_sum(p1, p2, x[1]); 244 | return *this; 245 | } 246 | 247 | /* double-double *= double-double */ 248 | inline dd_real &dd_real::operator*=(const dd_real &a) { 249 | double p1, p2; 250 | p1 = qd::two_prod(x[0], a.x[0], p2); 251 | p2 += a.x[1] * x[0]; 252 | p2 += a.x[0] * x[1]; 253 | x[0] = qd::quick_two_sum(p1, p2, x[1]); 254 | return *this; 255 | } 256 | 257 | /*********** Divisions ************/ 258 | inline dd_real dd_real::div(double a, double b) { 259 | double q1, q2; 260 | double p1, p2; 261 | double s, e; 262 | 263 | q1 = a / b; 264 | 265 | /* Compute a - q1 * b */ 266 | p1 = qd::two_prod(q1, b, p2); 267 | s = qd::two_diff(a, p1, e); 268 | e -= p2; 269 | 270 | /* get next approximation */ 271 | q2 = (s + e) / b; 272 | 273 | s = qd::quick_two_sum(q1, q2, e); 274 | 275 | return dd_real(s, e); 276 | } 277 | 278 | /* double-double / double */ 279 | inline dd_real operator/(const dd_real &a, double b) { 280 | 281 | double q1, q2; 282 | double p1, p2; 283 | double s, e; 284 | dd_real r; 285 | 286 | q1 = a.x[0] / b; /* approximate quotient. */ 287 | 288 | /* Compute this - q1 * d */ 289 | p1 = qd::two_prod(q1, b, p2); 290 | s = qd::two_diff(a.x[0], p1, e); 291 | e += a.x[1]; 292 | e -= p2; 293 | 294 | /* get next approximation. */ 295 | q2 = (s + e) / b; 296 | 297 | /* renormalize */ 298 | r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]); 299 | 300 | return r; 301 | } 302 | 303 | inline dd_real dd_real::sloppy_div(const dd_real &a, const dd_real &b) { 304 | double s1, s2; 305 | double q1, q2; 306 | dd_real r; 307 | 308 | q1 = a.x[0] / b.x[0]; /* approximate quotient */ 309 | 310 | /* compute this - q1 * dd */ 311 | r = b * q1; 312 | s1 = qd::two_diff(a.x[0], r.x[0], s2); 313 | s2 -= r.x[1]; 314 | s2 += a.x[1]; 315 | 316 | /* get next approximation */ 317 | q2 = (s1 + s2) / b.x[0]; 318 | 319 | /* renormalize */ 320 | r.x[0] = qd::quick_two_sum(q1, q2, r.x[1]); 321 | return r; 322 | } 323 | 324 | inline dd_real dd_real::accurate_div(const dd_real &a, const dd_real &b) { 325 | double q1, q2, q3; 326 | dd_real r; 327 | 328 | q1 = a.x[0] / b.x[0]; /* approximate quotient */ 329 | 330 | r = a - q1 * b; 331 | 332 | q2 = r.x[0] / b.x[0]; 333 | r -= (q2 * b); 334 | 335 | q3 = r.x[0] / b.x[0]; 336 | 337 | q1 = qd::quick_two_sum(q1, q2, q2); 338 | r = dd_real(q1, q2) + q3; 339 | return r; 340 | } 341 | 342 | /* double-double / double-double */ 343 | inline dd_real operator/(const dd_real &a, const dd_real &b) { 344 | #ifdef QD_SLOPPY_DIV 345 | return dd_real::sloppy_div(a, b); 346 | #else 347 | return dd_real::accurate_div(a, b); 348 | #endif 349 | } 350 | 351 | /* double / double-double */ 352 | inline dd_real operator/(double a, const dd_real &b) { 353 | return dd_real(a) / b; 354 | } 355 | 356 | inline dd_real inv(const dd_real &a) { 357 | return 1.0 / a; 358 | } 359 | 360 | /*********** Self-Divisions ************/ 361 | /* double-double /= double */ 362 | inline dd_real &dd_real::operator/=(double a) { 363 | *this = *this / a; 364 | return *this; 365 | } 366 | 367 | /* double-double /= double-double */ 368 | inline dd_real &dd_real::operator/=(const dd_real &a) { 369 | *this = *this / a; 370 | return *this; 371 | } 372 | 373 | /********** Remainder **********/ 374 | inline dd_real drem(const dd_real &a, const dd_real &b) { 375 | dd_real n = nint(a / b); 376 | return (a - n * b); 377 | } 378 | 379 | inline dd_real divrem(const dd_real &a, const dd_real &b, dd_real &r) { 380 | dd_real n = nint(a / b); 381 | r = a - n * b; 382 | return n; 383 | } 384 | 385 | /*********** Squaring **********/ 386 | inline dd_real sqr(const dd_real &a) { 387 | double p1, p2; 388 | double s1, s2; 389 | p1 = qd::two_sqr(a.x[0], p2); 390 | p2 += 2.0 * a.x[0] * a.x[1]; 391 | p2 += a.x[1] * a.x[1]; 392 | s1 = qd::quick_two_sum(p1, p2, s2); 393 | return dd_real(s1, s2); 394 | } 395 | 396 | inline dd_real dd_real::sqr(double a) { 397 | double p1, p2; 398 | p1 = qd::two_sqr(a, p2); 399 | return dd_real(p1, p2); 400 | } 401 | 402 | 403 | /********** Exponentiation **********/ 404 | inline dd_real dd_real::operator^(int n) { 405 | return npwr(*this, n); 406 | } 407 | 408 | 409 | /*********** Assignments ************/ 410 | /* double-double = double */ 411 | inline dd_real &dd_real::operator=(double a) { 412 | x[0] = a; 413 | x[1] = 0.0; 414 | return *this; 415 | } 416 | 417 | /*********** Equality Comparisons ************/ 418 | /* double-double == double */ 419 | inline bool operator==(const dd_real &a, double b) { 420 | return (a.x[0] == b && a.x[1] == 0.0); 421 | } 422 | 423 | /* double-double == double-double */ 424 | inline bool operator==(const dd_real &a, const dd_real &b) { 425 | return (a.x[0] == b.x[0] && a.x[1] == b.x[1]); 426 | } 427 | 428 | /* double == double-double */ 429 | inline bool operator==(double a, const dd_real &b) { 430 | return (a == b.x[0] && b.x[1] == 0.0); 431 | } 432 | 433 | /*********** Greater-Than Comparisons ************/ 434 | /* double-double > double */ 435 | inline bool operator>(const dd_real &a, double b) { 436 | return (a.x[0] > b || (a.x[0] == b && a.x[1] > 0.0)); 437 | } 438 | 439 | /* double-double > double-double */ 440 | inline bool operator>(const dd_real &a, const dd_real &b) { 441 | return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] > b.x[1])); 442 | } 443 | 444 | /* double > double-double */ 445 | inline bool operator>(double a, const dd_real &b) { 446 | return (a > b.x[0] || (a == b.x[0] && b.x[1] < 0.0)); 447 | } 448 | 449 | /*********** Less-Than Comparisons ************/ 450 | /* double-double < double */ 451 | inline bool operator<(const dd_real &a, double b) { 452 | return (a.x[0] < b || (a.x[0] == b && a.x[1] < 0.0)); 453 | } 454 | 455 | /* double-double < double-double */ 456 | inline bool operator<(const dd_real &a, const dd_real &b) { 457 | return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] < b.x[1])); 458 | } 459 | 460 | /* double < double-double */ 461 | inline bool operator<(double a, const dd_real &b) { 462 | return (a < b.x[0] || (a == b.x[0] && b.x[1] > 0.0)); 463 | } 464 | 465 | /*********** Greater-Than-Or-Equal-To Comparisons ************/ 466 | /* double-double >= double */ 467 | inline bool operator>=(const dd_real &a, double b) { 468 | return (a.x[0] > b || (a.x[0] == b && a.x[1] >= 0.0)); 469 | } 470 | 471 | /* double-double >= double-double */ 472 | inline bool operator>=(const dd_real &a, const dd_real &b) { 473 | return (a.x[0] > b.x[0] || (a.x[0] == b.x[0] && a.x[1] >= b.x[1])); 474 | } 475 | 476 | /* double >= double-double */ 477 | inline bool operator>=(double a, const dd_real &b) { 478 | return (b <= a); 479 | } 480 | 481 | /*********** Less-Than-Or-Equal-To Comparisons ************/ 482 | /* double-double <= double */ 483 | inline bool operator<=(const dd_real &a, double b) { 484 | return (a.x[0] < b || (a.x[0] == b && a.x[1] <= 0.0)); 485 | } 486 | 487 | /* double-double <= double-double */ 488 | inline bool operator<=(const dd_real &a, const dd_real &b) { 489 | return (a.x[0] < b.x[0] || (a.x[0] == b.x[0] && a.x[1] <= b.x[1])); 490 | } 491 | 492 | /* double <= double-double */ 493 | inline bool operator<=(double a, const dd_real &b) { 494 | return (b >= a); 495 | } 496 | 497 | /*********** Not-Equal-To Comparisons ************/ 498 | /* double-double != double */ 499 | inline bool operator!=(const dd_real &a, double b) { 500 | return (a.x[0] != b || a.x[1] != 0.0); 501 | } 502 | 503 | /* double-double != double-double */ 504 | inline bool operator!=(const dd_real &a, const dd_real &b) { 505 | return (a.x[0] != b.x[0] || a.x[1] != b.x[1]); 506 | } 507 | 508 | /* double != double-double */ 509 | inline bool operator!=(double a, const dd_real &b) { 510 | return (a != b.x[0] || b.x[1] != 0.0); 511 | } 512 | 513 | /*********** Micellaneous ************/ 514 | /* this == 0 */ 515 | inline bool dd_real::is_zero() const { 516 | return (x[0] == 0.0); 517 | } 518 | 519 | /* this == 1 */ 520 | inline bool dd_real::is_one() const { 521 | return (x[0] == 1.0 && x[1] == 0.0); 522 | } 523 | 524 | /* this > 0 */ 525 | inline bool dd_real::is_positive() const { 526 | return (x[0] > 0.0); 527 | } 528 | 529 | /* this < 0 */ 530 | inline bool dd_real::is_negative() const { 531 | return (x[0] < 0.0); 532 | } 533 | 534 | /* Absolute value */ 535 | inline dd_real abs(const dd_real &a) { 536 | return (a.x[0] < 0.0) ? -a : a; 537 | } 538 | 539 | inline dd_real fabs(const dd_real &a) { 540 | return abs(a); 541 | } 542 | 543 | /* Round to Nearest integer */ 544 | inline dd_real nint(const dd_real &a) { 545 | double hi = qd::nint(a.x[0]); 546 | double lo; 547 | 548 | if (hi == a.x[0]) { 549 | /* High word is an integer already. Round the low word.*/ 550 | lo = qd::nint(a.x[1]); 551 | 552 | /* Renormalize. This is needed if x[0] = some integer, x[1] = 1/2.*/ 553 | hi = qd::quick_two_sum(hi, lo, lo); 554 | } else { 555 | /* High word is not an integer. */ 556 | lo = 0.0; 557 | if (qd_abs(hi-a.x[0]) == 0.5 && a.x[1] < 0.0) { 558 | /* There is a tie in the high word, consult the low word 559 | to break the tie. */ 560 | hi -= 1.0; /* NOTE: This does not cause INEXACT. */ 561 | } 562 | } 563 | 564 | return dd_real(hi, lo); 565 | } 566 | 567 | inline dd_real floor(const dd_real &a) { 568 | double hi = qd_floor(a.x[0]); 569 | double lo = 0.0; 570 | 571 | if (hi == a.x[0]) { 572 | /* High word is integer already. Round the low word. */ 573 | lo = qd_floor(a.x[1]); 574 | hi = qd::quick_two_sum(hi, lo, lo); 575 | } 576 | 577 | return dd_real(hi, lo); 578 | } 579 | 580 | inline dd_real ceil(const dd_real &a) { 581 | double hi = qd_ceil(a.x[0]); 582 | double lo = 0.0; 583 | 584 | if (hi == a.x[0]) { 585 | /* High word is integer already. Round the low word. */ 586 | lo = qd_ceil(a.x[1]); 587 | hi = qd::quick_two_sum(hi, lo, lo); 588 | } 589 | 590 | return dd_real(hi, lo); 591 | } 592 | 593 | inline dd_real aint(const dd_real &a) { 594 | return (a.x[0] >= 0.0) ? floor(a) : ceil(a); 595 | } 596 | 597 | /* Cast to double. */ 598 | inline double to_double(const dd_real &a) { 599 | return a.x[0]; 600 | } 601 | 602 | /* Cast to int. */ 603 | inline int to_int(const dd_real &a) { 604 | return static_cast(a.x[0]); 605 | } 606 | 607 | /* Random number generator */ 608 | inline dd_real dd_real::rand() { 609 | return ddrand(); 610 | } 611 | 612 | #endif /* _QD_DD_INLINE_H */ 613 | -------------------------------------------------------------------------------- /C/dd_real.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * src/dd_real.cc 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2007 9 | * 10 | * Contains implementation of non-inlined functions of double-double 11 | * package. Inlined functions are found in dd_inline.h (in include directory). 12 | */ 13 | 14 | #include "qd_config.h" 15 | #include "dd_real.h" 16 | 17 | #ifndef QD_INLINE 18 | #include "dd_inline.h" 19 | #endif 20 | 21 | /* This routine is called whenever a fatal error occurs. */ 22 | void dd_real::error(const char *msg) { 23 | } 24 | 25 | /* Computes the square root of the double-double number dd. 26 | NOTE: dd must be a non-negative number. */ 27 | QD_API dd_real sqrt(const dd_real &a) { 28 | /* Strategy: Use Karp's trick: if x is an approximation 29 | to sqrt(a), then 30 | 31 | sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx) 32 | 33 | The approximation is accurate to twice the accuracy of x. 34 | Also, the multiplication (a*x) and [-]*x can be done with 35 | only half the precision. 36 | */ 37 | 38 | if (a.is_zero()) 39 | return 0.0; 40 | 41 | if (a.is_negative()) { 42 | dd_real::error("(dd_real::sqrt): Negative argument."); 43 | return dd_real::_nan; 44 | } 45 | 46 | double x = 1.0 / qd_sqrt(a.x[0]); 47 | double ax = a.x[0] * x; 48 | return dd_real::add(ax, (a - dd_real::sqr(ax)).x[0] * (x * 0.5)); 49 | } 50 | 51 | /* Computes the square root of a double in double-double precision. 52 | NOTE: d must not be negative. */ 53 | dd_real dd_real::sqrt(double d) { 54 | return ::sqrt(dd_real(d)); 55 | } 56 | 57 | /* Computes the n-th root of the double-double number a. 58 | NOTE: n must be a positive integer. 59 | NOTE: If n is even, then a must not be negative. */ 60 | dd_real nroot(const dd_real &a, int n) { 61 | /* Strategy: Use Newton iteration for the function 62 | 63 | f(x) = x^(-n) - a 64 | 65 | to find its root a^{-1/n}. The iteration is thus 66 | 67 | x' = x + x * (1 - a * x^n) / n 68 | 69 | which converges quadratically. We can then find 70 | a^{1/n} by taking the reciprocal. 71 | */ 72 | 73 | if (n <= 0) { 74 | dd_real::error("(dd_real::nroot): N must be positive."); 75 | return dd_real::_nan; 76 | } 77 | 78 | if (n%2 == 0 && a.is_negative()) { 79 | dd_real::error("(dd_real::nroot): Negative argument."); 80 | return dd_real::_nan; 81 | } 82 | 83 | if (n == 1) { 84 | return a; 85 | } 86 | if (n == 2) { 87 | return sqrt(a); 88 | } 89 | 90 | if (a.is_zero()) 91 | return 0.0; 92 | 93 | /* Note a^{-1/n} = exp(-log(a)/n) */ 94 | dd_real r = abs(a); 95 | dd_real x = qd_exp(-qd_log(r.x[0]) / n); 96 | 97 | /* Perform Newton's iteration. */ 98 | x += x * (1.0 - r * npwr(x, n)) / static_cast(n); 99 | if (a.x[0] < 0.0) 100 | x = -x; 101 | return 1.0/x; 102 | } 103 | 104 | /* Computes the n-th power of a double-double number. 105 | NOTE: 0^0 causes an error. */ 106 | dd_real npwr(const dd_real &a, int n) { 107 | 108 | if (n == 0) { 109 | if (a.is_zero()) { 110 | dd_real::error("(dd_real::npwr): Invalid argument."); 111 | return dd_real::_nan; 112 | } 113 | return 1.0; 114 | } 115 | 116 | dd_real r = a; 117 | dd_real s = 1.0; 118 | int N = qd_abs(n); 119 | 120 | if (N > 1) { 121 | /* Use binary exponentiation */ 122 | while (N > 0) { 123 | if (N % 2 == 1) { 124 | s *= r; 125 | } 126 | N /= 2; 127 | if (N > 0) 128 | r = sqr(r); 129 | } 130 | } else { 131 | s = r; 132 | } 133 | 134 | /* Compute the reciprocal if n is negative. */ 135 | if (n < 0) 136 | return (1.0 / s); 137 | 138 | return s; 139 | } 140 | 141 | dd_real pow(const dd_real &a, int n) { 142 | return npwr(a, n); 143 | } 144 | 145 | dd_real pow(const dd_real &a, const dd_real &b) { 146 | return exp(b * log(a)); 147 | } 148 | 149 | static const int n_inv_fact = 15; 150 | static const double inv_fact[n_inv_fact][2] = { 151 | { 1.66666666666666657e-01, 9.25185853854297066e-18}, 152 | { 4.16666666666666644e-02, 2.31296463463574266e-18}, 153 | { 8.33333333333333322e-03, 1.15648231731787138e-19}, 154 | { 1.38888888888888894e-03, -5.30054395437357706e-20}, 155 | { 1.98412698412698413e-04, 1.72095582934207053e-22}, 156 | { 2.48015873015873016e-05, 2.15119478667758816e-23}, 157 | { 2.75573192239858925e-06, -1.85839327404647208e-22}, 158 | { 2.75573192239858883e-07, 2.37677146222502973e-23}, 159 | { 2.50521083854417202e-08, -1.44881407093591197e-24}, 160 | { 2.08767569878681002e-09, -1.20734505911325997e-25}, 161 | { 1.60590438368216133e-10, 1.25852945887520981e-26}, 162 | { 1.14707455977297245e-11, 2.06555127528307454e-28}, 163 | { 7.64716373181981641e-13, 7.03872877733453001e-30}, 164 | { 4.77947733238738525e-14, 4.39920548583408126e-31}, 165 | { 2.81145725434552060e-15, 1.65088427308614326e-31} 166 | }; 167 | 168 | /* Exponential. Computes exp(x) in double-double precision. */ 169 | dd_real exp(const dd_real &a) { 170 | /* Strategy: We first reduce the size of x by noting that 171 | 172 | exp(kr + m * log(2)) = 2^m * exp(r)^k 173 | 174 | where m and k are integers. By choosing m appropriately 175 | we can make |kr| <= log(2) / 2 = 0.347. Then exp(r) is 176 | evaluated using the familiar Taylor series. Reducing the 177 | argument substantially speeds up the convergence. */ 178 | 179 | const double k = 512.0; 180 | const double inv_k = 1.0 / k; 181 | 182 | if (a.x[0] <= -709.0) 183 | return 0.0; 184 | 185 | if (a.x[0] >= 709.0) 186 | return dd_real::_inf; 187 | 188 | if (a.is_zero()) 189 | return 1.0; 190 | 191 | if (a.is_one()) 192 | return dd_real::_e; 193 | 194 | double m = qd_floor(a.x[0] / dd_real::_log2.x[0] + 0.5); 195 | dd_real r = mul_pwr2(a - dd_real::_log2 * m, inv_k); 196 | dd_real s, t, p; 197 | 198 | p = sqr(r); 199 | s = r + mul_pwr2(p, 0.5); 200 | p *= r; 201 | t = p * dd_real(inv_fact[0][0], inv_fact[0][1]); 202 | int i = 0; 203 | do { 204 | s += t; 205 | p *= r; 206 | ++i; 207 | t = p * dd_real(inv_fact[i][0], inv_fact[i][1]); 208 | } while (qd_fabs(to_double(t)) > inv_k * dd_real::_eps && i < 5); 209 | 210 | s += t; 211 | 212 | s = mul_pwr2(s, 2.0) + sqr(s); 213 | s = mul_pwr2(s, 2.0) + sqr(s); 214 | s = mul_pwr2(s, 2.0) + sqr(s); 215 | s = mul_pwr2(s, 2.0) + sqr(s); 216 | s = mul_pwr2(s, 2.0) + sqr(s); 217 | s = mul_pwr2(s, 2.0) + sqr(s); 218 | s = mul_pwr2(s, 2.0) + sqr(s); 219 | s = mul_pwr2(s, 2.0) + sqr(s); 220 | s = mul_pwr2(s, 2.0) + sqr(s); 221 | s += 1.0; 222 | 223 | return ldexp(s, static_cast(m)); 224 | } 225 | 226 | /* Logarithm. Computes log(x) in double-double precision. 227 | This is a natural logarithm (i.e., base e). */ 228 | dd_real log(const dd_real &a) { 229 | /* Strategy. The Taylor series for log converges much more 230 | slowly than that of exp, due to the lack of the factorial 231 | term in the denominator. Hence this routine instead tries 232 | to determine the root of the function 233 | 234 | f(x) = exp(x) - a 235 | 236 | using Newton iteration. The iteration is given by 237 | 238 | x' = x - f(x)/f'(x) 239 | = x - (1 - a * exp(-x)) 240 | = x + a * exp(-x) - 1. 241 | 242 | Only one iteration is needed, since Newton's iteration 243 | approximately doubles the number of digits per iteration. */ 244 | 245 | if (a.is_one()) { 246 | return 0.0; 247 | } 248 | 249 | if (a.x[0] <= 0.0) { 250 | dd_real::error("(dd_real::log): Non-positive argument."); 251 | return dd_real::_nan; 252 | } 253 | 254 | dd_real x = qd_log(a.x[0]); /* Initial approximation */ 255 | 256 | x = x + a * exp(-x) - 1.0; 257 | return x; 258 | } 259 | 260 | dd_real log10(const dd_real &a) { 261 | return log(a) / dd_real::_log10; 262 | } 263 | 264 | /* Table of sin(k * pi/16) and cos(k * pi/16). */ 265 | static const double sin_table [4][2] = { 266 | {1.950903220161282758e-01, -7.991079068461731263e-18}, 267 | {3.826834323650897818e-01, -1.005077269646158761e-17}, 268 | {5.555702330196021776e-01, 4.709410940561676821e-17}, 269 | {7.071067811865475727e-01, -4.833646656726456726e-17} 270 | }; 271 | 272 | static const double cos_table [4][2] = { 273 | {9.807852804032304306e-01, 1.854693999782500573e-17}, 274 | {9.238795325112867385e-01, 1.764504708433667706e-17}, 275 | {8.314696123025452357e-01, 1.407385698472802389e-18}, 276 | {7.071067811865475727e-01, -4.833646656726456726e-17} 277 | }; 278 | 279 | /* Computes sin(a) using Taylor series. 280 | Assumes |a| <= pi/32. */ 281 | static dd_real sin_taylor(const dd_real &a) { 282 | const double thresh = 0.5 * qd_fabs(to_double(a)) * dd_real::_eps; 283 | dd_real r, s, t, x; 284 | 285 | if (a.is_zero()) { 286 | return 0.0; 287 | } 288 | 289 | int i = 0; 290 | x = -sqr(a); 291 | s = a; 292 | r = a; 293 | do { 294 | r *= x; 295 | t = r * dd_real(inv_fact[i][0], inv_fact[i][1]); 296 | s += t; 297 | i += 2; 298 | } while (i < n_inv_fact && qd_fabs(to_double(t)) > thresh); 299 | 300 | return s; 301 | } 302 | 303 | static dd_real cos_taylor(const dd_real &a) { 304 | const double thresh = 0.5 * dd_real::_eps; 305 | dd_real r, s, t, x; 306 | 307 | if (a.is_zero()) { 308 | return 1.0; 309 | } 310 | 311 | x = -sqr(a); 312 | r = x; 313 | s = 1.0 + mul_pwr2(r, 0.5); 314 | int i = 1; 315 | do { 316 | r *= x; 317 | t = r * dd_real(inv_fact[i][0], inv_fact[i][1]); 318 | s += t; 319 | i += 2; 320 | } while (i < n_inv_fact && qd_fabs(to_double(t)) > thresh); 321 | 322 | return s; 323 | } 324 | 325 | static void sincos_taylor(const dd_real &a, 326 | dd_real &sin_a, dd_real &cos_a) { 327 | if (a.is_zero()) { 328 | sin_a = 0.0; 329 | cos_a = 1.0; 330 | return; 331 | } 332 | 333 | sin_a = sin_taylor(a); 334 | cos_a = sqrt(1.0 - sqr(sin_a)); 335 | } 336 | 337 | 338 | dd_real sin(const dd_real &a) { 339 | 340 | /* Strategy. To compute sin(x), we choose integers a, b so that 341 | 342 | x = s + a * (pi/2) + b * (pi/16) 343 | 344 | and |s| <= pi/32. Using the fact that 345 | 346 | sin(pi/16) = 0.5 * sqrt(2 - sqrt(2 + sqrt(2))) 347 | 348 | we can compute sin(x) from sin(s), cos(s). This greatly 349 | increases the convergence of the sine Taylor series. */ 350 | 351 | if (a.is_zero()) { 352 | return 0.0; 353 | } 354 | 355 | // approximately reduce modulo 2*pi 356 | dd_real z = nint(a / dd_real::_2pi); 357 | dd_real r = a - dd_real::_2pi * z; 358 | 359 | // approximately reduce modulo pi/2 and then modulo pi/16. 360 | dd_real t; 361 | double q = qd_floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); 362 | t = r - dd_real::_pi2 * q; 363 | int j = static_cast(q); 364 | q = qd_floor(t.x[0] / dd_real::_pi16.x[0] + 0.5); 365 | t -= dd_real::_pi16 * q; 366 | int k = static_cast(q); 367 | int abs_k = qd_abs(k); 368 | 369 | if (j < -2 || j > 2) { 370 | dd_real::error("(dd_real::sin): Cannot reduce modulo pi/2."); 371 | return dd_real::_nan; 372 | } 373 | 374 | if (abs_k > 4) { 375 | dd_real::error("(dd_real::sin): Cannot reduce modulo pi/16."); 376 | return dd_real::_nan; 377 | } 378 | 379 | if (k == 0) { 380 | switch (j) { 381 | case 0: 382 | return sin_taylor(t); 383 | case 1: 384 | return cos_taylor(t); 385 | case -1: 386 | return -cos_taylor(t); 387 | default: 388 | return -sin_taylor(t); 389 | } 390 | } 391 | 392 | dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); 393 | dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); 394 | dd_real sin_t, cos_t; 395 | sincos_taylor(t, sin_t, cos_t); 396 | if (j == 0) { 397 | if (k > 0) { 398 | r = u * sin_t + v * cos_t; 399 | } else { 400 | r = u * sin_t - v * cos_t; 401 | } 402 | } else if (j == 1) { 403 | if (k > 0) { 404 | r = u * cos_t - v * sin_t; 405 | } else { 406 | r = u * cos_t + v * sin_t; 407 | } 408 | } else if (j == -1) { 409 | if (k > 0) { 410 | r = v * sin_t - u * cos_t; 411 | } else if (k < 0) { 412 | r = -u * cos_t - v * sin_t; 413 | } 414 | } else { 415 | if (k > 0) { 416 | r = -u * sin_t - v * cos_t; 417 | } else { 418 | r = v * cos_t - u * sin_t; 419 | } 420 | } 421 | 422 | return r; 423 | } 424 | 425 | dd_real cos(const dd_real &a) { 426 | 427 | if (a.is_zero()) { 428 | return 1.0; 429 | } 430 | 431 | // approximately reduce modulo 2*pi 432 | dd_real z = nint(a / dd_real::_2pi); 433 | dd_real r = a - z * dd_real::_2pi; 434 | 435 | // approximately reduce modulo pi/2 and then modulo pi/16 436 | dd_real t; 437 | double q = qd_floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); 438 | t = r - dd_real::_pi2 * q; 439 | int j = static_cast(q); 440 | q = qd_floor(t.x[0] / dd_real::_pi16.x[0] + 0.5); 441 | t -= dd_real::_pi16 * q; 442 | int k = static_cast(q); 443 | int abs_k = qd_abs(k); 444 | 445 | if (j < -2 || j > 2) { 446 | dd_real::error("(dd_real::cos): Cannot reduce modulo pi/2."); 447 | return dd_real::_nan; 448 | } 449 | 450 | if (abs_k > 4) { 451 | dd_real::error("(dd_real::cos): Cannot reduce modulo pi/16."); 452 | return dd_real::_nan; 453 | } 454 | 455 | if (k == 0) { 456 | switch (j) { 457 | case 0: 458 | return cos_taylor(t); 459 | case 1: 460 | return -sin_taylor(t); 461 | case -1: 462 | return sin_taylor(t); 463 | default: 464 | return -cos_taylor(t); 465 | } 466 | } 467 | 468 | dd_real sin_t, cos_t; 469 | sincos_taylor(t, sin_t, cos_t); 470 | dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); 471 | dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); 472 | 473 | if (j == 0) { 474 | if (k > 0) { 475 | r = u * cos_t - v * sin_t; 476 | } else { 477 | r = u * cos_t + v * sin_t; 478 | } 479 | } else if (j == 1) { 480 | if (k > 0) { 481 | r = - u * sin_t - v * cos_t; 482 | } else { 483 | r = v * cos_t - u * sin_t; 484 | } 485 | } else if (j == -1) { 486 | if (k > 0) { 487 | r = u * sin_t + v * cos_t; 488 | } else { 489 | r = u * sin_t - v * cos_t; 490 | } 491 | } else { 492 | if (k > 0) { 493 | r = v * sin_t - u * cos_t; 494 | } else { 495 | r = - u * cos_t - v * sin_t; 496 | } 497 | } 498 | 499 | return r; 500 | } 501 | 502 | void sincos(const dd_real &a, dd_real &sin_a, dd_real &cos_a) { 503 | 504 | if (a.is_zero()) { 505 | sin_a = 0.0; 506 | cos_a = 1.0; 507 | return; 508 | } 509 | 510 | // approximately reduce modulo 2*pi 511 | dd_real z = nint(a / dd_real::_2pi); 512 | dd_real r = a - dd_real::_2pi * z; 513 | 514 | // approximately reduce module pi/2 and pi/16 515 | dd_real t; 516 | double q = qd_floor(r.x[0] / dd_real::_pi2.x[0] + 0.5); 517 | t = r - dd_real::_pi2 * q; 518 | int j = static_cast(q); 519 | int abs_j = qd_abs(j); 520 | q = qd_floor(t.x[0] / dd_real::_pi16.x[0] + 0.5); 521 | t -= dd_real::_pi16 * q; 522 | int k = static_cast(q); 523 | int abs_k = qd_abs(k); 524 | 525 | if (abs_j > 2) { 526 | dd_real::error("(dd_real::sincos): Cannot reduce modulo pi/2."); 527 | cos_a = sin_a = dd_real::_nan; 528 | return; 529 | } 530 | 531 | if (abs_k > 4) { 532 | dd_real::error("(dd_real::sincos): Cannot reduce modulo pi/16."); 533 | cos_a = sin_a = dd_real::_nan; 534 | return; 535 | } 536 | 537 | dd_real sin_t, cos_t; 538 | dd_real s, c; 539 | 540 | sincos_taylor(t, sin_t, cos_t); 541 | 542 | if (abs_k == 0) { 543 | s = sin_t; 544 | c = cos_t; 545 | } else { 546 | dd_real u(cos_table[abs_k-1][0], cos_table[abs_k-1][1]); 547 | dd_real v(sin_table[abs_k-1][0], sin_table[abs_k-1][1]); 548 | 549 | if (k > 0) { 550 | s = u * sin_t + v * cos_t; 551 | c = u * cos_t - v * sin_t; 552 | } else { 553 | s = u * sin_t - v * cos_t; 554 | c = u * cos_t + v * sin_t; 555 | } 556 | } 557 | 558 | if (abs_j == 0) { 559 | sin_a = s; 560 | cos_a = c; 561 | } else if (j == 1) { 562 | sin_a = c; 563 | cos_a = -s; 564 | } else if (j == -1) { 565 | sin_a = -c; 566 | cos_a = s; 567 | } else { 568 | sin_a = -s; 569 | cos_a = -c; 570 | } 571 | 572 | } 573 | 574 | dd_real atan(const dd_real &a) { 575 | return atan2(a, dd_real(1.0)); 576 | } 577 | 578 | dd_real atan2(const dd_real &y, const dd_real &x) { 579 | /* Strategy: Instead of using Taylor series to compute 580 | arctan, we instead use Newton's iteration to solve 581 | the equation 582 | 583 | sin(z) = y/r or cos(z) = x/r 584 | 585 | where r = sqrt(x^2 + y^2). 586 | The iteration is given by 587 | 588 | z' = z + (y - sin(z)) / cos(z) (for equation 1) 589 | z' = z - (x - cos(z)) / sin(z) (for equation 2) 590 | 591 | Here, x and y are normalized so that x^2 + y^2 = 1. 592 | If |x| > |y|, then first iteration is used since the 593 | denominator is larger. Otherwise, the second is used. 594 | */ 595 | 596 | if (x.is_zero()) { 597 | 598 | if (y.is_zero()) { 599 | /* Both x and y is zero. */ 600 | dd_real::error("(dd_real::atan2): Both arguments zero."); 601 | return dd_real::_nan; 602 | } 603 | 604 | return (y.is_positive()) ? dd_real::_pi2 : -dd_real::_pi2; 605 | } else if (y.is_zero()) { 606 | return (x.is_positive()) ? dd_real(0.0) : dd_real::_pi; 607 | } 608 | 609 | if (x == y) { 610 | return (y.is_positive()) ? dd_real::_pi4 : -dd_real::_3pi4; 611 | } 612 | 613 | if (x == -y) { 614 | return (y.is_positive()) ? dd_real::_3pi4 : -dd_real::_pi4; 615 | } 616 | 617 | dd_real r = sqrt(sqr(x) + sqr(y)); 618 | dd_real xx = x / r; 619 | dd_real yy = y / r; 620 | 621 | /* Compute double precision approximation to atan. */ 622 | dd_real z = qd_atan2(to_double(y), to_double(x)); 623 | dd_real sin_z, cos_z; 624 | 625 | if (qd_fabs(xx.x[0]) > qd_fabs(yy.x[0])) { 626 | /* Use Newton iteration 1. z' = z + (y - sin(z)) / cos(z) */ 627 | sincos(z, sin_z, cos_z); 628 | z += (yy - sin_z) / cos_z; 629 | } else { 630 | /* Use Newton iteration 2. z' = z - (x - cos(z)) / sin(z) */ 631 | sincos(z, sin_z, cos_z); 632 | z -= (xx - cos_z) / sin_z; 633 | } 634 | 635 | return z; 636 | } 637 | 638 | dd_real tan(const dd_real &a) { 639 | dd_real s, c; 640 | sincos(a, s, c); 641 | return s/c; 642 | } 643 | 644 | dd_real asin(const dd_real &a) { 645 | dd_real abs_a = abs(a); 646 | 647 | if (abs_a > 1.0) { 648 | dd_real::error("(dd_real::asin): Argument out of domain."); 649 | return dd_real::_nan; 650 | } 651 | 652 | if (abs_a.is_one()) { 653 | return (a.is_positive()) ? dd_real::_pi2 : -dd_real::_pi2; 654 | } 655 | 656 | return atan2(a, sqrt(1.0 - sqr(a))); 657 | } 658 | 659 | dd_real acos(const dd_real &a) { 660 | dd_real abs_a = abs(a); 661 | 662 | if (abs_a > 1.0) { 663 | dd_real::error("(dd_real::acos): Argument out of domain."); 664 | return dd_real::_nan; 665 | } 666 | 667 | if (abs_a.is_one()) { 668 | return (a.is_positive()) ? dd_real(0.0) : dd_real::_pi; 669 | } 670 | 671 | return atan2(sqrt(1.0 - sqr(a)), a); 672 | } 673 | 674 | dd_real sinh(const dd_real &a) { 675 | if (a.is_zero()) { 676 | return 0.0; 677 | } 678 | 679 | if (abs(a) > 0.05) { 680 | dd_real ea = exp(a); 681 | return mul_pwr2(ea - inv(ea), 0.5); 682 | } 683 | 684 | /* since a is small, using the above formula gives 685 | a lot of cancellation. So use Taylor series. */ 686 | dd_real s = a; 687 | dd_real t = a; 688 | dd_real r = sqr(t); 689 | double m = 1.0; 690 | double thresh = qd_fabs((to_double(a)) * dd_real::_eps); 691 | 692 | do { 693 | m += 2.0; 694 | t *= r; 695 | t /= (m-1) * m; 696 | 697 | s += t; 698 | } while (abs(t) > thresh); 699 | 700 | return s; 701 | 702 | } 703 | 704 | dd_real cosh(const dd_real &a) { 705 | if (a.is_zero()) { 706 | return 1.0; 707 | } 708 | 709 | dd_real ea = exp(a); 710 | return mul_pwr2(ea + inv(ea), 0.5); 711 | } 712 | 713 | dd_real tanh(const dd_real &a) { 714 | if (a.is_zero()) { 715 | return 0.0; 716 | } 717 | 718 | if (qd_fabs(to_double(a)) > 0.05) { 719 | dd_real ea = exp(a); 720 | dd_real inv_ea = inv(ea); 721 | return (ea - inv_ea) / (ea + inv_ea); 722 | } else { 723 | dd_real s, c; 724 | s = sinh(a); 725 | c = sqrt(1.0 + sqr(s)); 726 | return s / c; 727 | } 728 | } 729 | 730 | void sincosh(const dd_real &a, dd_real &s, dd_real &c) { 731 | if (qd_fabs(to_double(a)) <= 0.05) { 732 | s = sinh(a); 733 | c = sqrt(1.0 + sqr(s)); 734 | } else { 735 | dd_real ea = exp(a); 736 | dd_real inv_ea = inv(ea); 737 | s = mul_pwr2(ea - inv_ea, 0.5); 738 | c = mul_pwr2(ea + inv_ea, 0.5); 739 | } 740 | } 741 | 742 | dd_real asinh(const dd_real &a) { 743 | return log(a + sqrt(sqr(a) + 1.0)); 744 | } 745 | 746 | dd_real acosh(const dd_real &a) { 747 | if (a < 1.0) { 748 | dd_real::error("(dd_real::acosh): Argument out of domain."); 749 | return dd_real::_nan; 750 | } 751 | 752 | return log(a + sqrt(sqr(a) - 1.0)); 753 | } 754 | 755 | dd_real atanh(const dd_real &a) { 756 | if (abs(a) >= 1.0) { 757 | dd_real::error("(dd_real::atanh): Argument out of domain."); 758 | return dd_real::_nan; 759 | } 760 | 761 | return mul_pwr2(log((1.0 + a) / (1.0 - a)), 0.5); 762 | } 763 | 764 | QD_API dd_real fmod(const dd_real &a, const dd_real &b) { 765 | dd_real n = aint(a / b); 766 | return (a - b * n); 767 | } -------------------------------------------------------------------------------- /C/dd_real.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/dd_real.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2007 9 | * 10 | * Double-double precision (>= 106-bit significand) floating point 11 | * arithmetic package based on David Bailey's Fortran-90 double-double 12 | * package, with some changes. See 13 | * 14 | * http://www.nersc.gov/~dhbailey/mpdist/mpdist.html 15 | * 16 | * for the original Fortran-90 version. 17 | * 18 | * Overall structure is similar to that of Keith Brigg's C++ double-double 19 | * package. See 20 | * 21 | * http://www-epidem.plansci.cam.ac.uk/~kbriggs/doubledouble.html 22 | * 23 | * for more details. In particular, the fix for x86 computers is borrowed 24 | * from his code. 25 | * 26 | * Yozo Hida 27 | */ 28 | 29 | #ifndef _QD_DD_REAL_H 30 | #define _QD_DD_REAL_H 31 | 32 | #include "qd_config.h" 33 | 34 | // Some compilers define isnan, isfinite, and isinf as macros, even for 35 | // C++ codes, which cause havoc when overloading these functions. We undef 36 | // them here. 37 | #ifdef isnan 38 | #undef isnan 39 | #endif 40 | 41 | #ifdef isfinite 42 | #undef isfinite 43 | #endif 44 | 45 | #ifdef isinf 46 | #undef isinf 47 | #endif 48 | 49 | #ifdef max 50 | #undef max 51 | #endif 52 | 53 | #ifdef min 54 | #undef min 55 | #endif 56 | 57 | struct dd_real { 58 | double x[2]; 59 | 60 | dd_real(double hi, double lo) { x[0] = hi; x[1] = lo; } 61 | dd_real() {x[0] = 0.0; x[1] = 0.0; } 62 | dd_real(double h) { x[0] = h; x[1] = 0.0; } 63 | dd_real(int h) { 64 | x[0] = (static_cast(h)); 65 | x[1] = 0.0; 66 | } 67 | 68 | dd_real (const char *s); 69 | explicit dd_real (const double *d) { 70 | x[0] = d[0]; x[1] = d[1]; 71 | } 72 | 73 | static void error(const char *msg); 74 | 75 | double _hi() const { return x[0]; } 76 | double _lo() const { return x[1]; } 77 | 78 | static dd_real _2pi; 79 | static dd_real _pi; 80 | static dd_real _3pi4; 81 | static dd_real _pi2; 82 | static dd_real _pi4; 83 | static dd_real _e; 84 | static dd_real _log2; 85 | static dd_real _log10; 86 | static dd_real _nan; 87 | static dd_real _inf; 88 | 89 | static const double _eps; 90 | static const double _min_normalized; 91 | static dd_real _max; 92 | static dd_real _safe_max; 93 | static const int _ndigits; 94 | 95 | static dd_real _pi16; 96 | 97 | bool isnan() const { return QD_ISNAN(x[0]) || QD_ISNAN(x[1]); } 98 | bool isfinite() const { return QD_ISFINITE(x[0]); } 99 | bool isinf() const { return QD_ISINF(x[0]); } 100 | 101 | static dd_real add(double a, double b); 102 | static dd_real ieee_add(const dd_real &a, const dd_real &b); 103 | static dd_real sloppy_add(const dd_real &a, const dd_real &b); 104 | 105 | dd_real &operator+=(double a); 106 | dd_real &operator+=(const dd_real &a); 107 | 108 | static dd_real sub(double a, double b); 109 | 110 | dd_real &operator-=(double a); 111 | dd_real &operator-=(const dd_real &a); 112 | 113 | dd_real operator-() const; 114 | 115 | static dd_real mul(double a, double b); 116 | 117 | dd_real &operator*=(double a); 118 | dd_real &operator*=(const dd_real &a); 119 | 120 | static dd_real div(double a, double b); 121 | static dd_real sloppy_div(const dd_real &a, const dd_real &b); 122 | static dd_real accurate_div(const dd_real &a, const dd_real &b); 123 | 124 | dd_real &operator/=(double a); 125 | dd_real &operator/=(const dd_real &a); 126 | 127 | dd_real &operator=(double a); 128 | dd_real &operator=(const char *s); 129 | 130 | dd_real operator^(int n); 131 | static dd_real sqr(double d); 132 | 133 | static dd_real sqrt(double a); 134 | 135 | bool is_zero() const; 136 | bool is_one() const; 137 | bool is_positive() const; 138 | bool is_negative() const; 139 | 140 | static dd_real rand(void); 141 | }; 142 | 143 | QD_API dd_real ddrand(void); 144 | QD_API dd_real sqrt(const dd_real &a); 145 | 146 | QD_API dd_real polyeval(const dd_real *c, int n, const dd_real &x); 147 | QD_API dd_real polyroot(const dd_real *c, int n, 148 | const dd_real &x0, int max_iter = 32, double thresh = 0.0); 149 | 150 | QD_API inline bool isnan(const dd_real &a) { return a.isnan(); } 151 | QD_API inline bool isfinite(const dd_real &a) { return a.isfinite(); } 152 | QD_API inline bool isinf(const dd_real &a) { return a.isinf(); } 153 | 154 | /* Computes dd * d where d is known to be a power of 2. */ 155 | QD_API dd_real mul_pwr2(const dd_real &dd, double d); 156 | 157 | QD_API dd_real operator+(const dd_real &a, double b); 158 | QD_API dd_real operator+(double a, const dd_real &b); 159 | QD_API dd_real operator+(const dd_real &a, const dd_real &b); 160 | 161 | QD_API dd_real operator-(const dd_real &a, double b); 162 | QD_API dd_real operator-(double a, const dd_real &b); 163 | QD_API dd_real operator-(const dd_real &a, const dd_real &b); 164 | 165 | QD_API dd_real operator*(const dd_real &a, double b); 166 | QD_API dd_real operator*(double a, const dd_real &b); 167 | QD_API dd_real operator*(const dd_real &a, const dd_real &b); 168 | 169 | QD_API dd_real operator/(const dd_real &a, double b); 170 | QD_API dd_real operator/(double a, const dd_real &b); 171 | QD_API dd_real operator/(const dd_real &a, const dd_real &b); 172 | 173 | QD_API dd_real inv(const dd_real &a); 174 | 175 | QD_API dd_real rem(const dd_real &a, const dd_real &b); 176 | QD_API dd_real drem(const dd_real &a, const dd_real &b); 177 | QD_API dd_real divrem(const dd_real &a, const dd_real &b, dd_real &r); 178 | 179 | QD_API dd_real pow(const dd_real &a, int n); 180 | QD_API dd_real pow(const dd_real &a, const dd_real &b); 181 | QD_API dd_real npwr(const dd_real &a, int n); 182 | QD_API dd_real sqr(const dd_real &a); 183 | 184 | QD_API dd_real sqrt(const dd_real &a); 185 | QD_API dd_real nroot(const dd_real &a, int n); 186 | 187 | QD_API bool operator==(const dd_real &a, double b); 188 | QD_API bool operator==(double a, const dd_real &b); 189 | QD_API bool operator==(const dd_real &a, const dd_real &b); 190 | 191 | QD_API bool operator<=(const dd_real &a, double b); 192 | QD_API bool operator<=(double a, const dd_real &b); 193 | QD_API bool operator<=(const dd_real &a, const dd_real &b); 194 | 195 | QD_API bool operator>=(const dd_real &a, double b); 196 | QD_API bool operator>=(double a, const dd_real &b); 197 | QD_API bool operator>=(const dd_real &a, const dd_real &b); 198 | 199 | QD_API bool operator<(const dd_real &a, double b); 200 | QD_API bool operator<(double a, const dd_real &b); 201 | QD_API bool operator<(const dd_real &a, const dd_real &b); 202 | 203 | QD_API bool operator>(const dd_real &a, double b); 204 | QD_API bool operator>(double a, const dd_real &b); 205 | QD_API bool operator>(const dd_real &a, const dd_real &b); 206 | 207 | QD_API bool operator!=(const dd_real &a, double b); 208 | QD_API bool operator!=(double a, const dd_real &b); 209 | QD_API bool operator!=(const dd_real &a, const dd_real &b); 210 | 211 | QD_API dd_real nint(const dd_real &a); 212 | QD_API dd_real floor(const dd_real &a); 213 | QD_API dd_real ceil(const dd_real &a); 214 | QD_API dd_real aint(const dd_real &a); 215 | 216 | QD_API dd_real ddrand(void); 217 | 218 | double to_double(const dd_real &a); 219 | int to_int(const dd_real &a); 220 | 221 | QD_API dd_real exp(const dd_real &a); 222 | QD_API dd_real ldexp(const dd_real &a, int exp); 223 | QD_API dd_real log(const dd_real &a); 224 | QD_API dd_real log10(const dd_real &a); 225 | 226 | QD_API dd_real sin(const dd_real &a); 227 | QD_API dd_real cos(const dd_real &a); 228 | QD_API dd_real tan(const dd_real &a); 229 | QD_API void sincos(const dd_real &a, dd_real &sin_a, dd_real &cos_a); 230 | 231 | QD_API dd_real asin(const dd_real &a); 232 | QD_API dd_real acos(const dd_real &a); 233 | QD_API dd_real atan(const dd_real &a); 234 | QD_API dd_real atan2(const dd_real &y, const dd_real &x); 235 | 236 | QD_API dd_real sinh(const dd_real &a); 237 | QD_API dd_real cosh(const dd_real &a); 238 | QD_API dd_real tanh(const dd_real &a); 239 | QD_API void sincosh(const dd_real &a, 240 | dd_real &sinh_a, dd_real &cosh_a); 241 | 242 | QD_API dd_real asinh(const dd_real &a); 243 | QD_API dd_real acosh(const dd_real &a); 244 | QD_API dd_real atanh(const dd_real &a); 245 | 246 | QD_API dd_real fabs(const dd_real &a); 247 | QD_API dd_real abs(const dd_real &a); /* same as fabs */ 248 | 249 | QD_API dd_real fmod(const dd_real &a, const dd_real &b); 250 | 251 | #ifdef QD_INLINE 252 | #include "dd_inline.h" 253 | #endif 254 | 255 | #endif /* _QD_DD_REAL_H */ 256 | 257 | -------------------------------------------------------------------------------- /C/inline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/inline.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * This file contains the basic functions used both by double-double 11 | * and quad-double package. These are declared as inline functions as 12 | * they are the smallest building blocks of the double-double and 13 | * quad-double arithmetic. 14 | */ 15 | #ifndef _QD_INLINE_H 16 | #define _QD_INLINE_H 17 | 18 | #define _QD_SPLITTER 134217729.0 // = 2^27 + 1 19 | #define _QD_SPLIT_THRESH 6.69692879491417e+299 // = 2^996 20 | 21 | #ifdef QD_VACPP_BUILTINS_H 22 | /* For VisualAge C++ __fmadd */ 23 | #include 24 | #endif 25 | 26 | #ifdef HP_ARM 27 | #include 28 | inline double qd_sqrt(double a) { 29 | return std::sqrt(a); 30 | } 31 | #else 32 | 33 | #include "xmmintrin.h" 34 | #include "immintrin.h" 35 | 36 | inline double qd_sqrt(double a) { 37 | return _mm_cvtsd_f64(_mm_sqrt_pd(_mm_set_sd(a))); 38 | } 39 | #endif 40 | 41 | extern "C" { 42 | extern double qd_ldexp(double a, int p); 43 | extern double qd_log(double a); 44 | extern double qd_log10(double a); 45 | extern double qd_exp(double a); 46 | extern double qd_atan2(double y, double x); 47 | extern double qd_nan(); 48 | extern double qd_inf(); 49 | extern double qd_floor(double a); 50 | extern double qd_ceil(double a); 51 | } 52 | 53 | namespace qd { 54 | 55 | static double _d_nan; 56 | static double _d_inf; 57 | 58 | /*********** Basic Functions ************/ 59 | /* Computes fl(a+b) and err(a+b). Assumes |a| >= |b|. */ 60 | inline double quick_two_sum(double a, double b, double &err) { 61 | double s = a + b; 62 | err = b - (s - a); 63 | return s; 64 | } 65 | 66 | /* Computes fl(a-b) and err(a-b). Assumes |a| >= |b| */ 67 | inline double quick_two_diff(double a, double b, double &err) { 68 | double s = a - b; 69 | err = (a - s) - b; 70 | return s; 71 | } 72 | 73 | /* Computes fl(a+b) and err(a+b). */ 74 | inline double two_sum(double a, double b, double &err) { 75 | double s = a + b; 76 | double bb = s - a; 77 | err = (a - (s - bb)) + (b - bb); 78 | return s; 79 | } 80 | 81 | /* Computes fl(a-b) and err(a-b). */ 82 | inline double two_diff(double a, double b, double &err) { 83 | double s = a - b; 84 | double bb = s - a; 85 | err = (a - (s - bb)) - (b + bb); 86 | return s; 87 | } 88 | 89 | #ifndef QD_FMS 90 | /* Computes high word and lo word of a */ 91 | inline void split(double a, double &hi, double &lo) { 92 | double temp; 93 | if (a > _QD_SPLIT_THRESH || a < -_QD_SPLIT_THRESH) { 94 | a *= 3.7252902984619140625e-09; // 2^-28 95 | temp = _QD_SPLITTER * a; 96 | hi = temp - (temp - a); 97 | lo = a - hi; 98 | hi *= 268435456.0; // 2^28 99 | lo *= 268435456.0; // 2^28 100 | } else { 101 | temp = _QD_SPLITTER * a; 102 | hi = temp - (temp - a); 103 | lo = a - hi; 104 | } 105 | } 106 | #endif 107 | 108 | /* Computes fl(a*b) and err(a*b). */ 109 | inline double two_prod(double a, double b, double &err) { 110 | #ifdef QD_FMS 111 | double p = a * b; 112 | err = QD_FMS(a, b, p); 113 | return p; 114 | #else 115 | double a_hi, a_lo, b_hi, b_lo; 116 | double p = a * b; 117 | split(a, a_hi, a_lo); 118 | split(b, b_hi, b_lo); 119 | err = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo; 120 | return p; 121 | #endif 122 | } 123 | 124 | /* Computes fl(a*a) and err(a*a). Faster than the above method. */ 125 | inline double two_sqr(double a, double &err) { 126 | #ifdef QD_FMS 127 | double p = a * a; 128 | err = QD_FMS(a, a, p); 129 | return p; 130 | #else 131 | double hi, lo; 132 | double q = a * a; 133 | split(a, hi, lo); 134 | err = ((hi * hi - q) + 2.0 * hi * lo) + lo * lo; 135 | return q; 136 | #endif 137 | } 138 | 139 | /* Computes the nearest integer to d. */ 140 | inline double nint(double d) { 141 | if (d == qd_floor(d)) 142 | return d; 143 | return qd_floor(d + 0.5); 144 | } 145 | 146 | /* Computes the truncated integer. */ 147 | inline double aint(double d) { 148 | return (d >= 0.0) ? qd_floor(d) : qd_ceil(d); 149 | } 150 | 151 | inline double sqr(double t) { 152 | return t * t; 153 | } 154 | 155 | inline double to_double(double a) { return a; } 156 | inline int to_int(double a) { return static_cast(a); } 157 | 158 | } 159 | 160 | #endif /* _QD_INLINE_H */ -------------------------------------------------------------------------------- /C/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir)/.. 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_CFLAGS += -Wno-absolute-value -DHP_ARM -DHP_ANDROID 6 | 7 | ifdef MP_ACCURATE 8 | LOCAL_CFLAGS += -DHP_ACCURATE 9 | endif 10 | 11 | LOCAL_MODULE := mp-android 12 | 13 | LOCAL_SRC_FILES := c_dd.cpp c_qd.cpp 14 | 15 | include $(BUILD_STATIC_LIBRARY) 16 | -------------------------------------------------------------------------------- /C/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi-v7a arm64-v8a 2 | APP_PLATFORM := android-14 3 | APP_OPTIM := release 4 | APP_STL := c++_static 5 | -------------------------------------------------------------------------------- /C/qd.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/C/qd.pdf -------------------------------------------------------------------------------- /C/qd_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _QD_QD_CONFIG_H 2 | #define _QD_QD_CONFIG_H 1 3 | 4 | #if (defined(__WIN32) || defined(__WIN64)) 5 | #if defined(__x86_64__) 6 | 7 | // Delphi uses the Microsoft calling convention on 64-bit Windows, passing parameters in RCX, RDC, R8 and R9. 8 | // By default, Clang uses the AMD64 calling convention, passing parameters in RSI, RDI, RDX and RCX. 9 | #define QD_API __attribute__((ms_abi)) 10 | 11 | #elif defined(__i386) 12 | 13 | // On 32-bit Windows, regparm(3) is identical to Delphi's "register" calling conventions. 14 | // It passes parameters in EAX, EDX and ECX 15 | #define QD_API __attribute__((regparm(3))) 16 | 17 | #endif 18 | #else 19 | 20 | #define QD_API 21 | 22 | #endif 23 | 24 | #define qd_abs(a) __builtin_abs(a) 25 | #define qd_fabs(a) __builtin_fabs(a) 26 | 27 | /* Set the following to 1 to define commonly used function 28 | to be inlined. This should be set to 1 unless the compiler 29 | does not support the "inline" keyword, or if building for 30 | debugging purposes. */ 31 | #define QD_INLINE 1 32 | 33 | #ifdef HP_ANDROID 34 | #include 35 | #define QD_ISFINITE(x) ( std::isnan(x) ) 36 | #define QD_ISINF(x) ( std::isinf(x) ) 37 | #define QD_ISNAN(x) ( std::isfinite(x) ) 38 | #else 39 | /* Define this macro to be the isfinite(x) function. */ 40 | #define QD_ISFINITE(x) ( __builtin_isfinite(x) != 0 ) 41 | 42 | /* Define this macro to be the isinf(x) function. */ 43 | #define QD_ISINF(x) ( __builtin_isinf(x) != 0 ) 44 | 45 | /* Define this macro to be the isnan(x) function. */ 46 | #define QD_ISNAN(x) ( __builtin_isnan(x) != 0 ) 47 | #endif 48 | 49 | #ifdef HP_ACCURATE 50 | #define QD_IEEE_ADD 1 51 | #else 52 | #define QD_SLOPPY_MUL 1 53 | #define QD_SLOPPY_DIV 1 54 | #endif 55 | 56 | #endif /* _QD_QD_CONFIG_H */ 57 | -------------------------------------------------------------------------------- /C/qd_const.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * src/qd_const.cc 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Defines constants used in quad-double package. 11 | */ 12 | #include "qd_config.h" 13 | #include "qd_real.h" 14 | 15 | /* Some useful constants. */ 16 | qd_real qd_real::_2pi; 17 | qd_real qd_real::_pi; 18 | qd_real qd_real::_pi2; 19 | qd_real qd_real::_pi4; 20 | qd_real qd_real::_3pi4; 21 | qd_real qd_real::_e; 22 | qd_real qd_real::_log2; 23 | qd_real qd_real::_log10; 24 | qd_real qd_real::_nan; 25 | qd_real qd_real::_inf; 26 | 27 | qd_real qd_real::_max; 28 | qd_real qd_real::_safe_max; 29 | qd_real qd_real::_pi1024; 30 | 31 | const double qd_real::_eps = 1.21543267145725e-63; // = 2^-209 32 | const double qd_real::_min_normalized = 1.6259745436952323e-260; // = 2^(-1022 + 3*53) 33 | 34 | const int qd_real::_ndigits = 62; 35 | 36 | -------------------------------------------------------------------------------- /C/qd_inline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/qd_inline.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2001 9 | * 10 | * Contains small functions (suitable for inlining) in the quad-double 11 | * arithmetic package. 12 | */ 13 | #ifndef _QD_QD_INLINE_H 14 | #define _QD_QD_INLINE_H 15 | 16 | #include "inline.h" 17 | 18 | #ifndef QD_INLINE 19 | #define inline 20 | #endif 21 | 22 | /********** Constructors **********/ 23 | inline qd_real::qd_real(double x0, double x1, double x2, double x3) { 24 | x[0] = x0; 25 | x[1] = x1; 26 | x[2] = x2; 27 | x[3] = x3; 28 | } 29 | 30 | inline qd_real::qd_real(const double *xx) { 31 | x[0] = xx[0]; 32 | x[1] = xx[1]; 33 | x[2] = xx[2]; 34 | x[3] = xx[3]; 35 | } 36 | 37 | inline qd_real::qd_real(double x0) { 38 | x[0] = x0; 39 | x[1] = x[2] = x[3] = 0.0; 40 | } 41 | 42 | inline qd_real::qd_real() { 43 | x[0] = 0.0; 44 | x[1] = 0.0; 45 | x[2] = 0.0; 46 | x[3] = 0.0; 47 | } 48 | 49 | inline qd_real::qd_real(const dd_real &a) { 50 | x[0] = a._hi(); 51 | x[1] = a._lo(); 52 | x[2] = x[3] = 0.0; 53 | } 54 | 55 | inline qd_real::qd_real(int i) { 56 | x[0] = static_cast(i); 57 | x[1] = x[2] = x[3] = 0.0; 58 | } 59 | 60 | /********** Accessors **********/ 61 | inline double qd_real::operator[](int i) const { 62 | return x[i]; 63 | } 64 | 65 | inline double &qd_real::operator[](int i) { 66 | return x[i]; 67 | } 68 | 69 | inline bool qd_real::isnan() const { 70 | return QD_ISNAN(x[0]) || QD_ISNAN(x[1]) || QD_ISNAN(x[2]) || QD_ISNAN(x[3]); 71 | } 72 | 73 | /********** Renormalization **********/ 74 | namespace qd { 75 | inline void quick_renorm(double &c0, double &c1, 76 | double &c2, double &c3, double &c4) { 77 | double t0, t1, t2, t3; 78 | double s; 79 | s = qd::quick_two_sum(c3, c4, t3); 80 | s = qd::quick_two_sum(c2, s , t2); 81 | s = qd::quick_two_sum(c1, s , t1); 82 | c0 = qd::quick_two_sum(c0, s , t0); 83 | 84 | s = qd::quick_two_sum(t2, t3, t2); 85 | s = qd::quick_two_sum(t1, s , t1); 86 | c1 = qd::quick_two_sum(t0, s , t0); 87 | 88 | s = qd::quick_two_sum(t1, t2, t1); 89 | c2 = qd::quick_two_sum(t0, s , t0); 90 | 91 | c3 = t0 + t1; 92 | } 93 | 94 | inline void renorm(double &c0, double &c1, 95 | double &c2, double &c3) { 96 | double s0, s1, s2 = 0.0, s3 = 0.0; 97 | 98 | if (QD_ISINF(c0)) return; 99 | 100 | s0 = qd::quick_two_sum(c2, c3, c3); 101 | s0 = qd::quick_two_sum(c1, s0, c2); 102 | c0 = qd::quick_two_sum(c0, s0, c1); 103 | 104 | s0 = c0; 105 | s1 = c1; 106 | if (s1 != 0.0) { 107 | s1 = qd::quick_two_sum(s1, c2, s2); 108 | if (s2 != 0.0) 109 | s2 = qd::quick_two_sum(s2, c3, s3); 110 | else 111 | s1 = qd::quick_two_sum(s1, c3, s2); 112 | } else { 113 | s0 = qd::quick_two_sum(s0, c2, s1); 114 | if (s1 != 0.0) 115 | s1 = qd::quick_two_sum(s1, c3, s2); 116 | else 117 | s0 = qd::quick_two_sum(s0, c3, s1); 118 | } 119 | 120 | c0 = s0; 121 | c1 = s1; 122 | c2 = s2; 123 | c3 = s3; 124 | } 125 | 126 | inline void renorm(double &c0, double &c1, 127 | double &c2, double &c3, double &c4) { 128 | double s0, s1, s2 = 0.0, s3 = 0.0; 129 | 130 | if (QD_ISINF(c0)) return; 131 | 132 | s0 = qd::quick_two_sum(c3, c4, c4); 133 | s0 = qd::quick_two_sum(c2, s0, c3); 134 | s0 = qd::quick_two_sum(c1, s0, c2); 135 | c0 = qd::quick_two_sum(c0, s0, c1); 136 | 137 | s0 = c0; 138 | s1 = c1; 139 | 140 | if (s1 != 0.0) { 141 | s1 = qd::quick_two_sum(s1, c2, s2); 142 | if (s2 != 0.0) { 143 | s2 = qd::quick_two_sum(s2, c3, s3); 144 | if (s3 != 0.0) 145 | s3 += c4; 146 | else 147 | s2 = qd::quick_two_sum(s2, c4, s3); 148 | } else { 149 | s1 = qd::quick_two_sum(s1, c3, s2); 150 | if (s2 != 0.0) 151 | s2 = qd::quick_two_sum(s2, c4, s3); 152 | else 153 | s1 = qd::quick_two_sum(s1, c4, s2); 154 | } 155 | } else { 156 | s0 = qd::quick_two_sum(s0, c2, s1); 157 | if (s1 != 0.0) { 158 | s1 = qd::quick_two_sum(s1, c3, s2); 159 | if (s2 != 0.0) 160 | s2 = qd::quick_two_sum(s2, c4, s3); 161 | else 162 | s1 = qd::quick_two_sum(s1, c4, s2); 163 | } else { 164 | s0 = qd::quick_two_sum(s0, c3, s1); 165 | if (s1 != 0.0) 166 | s1 = qd::quick_two_sum(s1, c4, s2); 167 | else 168 | s0 = qd::quick_two_sum(s0, c4, s1); 169 | } 170 | } 171 | 172 | c0 = s0; 173 | c1 = s1; 174 | c2 = s2; 175 | c3 = s3; 176 | } 177 | } 178 | 179 | inline void qd_real::renorm() { 180 | qd::renorm(x[0], x[1], x[2], x[3]); 181 | } 182 | 183 | inline void qd_real::renorm(double &e) { 184 | qd::renorm(x[0], x[1], x[2], x[3], e); 185 | } 186 | 187 | 188 | /********** Additions ************/ 189 | namespace qd { 190 | 191 | inline void three_sum(double &a, double &b, double &c) { 192 | double t1, t2, t3; 193 | t1 = qd::two_sum(a, b, t2); 194 | a = qd::two_sum(c, t1, t3); 195 | b = qd::two_sum(t2, t3, c); 196 | } 197 | 198 | inline void three_sum2(double &a, double &b, double &c) { 199 | double t1, t2, t3; 200 | t1 = qd::two_sum(a, b, t2); 201 | a = qd::two_sum(c, t1, t3); 202 | b = t2 + t3; 203 | } 204 | 205 | } 206 | 207 | /* quad-double + double */ 208 | inline qd_real operator+(const qd_real &a, double b) { 209 | double c0, c1, c2, c3; 210 | double e; 211 | 212 | c0 = qd::two_sum(a[0], b, e); 213 | c1 = qd::two_sum(a[1], e, e); 214 | c2 = qd::two_sum(a[2], e, e); 215 | c3 = qd::two_sum(a[3], e, e); 216 | 217 | qd::renorm(c0, c1, c2, c3, e); 218 | 219 | return qd_real(c0, c1, c2, c3); 220 | } 221 | 222 | /* quad-double + double-double */ 223 | inline qd_real operator+(const qd_real &a, const dd_real &b) { 224 | 225 | double s0, s1, s2, s3; 226 | double t0, t1; 227 | 228 | s0 = qd::two_sum(a[0], b._hi(), t0); 229 | s1 = qd::two_sum(a[1], b._lo(), t1); 230 | 231 | s1 = qd::two_sum(s1, t0, t0); 232 | 233 | s2 = a[2]; 234 | qd::three_sum(s2, t0, t1); 235 | 236 | s3 = qd::two_sum(t0, a[3], t0); 237 | t0 += t1; 238 | 239 | qd::renorm(s0, s1, s2, s3, t0); 240 | return qd_real(s0, s1, s2, s3); 241 | } 242 | 243 | 244 | /* double + quad-double */ 245 | inline qd_real operator+(double a, const qd_real &b) { 246 | return (b + a); 247 | } 248 | 249 | /* double-double + quad-double */ 250 | inline qd_real operator+(const dd_real &a, const qd_real &b) { 251 | return (b + a); 252 | } 253 | 254 | namespace qd { 255 | 256 | /* s = quick_three_accum(a, b, c) adds c to the dd-pair (a, b). 257 | * If the result does not fit in two doubles, then the sum is 258 | * output into s and (a,b) contains the remainder. Otherwise 259 | * s is zero and (a,b) contains the sum. */ 260 | inline double quick_three_accum(double &a, double &b, double c) { 261 | double s; 262 | bool za, zb; 263 | 264 | s = qd::two_sum(b, c, b); 265 | s = qd::two_sum(a, s, a); 266 | 267 | za = (a != 0.0); 268 | zb = (b != 0.0); 269 | 270 | if (za && zb) 271 | return s; 272 | 273 | if (!zb) { 274 | b = a; 275 | a = s; 276 | } else { 277 | a = s; 278 | } 279 | 280 | return 0.0; 281 | } 282 | 283 | } 284 | 285 | inline qd_real qd_real::ieee_add(const qd_real &a, const qd_real &b) { 286 | int i, j, k; 287 | double s, t; 288 | double u, v; /* double-length accumulator */ 289 | double x[4] = {0.0, 0.0, 0.0, 0.0}; 290 | 291 | i = j = k = 0; 292 | if (qd_fabs(a[i]) > qd_fabs(b[j])) 293 | u = a[i++]; 294 | else 295 | u = b[j++]; 296 | if (qd_fabs(a[i]) > qd_fabs(b[j])) 297 | v = a[i++]; 298 | else 299 | v = b[j++]; 300 | 301 | u = qd::quick_two_sum(u, v, v); 302 | 303 | while (k < 4) { 304 | if (i >= 4 && j >= 4) { 305 | x[k] = u; 306 | if (k < 3) 307 | x[++k] = v; 308 | break; 309 | } 310 | 311 | if (i >= 4) 312 | t = b[j++]; 313 | else if (j >= 4) 314 | t = a[i++]; 315 | else if (qd_fabs(a[i]) > qd_fabs(b[j])) { 316 | t = a[i++]; 317 | } else 318 | t = b[j++]; 319 | 320 | s = qd::quick_three_accum(u, v, t); 321 | 322 | if (s != 0.0) { 323 | x[k++] = s; 324 | } 325 | } 326 | 327 | /* add the rest. */ 328 | for (k = i; k < 4; k++) 329 | x[3] += a[k]; 330 | for (k = j; k < 4; k++) 331 | x[3] += b[k]; 332 | 333 | qd::renorm(x[0], x[1], x[2], x[3]); 334 | return qd_real(x[0], x[1], x[2], x[3]); 335 | } 336 | 337 | inline qd_real qd_real::sloppy_add(const qd_real &a, const qd_real &b) { 338 | /* 339 | double s0, s1, s2, s3; 340 | double t0, t1, t2, t3; 341 | 342 | s0 = qd::two_sum(a[0], b[0], t0); 343 | s1 = qd::two_sum(a[1], b[1], t1); 344 | s2 = qd::two_sum(a[2], b[2], t2); 345 | s3 = qd::two_sum(a[3], b[3], t3); 346 | 347 | s1 = qd::two_sum(s1, t0, t0); 348 | qd::three_sum(s2, t0, t1); 349 | qd::three_sum2(s3, t0, t2); 350 | t0 = t0 + t1 + t3; 351 | 352 | qd::renorm(s0, s1, s2, s3, t0); 353 | return qd_real(s0, s1, s2, s3, t0); 354 | */ 355 | 356 | /* Same as above, but addition re-organized to minimize 357 | data dependency ... unfortunately some compilers are 358 | not very smart to do this automatically */ 359 | double s0, s1, s2, s3; 360 | double t0, t1, t2, t3; 361 | 362 | double v0, v1, v2, v3; 363 | double u0, u1, u2, u3; 364 | double w0, w1, w2, w3; 365 | 366 | s0 = a[0] + b[0]; 367 | s1 = a[1] + b[1]; 368 | s2 = a[2] + b[2]; 369 | s3 = a[3] + b[3]; 370 | 371 | v0 = s0 - a[0]; 372 | v1 = s1 - a[1]; 373 | v2 = s2 - a[2]; 374 | v3 = s3 - a[3]; 375 | 376 | u0 = s0 - v0; 377 | u1 = s1 - v1; 378 | u2 = s2 - v2; 379 | u3 = s3 - v3; 380 | 381 | w0 = a[0] - u0; 382 | w1 = a[1] - u1; 383 | w2 = a[2] - u2; 384 | w3 = a[3] - u3; 385 | 386 | u0 = b[0] - v0; 387 | u1 = b[1] - v1; 388 | u2 = b[2] - v2; 389 | u3 = b[3] - v3; 390 | 391 | t0 = w0 + u0; 392 | t1 = w1 + u1; 393 | t2 = w2 + u2; 394 | t3 = w3 + u3; 395 | 396 | s1 = qd::two_sum(s1, t0, t0); 397 | qd::three_sum(s2, t0, t1); 398 | qd::three_sum2(s3, t0, t2); 399 | t0 = t0 + t1 + t3; 400 | 401 | /* renormalize */ 402 | qd::renorm(s0, s1, s2, s3, t0); 403 | return qd_real(s0, s1, s2, s3); 404 | } 405 | 406 | /* quad-double + quad-double */ 407 | inline qd_real operator+(const qd_real &a, const qd_real &b) { 408 | #ifndef QD_IEEE_ADD 409 | return qd_real::sloppy_add(a, b); 410 | #else 411 | return qd_real::ieee_add(a, b); 412 | #endif 413 | } 414 | 415 | 416 | 417 | /********** Self-Additions ************/ 418 | /* quad-double += double */ 419 | inline qd_real &qd_real::operator+=(double a) { 420 | *this = *this + a; 421 | return *this; 422 | } 423 | 424 | /* quad-double += double-double */ 425 | inline qd_real &qd_real::operator+=(const dd_real &a) { 426 | *this = *this + a; 427 | return *this; 428 | } 429 | 430 | /* quad-double += quad-double */ 431 | inline qd_real &qd_real::operator+=(const qd_real &a) { 432 | *this = *this + a; 433 | return *this; 434 | } 435 | 436 | /********** Unary Minus **********/ 437 | inline qd_real qd_real::operator-() const { 438 | return qd_real(-x[0], -x[1], -x[2], -x[3]); 439 | } 440 | 441 | /********** Subtractions **********/ 442 | inline qd_real operator-(const qd_real &a, double b) { 443 | return (a + (-b)); 444 | } 445 | 446 | inline qd_real operator-(double a, const qd_real &b) { 447 | return (a + (-b)); 448 | } 449 | 450 | inline qd_real operator-(const qd_real &a, const dd_real &b) { 451 | return (a + (-b)); 452 | } 453 | 454 | inline qd_real operator-(const dd_real &a, const qd_real &b) { 455 | return (a + (-b)); 456 | } 457 | 458 | inline qd_real operator-(const qd_real &a, const qd_real &b) { 459 | return (a + (-b)); 460 | } 461 | 462 | /********** Self-Subtractions **********/ 463 | inline qd_real &qd_real::operator-=(double a) { 464 | return ((*this) += (-a)); 465 | } 466 | 467 | inline qd_real &qd_real::operator-=(const dd_real &a) { 468 | return ((*this) += (-a)); 469 | } 470 | 471 | inline qd_real &qd_real::operator-=(const qd_real &a) { 472 | return ((*this) += (-a)); 473 | } 474 | 475 | 476 | inline qd_real operator*(double a, const qd_real &b) { 477 | return (b * a); 478 | } 479 | 480 | inline qd_real operator*(const dd_real &a, const qd_real &b) { 481 | return (b * a); 482 | } 483 | 484 | inline qd_real mul_pwr2(const qd_real &a, double b) { 485 | return qd_real(a[0] * b, a[1] * b, a[2] * b, a[3] * b); 486 | } 487 | 488 | /********** Multiplications **********/ 489 | inline qd_real operator*(const qd_real &a, double b) { 490 | double p0, p1, p2, p3; 491 | double q0, q1, q2; 492 | double s0, s1, s2, s3, s4; 493 | 494 | p0 = qd::two_prod(a[0], b, q0); 495 | p1 = qd::two_prod(a[1], b, q1); 496 | p2 = qd::two_prod(a[2], b, q2); 497 | p3 = a[3] * b; 498 | 499 | s0 = p0; 500 | 501 | s1 = qd::two_sum(q0, p1, s2); 502 | 503 | qd::three_sum(s2, q1, p2); 504 | 505 | qd::three_sum2(q1, q2, p3); 506 | s3 = q1; 507 | 508 | s4 = q2 + p2; 509 | 510 | qd::renorm(s0, s1, s2, s3, s4); 511 | return qd_real(s0, s1, s2, s3); 512 | 513 | } 514 | 515 | /* quad-double * double-double */ 516 | /* a0 * b0 0 517 | a0 * b1 1 518 | a1 * b0 2 519 | a1 * b1 3 520 | a2 * b0 4 521 | a2 * b1 5 522 | a3 * b0 6 523 | a3 * b1 7 */ 524 | inline qd_real operator*(const qd_real &a, const dd_real &b) { 525 | double p0, p1, p2, p3, p4; 526 | double q0, q1, q2, q3, q4; 527 | double s0, s1, s2; 528 | double t0, t1; 529 | 530 | p0 = qd::two_prod(a[0], b._hi(), q0); 531 | p1 = qd::two_prod(a[0], b._lo(), q1); 532 | p2 = qd::two_prod(a[1], b._hi(), q2); 533 | p3 = qd::two_prod(a[1], b._lo(), q3); 534 | p4 = qd::two_prod(a[2], b._hi(), q4); 535 | 536 | qd::three_sum(p1, p2, q0); 537 | 538 | /* Five-Three-Sum */ 539 | qd::three_sum(p2, p3, p4); 540 | q1 = qd::two_sum(q1, q2, q2); 541 | s0 = qd::two_sum(p2, q1, t0); 542 | s1 = qd::two_sum(p3, q2, t1); 543 | s1 = qd::two_sum(s1, t0, t0); 544 | s2 = t0 + t1 + p4; 545 | p2 = s0; 546 | 547 | p3 = a[2] * b._hi() + a[3] * b._lo() + q3 + q4; 548 | qd::three_sum2(p3, q0, s1); 549 | p4 = q0 + s2; 550 | 551 | qd::renorm(p0, p1, p2, p3, p4); 552 | return qd_real(p0, p1, p2, p3); 553 | } 554 | 555 | /* quad-double * quad-double */ 556 | /* a0 * b0 0 557 | a0 * b1 1 558 | a1 * b0 2 559 | a0 * b2 3 560 | a1 * b1 4 561 | a2 * b0 5 562 | a0 * b3 6 563 | a1 * b2 7 564 | a2 * b1 8 565 | a3 * b0 9 */ 566 | inline qd_real qd_real::sloppy_mul(const qd_real &a, const qd_real &b) { 567 | double p0, p1, p2, p3, p4, p5; 568 | double q0, q1, q2, q3, q4, q5; 569 | double t0, t1; 570 | double s0, s1, s2; 571 | 572 | p0 = qd::two_prod(a[0], b[0], q0); 573 | 574 | p1 = qd::two_prod(a[0], b[1], q1); 575 | p2 = qd::two_prod(a[1], b[0], q2); 576 | 577 | p3 = qd::two_prod(a[0], b[2], q3); 578 | p4 = qd::two_prod(a[1], b[1], q4); 579 | p5 = qd::two_prod(a[2], b[0], q5); 580 | 581 | /* Start Accumulation */ 582 | qd::three_sum(p1, p2, q0); 583 | 584 | /* Six-Three Sum of p2, q1, q2, p3, p4, p5. */ 585 | qd::three_sum(p2, q1, q2); 586 | qd::three_sum(p3, p4, p5); 587 | /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */ 588 | s0 = qd::two_sum(p2, p3, t0); 589 | s1 = qd::two_sum(q1, p4, t1); 590 | s2 = q2 + p5; 591 | s1 = qd::two_sum(s1, t0, t0); 592 | s2 += (t0 + t1); 593 | 594 | /* O(eps^3) order terms */ 595 | s1 += a[0]*b[3] + a[1]*b[2] + a[2]*b[1] + a[3]*b[0] + q0 + q3 + q4 + q5; 596 | qd::renorm(p0, p1, s0, s1, s2); 597 | return qd_real(p0, p1, s0, s1); 598 | } 599 | 600 | inline qd_real qd_real::accurate_mul(const qd_real &a, const qd_real &b) { 601 | double p0, p1, p2, p3, p4, p5; 602 | double q0, q1, q2, q3, q4, q5; 603 | double p6, p7, p8, p9; 604 | double q6, q7, q8, q9; 605 | double r0, r1; 606 | double t0, t1; 607 | double s0, s1, s2; 608 | 609 | p0 = qd::two_prod(a[0], b[0], q0); 610 | 611 | p1 = qd::two_prod(a[0], b[1], q1); 612 | p2 = qd::two_prod(a[1], b[0], q2); 613 | 614 | p3 = qd::two_prod(a[0], b[2], q3); 615 | p4 = qd::two_prod(a[1], b[1], q4); 616 | p5 = qd::two_prod(a[2], b[0], q5); 617 | 618 | /* Start Accumulation */ 619 | qd::three_sum(p1, p2, q0); 620 | 621 | /* Six-Three Sum of p2, q1, q2, p3, p4, p5. */ 622 | qd::three_sum(p2, q1, q2); 623 | qd::three_sum(p3, p4, p5); 624 | /* compute (s0, s1, s2) = (p2, q1, q2) + (p3, p4, p5). */ 625 | s0 = qd::two_sum(p2, p3, t0); 626 | s1 = qd::two_sum(q1, p4, t1); 627 | s2 = q2 + p5; 628 | s1 = qd::two_sum(s1, t0, t0); 629 | s2 += (t0 + t1); 630 | 631 | /* O(eps^3) order terms */ 632 | p6 = qd::two_prod(a[0], b[3], q6); 633 | p7 = qd::two_prod(a[1], b[2], q7); 634 | p8 = qd::two_prod(a[2], b[1], q8); 635 | p9 = qd::two_prod(a[3], b[0], q9); 636 | 637 | /* Nine-Two-Sum of q0, s1, q3, q4, q5, p6, p7, p8, p9. */ 638 | q0 = qd::two_sum(q0, q3, q3); 639 | q4 = qd::two_sum(q4, q5, q5); 640 | p6 = qd::two_sum(p6, p7, p7); 641 | p8 = qd::two_sum(p8, p9, p9); 642 | /* Compute (t0, t1) = (q0, q3) + (q4, q5). */ 643 | t0 = qd::two_sum(q0, q4, t1); 644 | t1 += (q3 + q5); 645 | /* Compute (r0, r1) = (p6, p7) + (p8, p9). */ 646 | r0 = qd::two_sum(p6, p8, r1); 647 | r1 += (p7 + p9); 648 | /* Compute (q3, q4) = (t0, t1) + (r0, r1). */ 649 | q3 = qd::two_sum(t0, r0, q4); 650 | q4 += (t1 + r1); 651 | /* Compute (t0, t1) = (q3, q4) + s1. */ 652 | t0 = qd::two_sum(q3, s1, t1); 653 | t1 += q4; 654 | 655 | /* O(eps^4) terms -- Nine-One-Sum */ 656 | t1 += a[1] * b[3] + a[2] * b[2] + a[3] * b[1] + q6 + q7 + q8 + q9 + s2; 657 | 658 | qd::renorm(p0, p1, s0, t0, t1); 659 | return qd_real(p0, p1, s0, t0); 660 | } 661 | 662 | inline qd_real operator*(const qd_real &a, const qd_real &b) { 663 | #ifdef QD_SLOPPY_MUL 664 | return qd_real::sloppy_mul(a, b); 665 | #else 666 | return qd_real::accurate_mul(a, b); 667 | #endif 668 | } 669 | 670 | /* quad-double ^ 2 = (x0 + x1 + x2 + x3) ^ 2 671 | = x0 ^ 2 + 2 x0 * x1 + (2 x0 * x2 + x1 ^ 2) 672 | + (2 x0 * x3 + 2 x1 * x2) */ 673 | inline qd_real sqr(const qd_real &a) { 674 | double p0, p1, p2, p3, p4, p5; 675 | double q0, q1, q2, q3; 676 | double s0, s1; 677 | double t0, t1; 678 | 679 | p0 = qd::two_sqr(a[0], q0); 680 | p1 = qd::two_prod(2.0 * a[0], a[1], q1); 681 | p2 = qd::two_prod(2.0 * a[0], a[2], q2); 682 | p3 = qd::two_sqr(a[1], q3); 683 | 684 | p1 = qd::two_sum(q0, p1, q0); 685 | 686 | q0 = qd::two_sum(q0, q1, q1); 687 | p2 = qd::two_sum(p2, p3, p3); 688 | 689 | s0 = qd::two_sum(q0, p2, t0); 690 | s1 = qd::two_sum(q1, p3, t1); 691 | 692 | s1 = qd::two_sum(s1, t0, t0); 693 | t0 += t1; 694 | 695 | s1 = qd::quick_two_sum(s1, t0, t0); 696 | p2 = qd::quick_two_sum(s0, s1, t1); 697 | p3 = qd::quick_two_sum(t1, t0, q0); 698 | 699 | p4 = 2.0 * a[0] * a[3]; 700 | p5 = 2.0 * a[1] * a[2]; 701 | 702 | p4 = qd::two_sum(p4, p5, p5); 703 | q2 = qd::two_sum(q2, q3, q3); 704 | 705 | t0 = qd::two_sum(p4, q2, t1); 706 | t1 = t1 + p5 + q3; 707 | 708 | p3 = qd::two_sum(p3, t0, p4); 709 | p4 = p4 + q0 + t1; 710 | 711 | qd::renorm(p0, p1, p2, p3, p4); 712 | return qd_real(p0, p1, p2, p3); 713 | 714 | } 715 | 716 | /********** Self-Multiplication **********/ 717 | /* quad-double *= double */ 718 | inline qd_real &qd_real::operator*=(double a) { 719 | *this = (*this * a); 720 | return *this; 721 | } 722 | 723 | /* quad-double *= double-double */ 724 | inline qd_real &qd_real::operator*=(const dd_real &a) { 725 | *this = (*this * a); 726 | return *this; 727 | } 728 | 729 | /* quad-double *= quad-double */ 730 | inline qd_real &qd_real::operator*=(const qd_real &a) { 731 | *this = *this * a; 732 | return *this; 733 | } 734 | 735 | inline qd_real operator/ (const qd_real &a, const dd_real &b) { 736 | #ifdef QD_SLOPPY_DIV 737 | return qd_real::sloppy_div(a, b); 738 | #else 739 | return qd_real::accurate_div(a, b); 740 | #endif 741 | } 742 | 743 | inline qd_real operator/(const qd_real &a, const qd_real &b) { 744 | #ifdef QD_SLOPPY_DIV 745 | return qd_real::sloppy_div(a, b); 746 | #else 747 | return qd_real::accurate_div(a, b); 748 | #endif 749 | } 750 | 751 | /* double / quad-double */ 752 | inline qd_real operator/(double a, const qd_real &b) { 753 | return qd_real(a) / b; 754 | } 755 | 756 | /* double-double / quad-double */ 757 | inline qd_real operator/(const dd_real &a, const qd_real &b) { 758 | return qd_real(a) / b; 759 | } 760 | 761 | /********** Self-Divisions **********/ 762 | /* quad-double /= double */ 763 | inline qd_real &qd_real::operator/=(double a) { 764 | *this = (*this / a); 765 | return *this; 766 | } 767 | 768 | /* quad-double /= double-double */ 769 | inline qd_real &qd_real::operator/=(const dd_real &a) { 770 | *this = (*this / a); 771 | return *this; 772 | } 773 | 774 | /* quad-double /= quad-double */ 775 | inline qd_real &qd_real::operator/=(const qd_real &a) { 776 | *this = (*this / a); 777 | return *this; 778 | } 779 | 780 | 781 | /********** Exponentiation **********/ 782 | inline qd_real qd_real::operator^(int n) const { 783 | return pow(*this, n); 784 | } 785 | 786 | /********** Miscellaneous **********/ 787 | inline qd_real abs(const qd_real &a) { 788 | return (a[0] < 0.0) ? -a : a; 789 | } 790 | 791 | inline qd_real fabs(const qd_real &a) { 792 | return abs(a); 793 | } 794 | 795 | /* Quick version. May be off by one when qd is very close 796 | to the middle of two integers. */ 797 | inline qd_real quick_nint(const qd_real &a) { 798 | qd_real r = qd_real(qd::nint(a[0]), qd::nint(a[1]), 799 | qd::nint(a[2]), qd::nint(a[3])); 800 | r.renorm(); 801 | return r; 802 | } 803 | 804 | /*********** Assignments ************/ 805 | /* quad-double = double */ 806 | inline qd_real &qd_real::operator=(double a) { 807 | x[0] = a; 808 | x[1] = x[2] = x[3] = 0.0; 809 | return *this; 810 | } 811 | 812 | /* quad-double = double-double */ 813 | inline qd_real &qd_real::operator=(const dd_real &a) { 814 | x[0] = a._hi(); 815 | x[1] = a._lo(); 816 | x[2] = x[3] = 0.0; 817 | return *this; 818 | } 819 | 820 | /********** Equality Comparison **********/ 821 | inline bool operator==(const qd_real &a, double b) { 822 | return (a[0] == b && a[1] == 0.0 && a[2] == 0.0 && a[3] == 0.0); 823 | } 824 | 825 | inline bool operator==(double a, const qd_real &b) { 826 | return (b == a); 827 | } 828 | 829 | inline bool operator==(const qd_real &a, const dd_real &b) { 830 | return (a[0] == b._hi() && a[1] == b._lo() && 831 | a[2] == 0.0 && a[3] == 0.0); 832 | } 833 | 834 | inline bool operator==(const dd_real &a, const qd_real &b) { 835 | return (b == a); 836 | } 837 | 838 | inline bool operator==(const qd_real &a, const qd_real &b) { 839 | return (a[0] == b[0] && a[1] == b[1] && 840 | a[2] == b[2] && a[3] == b[3]); 841 | } 842 | 843 | 844 | /********** Less-Than Comparison ***********/ 845 | inline bool operator<(const qd_real &a, double b) { 846 | return (a[0] < b || (a[0] == b && a[1] < 0.0)); 847 | } 848 | 849 | inline bool operator<(double a, const qd_real &b) { 850 | return (b > a); 851 | } 852 | 853 | inline bool operator<(const qd_real &a, const dd_real &b) { 854 | return (a[0] < b._hi() || 855 | (a[0] == b._hi() && (a[1] < b._lo() || 856 | (a[1] == b._lo() && a[2] < 0.0)))); 857 | } 858 | 859 | inline bool operator<(const dd_real &a, const qd_real &b) { 860 | return (b > a); 861 | } 862 | 863 | inline bool operator<(const qd_real &a, const qd_real &b) { 864 | return (a[0] < b[0] || 865 | (a[0] == b[0] && (a[1] < b[1] || 866 | (a[1] == b[1] && (a[2] < b[2] || 867 | (a[2] == b[2] && a[3] < b[3])))))); 868 | } 869 | 870 | /********** Greater-Than Comparison ***********/ 871 | inline bool operator>(const qd_real &a, double b) { 872 | return (a[0] > b || (a[0] == b && a[1] > 0.0)); 873 | } 874 | 875 | inline bool operator>(double a, const qd_real &b) { 876 | return (b < a); 877 | } 878 | 879 | inline bool operator>(const qd_real &a, const dd_real &b) { 880 | return (a[0] > b._hi() || 881 | (a[0] == b._hi() && (a[1] > b._lo() || 882 | (a[1] == b._lo() && a[2] > 0.0)))); 883 | } 884 | 885 | inline bool operator>(const dd_real &a, const qd_real &b) { 886 | return (b < a); 887 | } 888 | 889 | inline bool operator>(const qd_real &a, const qd_real &b) { 890 | return (a[0] > b[0] || 891 | (a[0] == b[0] && (a[1] > b[1] || 892 | (a[1] == b[1] && (a[2] > b[2] || 893 | (a[2] == b[2] && a[3] > b[3])))))); 894 | } 895 | 896 | 897 | /********** Less-Than-Or-Equal-To Comparison **********/ 898 | inline bool operator<=(const qd_real &a, double b) { 899 | return (a[0] < b || (a[0] == b && a[1] <= 0.0)); 900 | } 901 | 902 | inline bool operator<=(double a, const qd_real &b) { 903 | return (b >= a); 904 | } 905 | 906 | inline bool operator<=(const qd_real &a, const dd_real &b) { 907 | return (a[0] < b._hi() || 908 | (a[0] == b._hi() && (a[1] < b._lo() || 909 | (a[1] == b._lo() && a[2] <= 0.0)))); 910 | } 911 | 912 | inline bool operator<=(const dd_real &a, const qd_real &b) { 913 | return (b >= a); 914 | } 915 | 916 | inline bool operator<=(const qd_real &a, const qd_real &b) { 917 | return (a[0] < b[0] || 918 | (a[0] == b[0] && (a[1] < b[1] || 919 | (a[1] == b[1] && (a[2] < b[2] || 920 | (a[2] == b[2] && a[3] <= b[3])))))); 921 | } 922 | 923 | /********** Greater-Than-Or-Equal-To Comparison **********/ 924 | inline bool operator>=(const qd_real &a, double b) { 925 | return (a[0] > b || (a[0] == b && a[1] >= 0.0)); 926 | } 927 | 928 | inline bool operator>=(double a, const qd_real &b) { 929 | return (b <= a); 930 | } 931 | 932 | inline bool operator>=(const qd_real &a, const dd_real &b) { 933 | return (a[0] > b._hi() || 934 | (a[0] == b._hi() && (a[1] > b._lo() || 935 | (a[1] == b._lo() && a[2] >= 0.0)))); 936 | } 937 | 938 | inline bool operator>=(const dd_real &a, const qd_real &b) { 939 | return (b <= a); 940 | } 941 | 942 | inline bool operator>=(const qd_real &a, const qd_real &b) { 943 | return (a[0] > b[0] || 944 | (a[0] == b[0] && (a[1] > b[1] || 945 | (a[1] == b[1] && (a[2] > b[2] || 946 | (a[2] == b[2] && a[3] >= b[3])))))); 947 | } 948 | 949 | 950 | 951 | /********** Not-Equal-To Comparison **********/ 952 | inline bool operator!=(const qd_real &a, double b) { 953 | return !(a == b); 954 | } 955 | 956 | inline bool operator!=(double a, const qd_real &b) { 957 | return !(a == b); 958 | } 959 | 960 | inline bool operator!=(const qd_real &a, const dd_real &b) { 961 | return !(a == b); 962 | } 963 | 964 | inline bool operator!=(const dd_real &a, const qd_real &b) { 965 | return !(a == b); 966 | } 967 | 968 | inline bool operator!=(const qd_real &a, const qd_real &b) { 969 | return !(a == b); 970 | } 971 | 972 | 973 | 974 | inline qd_real aint(const qd_real &a) { 975 | return (a[0] >= 0) ? floor(a) : ceil(a); 976 | } 977 | 978 | inline bool qd_real::is_zero() const { 979 | return (x[0] == 0.0); 980 | } 981 | 982 | inline bool qd_real::is_one() const { 983 | return (x[0] == 1.0 && x[1] == 0.0 && x[2] == 0.0 && x[3] == 0.0); 984 | } 985 | 986 | inline bool qd_real::is_positive() const { 987 | return (x[0] > 0.0); 988 | } 989 | 990 | inline bool qd_real::is_negative() const { 991 | return (x[0] < 0.0); 992 | } 993 | 994 | inline dd_real to_dd_real(const qd_real &a) { 995 | return dd_real(a[0], a[1]); 996 | } 997 | 998 | inline double to_double(const qd_real &a) { 999 | return a[0]; 1000 | } 1001 | 1002 | inline int to_int(const qd_real &a) { 1003 | return static_cast(a[0]); 1004 | } 1005 | 1006 | inline qd_real inv(const qd_real &qd) { 1007 | return 1.0 / qd; 1008 | } 1009 | 1010 | inline qd_real max(const qd_real &a, const qd_real &b) { 1011 | return (a > b) ? a : b; 1012 | } 1013 | 1014 | inline qd_real max(const qd_real &a, const qd_real &b, 1015 | const qd_real &c) { 1016 | return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); 1017 | } 1018 | 1019 | inline qd_real min(const qd_real &a, const qd_real &b) { 1020 | return (a < b) ? a : b; 1021 | } 1022 | 1023 | inline qd_real min(const qd_real &a, const qd_real &b, 1024 | const qd_real &c) { 1025 | return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); 1026 | } 1027 | 1028 | inline qd_real ldexp(const qd_real &a, int n) { 1029 | return qd_real(qd_ldexp(a[0], n), qd_ldexp(a[1], n), 1030 | qd_ldexp(a[2], n), qd_ldexp(a[3], n)); 1031 | } 1032 | 1033 | #endif /* _QD_QD_INLINE_H */ 1034 | -------------------------------------------------------------------------------- /C/qd_real.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include/qd_real.h 3 | * 4 | * This work was supported by the Director, Office of Science, Division 5 | * of Mathematical, Information, and Computational Sciences of the 6 | * U.S. Department of Energy under contract number DE-AC03-76SF00098. 7 | * 8 | * Copyright (c) 2000-2007 9 | * 10 | * Quad-double precision (>= 212-bit significand) floating point arithmetic 11 | * package, written in ANSI C++, taking full advantage of operator overloading. 12 | * Uses similar techniques as that of David Bailey's double-double package 13 | * and that of Jonathan Shewchuk's adaptive precision floating point 14 | * arithmetic package. See 15 | * 16 | * http://www.nersc.gov/~dhbailey/mpdist/mpdist.html 17 | * http://www.cs.cmu.edu/~quake/robust.html 18 | * 19 | * for more details. 20 | * 21 | * Yozo Hida 22 | */ 23 | #ifndef _QD_QD_REAL_H 24 | #define _QD_QD_REAL_H 25 | 26 | #include "qd_config.h" 27 | #include "dd_real.h" 28 | 29 | struct qd_real { 30 | double x[4]; /* The Components. */ 31 | 32 | /* Eliminates any zeros in the middle component(s). */ 33 | void zero_elim(); 34 | void zero_elim(double &e); 35 | 36 | void renorm(); 37 | void renorm(double &e); 38 | 39 | void quick_accum(double d, double &e); 40 | void quick_prod_accum(double a, double b, double &e); 41 | 42 | qd_real(double x0, double x1, double x2, double x3); 43 | explicit qd_real(const double *xx); 44 | 45 | static qd_real _2pi; 46 | static qd_real _pi; 47 | static qd_real _3pi4; 48 | static qd_real _pi2; 49 | static qd_real _pi4; 50 | static qd_real _e; 51 | static qd_real _log2; 52 | static qd_real _log10; 53 | static qd_real _nan; 54 | static qd_real _inf; 55 | 56 | static const double _eps; 57 | static const double _min_normalized; 58 | static qd_real _max; 59 | static qd_real _safe_max; 60 | static const int _ndigits; 61 | 62 | static qd_real _pi1024; 63 | 64 | qd_real(); 65 | qd_real(const dd_real &dd); 66 | qd_real(double d); 67 | qd_real(int i); 68 | 69 | double operator[](int i) const; 70 | double &operator[](int i); 71 | 72 | static void error(const char *msg); 73 | 74 | bool isnan() const; 75 | bool isfinite() const { return QD_ISFINITE(x[0]); } 76 | bool isinf() const { return QD_ISINF(x[0]); } 77 | 78 | static qd_real ieee_add(const qd_real &a, const qd_real &b); 79 | static qd_real sloppy_add(const qd_real &a, const qd_real &b); 80 | 81 | qd_real &operator+=(double a); 82 | qd_real &operator+=(const dd_real &a); 83 | qd_real &operator+=(const qd_real &a); 84 | 85 | qd_real &operator-=(double a); 86 | qd_real &operator-=(const dd_real &a); 87 | qd_real &operator-=(const qd_real &a); 88 | 89 | static qd_real sloppy_mul(const qd_real &a, const qd_real &b); 90 | static qd_real accurate_mul(const qd_real &a, const qd_real &b); 91 | 92 | qd_real &operator*=(double a); 93 | qd_real &operator*=(const dd_real &a); 94 | qd_real &operator*=(const qd_real &a); 95 | 96 | static qd_real sloppy_div(const qd_real &a, const dd_real &b); 97 | static qd_real accurate_div(const qd_real &a, const dd_real &b); 98 | static qd_real sloppy_div(const qd_real &a, const qd_real &b); 99 | static qd_real accurate_div(const qd_real &a, const qd_real &b); 100 | 101 | qd_real &operator/=(double a); 102 | qd_real &operator/=(const dd_real &a); 103 | qd_real &operator/=(const qd_real &a); 104 | 105 | qd_real operator^(int n) const; 106 | 107 | qd_real operator-() const; 108 | 109 | qd_real &operator=(double a); 110 | qd_real &operator=(const dd_real &a); 111 | qd_real &operator=(const char *s); 112 | 113 | bool is_zero() const; 114 | bool is_one() const; 115 | bool is_positive() const; 116 | bool is_negative() const; 117 | 118 | void to_digits(char *s, int &expn, int precision = _ndigits) const; 119 | }; 120 | 121 | QD_API qd_real polyeval(const qd_real *c, int n, const qd_real &x); 122 | QD_API qd_real polyroot(const qd_real *c, int n, 123 | const qd_real &x0, int max_iter = 64, double thresh = 0.0); 124 | 125 | QD_API qd_real qdrand(void); 126 | QD_API qd_real sqrt(const qd_real &a); 127 | 128 | QD_API inline bool isnan(const qd_real &a) { return a.isnan(); } 129 | QD_API inline bool isfinite(const qd_real &a) { return a.isfinite(); } 130 | QD_API inline bool isinf(const qd_real &a) { return a.isinf(); } 131 | 132 | /* Computes qd * d where d is known to be a power of 2. 133 | This can be done component wise. */ 134 | QD_API qd_real mul_pwr2(const qd_real &qd, double d); 135 | 136 | QD_API qd_real operator+(const qd_real &a, const qd_real &b); 137 | QD_API qd_real operator+(const dd_real &a, const qd_real &b); 138 | QD_API qd_real operator+(const qd_real &a, const dd_real &b); 139 | QD_API qd_real operator+(const qd_real &a, double b); 140 | QD_API qd_real operator+(double a, const qd_real &b); 141 | 142 | QD_API qd_real operator-(const qd_real &a, const qd_real &b); 143 | QD_API qd_real operator-(const dd_real &a, const qd_real &b); 144 | QD_API qd_real operator-(const qd_real &a, const dd_real &b); 145 | QD_API qd_real operator-(const qd_real &a, double b); 146 | QD_API qd_real operator-(double a, const qd_real &b); 147 | 148 | QD_API qd_real operator*(const qd_real &a, const qd_real &b); 149 | QD_API qd_real operator*(const dd_real &a, const qd_real &b); 150 | QD_API qd_real operator*(const qd_real &a, const dd_real &b); 151 | QD_API qd_real operator*(const qd_real &a, double b); 152 | QD_API qd_real operator*(double a, const qd_real &b); 153 | 154 | QD_API qd_real operator/(const qd_real &a, const qd_real &b); 155 | QD_API qd_real operator/(const dd_real &a, const qd_real &b); 156 | QD_API qd_real operator/(const qd_real &a, const dd_real &b); 157 | QD_API qd_real operator/(const qd_real &a, double b); 158 | QD_API qd_real operator/(double a, const qd_real &b); 159 | 160 | QD_API qd_real sqr(const qd_real &a); 161 | QD_API qd_real sqrt(const qd_real &a); 162 | QD_API qd_real pow(const qd_real &a, int n); 163 | QD_API qd_real pow(const qd_real &a, const qd_real &b); 164 | QD_API qd_real npwr(const qd_real &a, int n); 165 | 166 | QD_API qd_real nroot(const qd_real &a, int n); 167 | 168 | QD_API qd_real rem(const qd_real &a, const qd_real &b); 169 | QD_API qd_real drem(const qd_real &a, const qd_real &b); 170 | QD_API qd_real divrem(const qd_real &a, const qd_real &b, qd_real &r); 171 | 172 | dd_real to_dd_real(const qd_real &a); 173 | double to_double(const qd_real &a); 174 | int to_int(const qd_real &a); 175 | 176 | QD_API bool operator==(const qd_real &a, const qd_real &b); 177 | QD_API bool operator==(const qd_real &a, const dd_real &b); 178 | QD_API bool operator==(const dd_real &a, const qd_real &b); 179 | QD_API bool operator==(double a, const qd_real &b); 180 | QD_API bool operator==(const qd_real &a, double b); 181 | 182 | QD_API bool operator<(const qd_real &a, const qd_real &b); 183 | QD_API bool operator<(const qd_real &a, const dd_real &b); 184 | QD_API bool operator<(const dd_real &a, const qd_real &b); 185 | QD_API bool operator<(double a, const qd_real &b); 186 | QD_API bool operator<(const qd_real &a, double b); 187 | 188 | QD_API bool operator>(const qd_real &a, const qd_real &b); 189 | QD_API bool operator>(const qd_real &a, const dd_real &b); 190 | QD_API bool operator>(const dd_real &a, const qd_real &b); 191 | QD_API bool operator>(double a, const qd_real &b); 192 | QD_API bool operator>(const qd_real &a, double b); 193 | 194 | QD_API bool operator<=(const qd_real &a, const qd_real &b); 195 | QD_API bool operator<=(const qd_real &a, const dd_real &b); 196 | QD_API bool operator<=(const dd_real &a, const qd_real &b); 197 | QD_API bool operator<=(double a, const qd_real &b); 198 | QD_API bool operator<=(const qd_real &a, double b); 199 | 200 | QD_API bool operator>=(const qd_real &a, const qd_real &b); 201 | QD_API bool operator>=(const qd_real &a, const dd_real &b); 202 | QD_API bool operator>=(const dd_real &a, const qd_real &b); 203 | QD_API bool operator>=(double a, const qd_real &b); 204 | QD_API bool operator>=(const qd_real &a, double b); 205 | 206 | QD_API bool operator!=(const qd_real &a, const qd_real &b); 207 | QD_API bool operator!=(const qd_real &a, const dd_real &b); 208 | QD_API bool operator!=(const dd_real &a, const qd_real &b); 209 | QD_API bool operator!=(double a, const qd_real &b); 210 | QD_API bool operator!=(const qd_real &a, double b); 211 | 212 | QD_API qd_real fabs(const qd_real &a); 213 | QD_API qd_real abs(const qd_real &a); /* same as fabs */ 214 | 215 | QD_API qd_real ldexp(const qd_real &a, int n); 216 | 217 | QD_API qd_real nint(const qd_real &a); 218 | QD_API qd_real quick_nint(const qd_real &a); 219 | QD_API qd_real floor(const qd_real &a); 220 | QD_API qd_real ceil(const qd_real &a); 221 | QD_API qd_real aint(const qd_real &a); 222 | 223 | QD_API qd_real sin(const qd_real &a); 224 | QD_API qd_real cos(const qd_real &a); 225 | QD_API qd_real tan(const qd_real &a); 226 | QD_API void sincos(const qd_real &a, qd_real &s, qd_real &c); 227 | 228 | QD_API qd_real asin(const qd_real &a); 229 | QD_API qd_real acos(const qd_real &a); 230 | QD_API qd_real atan(const qd_real &a); 231 | QD_API qd_real atan2(const qd_real &y, const qd_real &x); 232 | 233 | QD_API qd_real exp(const qd_real &a); 234 | QD_API qd_real log(const qd_real &a); 235 | QD_API qd_real log10(const qd_real &a); 236 | 237 | QD_API qd_real sinh(const qd_real &a); 238 | QD_API qd_real cosh(const qd_real &a); 239 | QD_API qd_real tanh(const qd_real &a); 240 | QD_API void sincosh(const qd_real &a, qd_real &sin_qd, qd_real &cos_qd); 241 | 242 | QD_API qd_real asinh(const qd_real &a); 243 | QD_API qd_real acosh(const qd_real &a); 244 | QD_API qd_real atanh(const qd_real &a); 245 | 246 | QD_API qd_real qdrand(void); 247 | 248 | QD_API qd_real max(const qd_real &a, const qd_real &b); 249 | QD_API qd_real max(const qd_real &a, const qd_real &b, const qd_real &c); 250 | QD_API qd_real min(const qd_real &a, const qd_real &b); 251 | QD_API qd_real min(const qd_real &a, const qd_real &b, const qd_real &c); 252 | 253 | QD_API qd_real fmod(const qd_real &a, const qd_real &b); 254 | #ifdef QD_INLINE 255 | #include "qd_inline.h" 256 | #endif 257 | 258 | #endif /* _QD_QD_REAL_H */ 259 | 260 | -------------------------------------------------------------------------------- /C/readme.txt: -------------------------------------------------------------------------------- 1 | Building the QD library for use with Delphi 2 | =========================================== 3 | 4 | Uses QD 2.3.22 (https://www.davidhbailey.com/dhbsoftware/) 5 | 6 | This directory contains a custom version of the QD library, more suitable for 7 | use from Delphi. 8 | 9 | Compile for Windows 10 | ------------------- 11 | * Install 64-bit MinGW with at least support for mingw32-gcc and mingw32-gcc-g++ 12 | https://sourceforge.net/projects/mingw-w64/files/mingw-w64/ 13 | * Add the MinGW\Bin directory to the path, or for temporary path addition: 14 | >set PATH=%PATH%;c:\MinGW64\mingw64\bin\ 15 | * Run BuildX86.bat and BuildX64.bat 16 | 17 | Explaination of gcc command line options used: 18 | * -m32: build 32-bit object file 19 | * -m64: build 64-bit object file 20 | * -c: compile only (do not link) 21 | * -o: name of output file 22 | * -I: add include directory to search path 23 | * -Wno-attributes: ignore warning "'regparm' attribute only applies to function 24 | types". This warning happens because the calling convention define (QD_API) 25 | is not only applied to functions, but to structs as well. 26 | * -mfpmath=sse: use SSE instead of FPU for floating-point math (only needed for 27 | Intel 32-bit) 28 | * -msse2: use SSE2 (which supports double-precision math) 29 | * -O3: full optimization 30 | * -mincoming-stack-boundary=2: assumes the stack is aligned on a 2^2=4 byte 31 | boundary when a function in the object file is called. Some functions in the 32 | object file require that the stack is aligned to a 16 byte boundary, but 33 | Delphi only aligns to 4 byte boundaries on Intel 32-bit. With this option, 34 | extra code is added in the object file to make sure the stack is aligned 35 | to a 16 byte boundary. This is not needed for 64-bit, since the stack is 36 | required to be aligned on 16 byte boundaries then. 37 | * -Xassembler -L: passes -L to the assembler. This keeps any local symbols in 38 | the object file (such as data containing floating-point constants). Without 39 | this, the object file would try to load that data from address 0, leading to 40 | an AV 41 | 42 | Compile for Android 43 | ------------------- 44 | * Make sure you have a recent version of the Android NDK installed. 45 | * Open the BuildAndroid.bat file in a text editor. 46 | * Modify the NDK_BUILD variable to point to the location of the ndk-build.cmd 47 | file in your NDK directory. 48 | * Run the batch file 49 | 50 | Build for macOS and iOS 51 | ----------------------- 52 | * Make this directory available on a Mac (either as a share or by copying it). 53 | * Open a terminal window and run: 54 | > ./BuildIOS.sh 55 | > ./BuildMacOS.sh -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Neslib.MultiPrecision is licensed under the Simplified BSD License. 2 | The underlying QD library is licensed under the BSD-LBNL license. See the 3 | document BSD-LBNL-License.doc in the "C" subdirectory for details. 4 | 5 | ------------------------------------------------------------------------------- 6 | 7 | Copyright (c) 2032 by Erik van Bilsen 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions of source code must retain the above copyright notice, this 14 | list of conditions and the following disclaimer. 15 | 2. Redistributions in binary form must reproduce the above copyright notice, 16 | this list of conditions and the following disclaimer in the documentation 17 | and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Obj/dd32-accurate.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/dd32-accurate.obj -------------------------------------------------------------------------------- /Obj/dd32.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/dd32.obj -------------------------------------------------------------------------------- /Obj/dd64-accurate.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/dd64-accurate.obj -------------------------------------------------------------------------------- /Obj/dd64.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/dd64.obj -------------------------------------------------------------------------------- /Obj/qd32-accurate.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/qd32-accurate.obj -------------------------------------------------------------------------------- /Obj/qd32.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/qd32.obj -------------------------------------------------------------------------------- /Obj/qd64-accurate.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/qd64-accurate.obj -------------------------------------------------------------------------------- /Obj/qd64.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Obj/qd64.obj -------------------------------------------------------------------------------- /Samples/Mandelbrot/AndroidManifest.template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | <%uses-permission%> 11 | 12 | 22 | 23 | <%provider%> 24 | <%application-meta-data%> 25 | <%uses-libraries%> 26 | <%services%> 27 | 29 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | <%activity%> 42 | <%receivers%> 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/Entitlement.TemplateOSX.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | <%appSandboxKeys%> 6 | 7 | 8 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/Entitlement.TemplateiOS.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | <%getTaskAllowKey%> 6 | <%applicationIdentifier%> 7 | <%pushNotificationKey%> 8 | <%keychainAccessGroups%> 9 | 10 | 11 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/FMain.fmx: -------------------------------------------------------------------------------- 1 | object FormMain: TFormMain 2 | Left = 0 3 | Top = 0 4 | BorderStyle = Single 5 | Caption = 'Multi Precision Mandelbrot' 6 | ClientHeight = 300 7 | ClientWidth = 516 8 | FormFactor.Width = 320 9 | FormFactor.Height = 480 10 | FormFactor.Devices = [Desktop] 11 | OnCreate = FormCreate 12 | OnClose = FormClose 13 | OnDestroy = FormDestroy 14 | OnResize = FormResize 15 | DesignerMasterStyle = 0 16 | object PaintBox: TPaintBox 17 | Align = Client 18 | ClipChildren = True 19 | Size.Width = 300.000000000000000000 20 | Size.Height = 300.000000000000000000 21 | Size.PlatformDefault = False 22 | OnClick = PaintBoxClick 23 | OnPaint = PaintBoxPaint 24 | end 25 | object LayoutOptions: TLayout 26 | Align = Left 27 | Margins.Left = 8.000000000000000000 28 | Margins.Top = 8.000000000000000000 29 | Margins.Right = 8.000000000000000000 30 | Margins.Bottom = 8.000000000000000000 31 | Position.X = 8.000000000000000000 32 | Position.Y = 8.000000000000000000 33 | Size.Width = 200.000000000000000000 34 | Size.Height = 284.000000000000000000 35 | Size.PlatformDefault = False 36 | TabOrder = 0 37 | object LabelPrecision: TLabel 38 | Align = Top 39 | AutoSize = True 40 | Size.Width = 200.000000000000000000 41 | Size.Height = 16.000000000000000000 42 | Size.PlatformDefault = False 43 | Text = 'Precision:' 44 | end 45 | object ComboBoxPrecision: TComboBox 46 | Align = Top 47 | Items.Strings = ( 48 | 'Single' 49 | 'Double' 50 | 'DoubleDouble' 51 | 'QuadDouble') 52 | ItemIndex = 0 53 | Position.Y = 16.000000000000000000 54 | Size.Width = 200.000000000000000000 55 | Size.Height = 30.000000000000000000 56 | Size.PlatformDefault = False 57 | TabOrder = 2 58 | end 59 | object ComboBoxMagnification: TComboBox 60 | Align = Top 61 | DropDownCount = 20 62 | Position.Y = 78.000000000000000000 63 | Size.Width = 200.000000000000000000 64 | Size.Height = 30.000000000000000000 65 | Size.PlatformDefault = False 66 | TabOrder = 1 67 | end 68 | object LabelMagnification: TLabel 69 | Align = Top 70 | AutoSize = True 71 | Margins.Top = 16.000000000000000000 72 | Position.Y = 62.000000000000000000 73 | Size.Width = 200.000000000000000000 74 | Size.Height = 16.000000000000000000 75 | Size.PlatformDefault = False 76 | Text = 'Magnification:' 77 | end 78 | object ButtonUpdateOrCancel: TButton 79 | Align = Top 80 | Default = True 81 | Margins.Top = 16.000000000000000000 82 | Position.Y = 124.000000000000000000 83 | Size.Width = 200.000000000000000000 84 | Size.Height = 35.000000000000000000 85 | Size.PlatformDefault = False 86 | TabOrder = 4 87 | Text = 'Update' 88 | OnClick = ButtonUpdateOrCancelClick 89 | end 90 | object LabelGradientOffset: TLabel 91 | Align = Top 92 | AutoSize = True 93 | Margins.Top = 16.000000000000000000 94 | Position.Y = 175.000000000000000000 95 | Size.Width = 200.000000000000000000 96 | Size.Height = 16.000000000000000000 97 | Size.PlatformDefault = False 98 | Text = 'Gradient offset: 0' 99 | end 100 | object LabelTime: TLabel 101 | Align = Bottom 102 | Position.Y = 267.000000000000000000 103 | Size.Width = 200.000000000000000000 104 | Size.Height = 17.000000000000000000 105 | Size.PlatformDefault = False 106 | end 107 | object TrackBarGradientOffset: TTrackBar 108 | Align = Top 109 | CanParentFocus = True 110 | Max = 127.000000000000000000 111 | Orientation = Horizontal 112 | Position.Y = 191.000000000000000000 113 | Size.Width = 200.000000000000000000 114 | Size.Height = 19.000000000000000000 115 | Size.PlatformDefault = False 116 | TabOrder = 6 117 | OnChange = TrackBarGradientOffsetChange 118 | end 119 | end 120 | object TimerUpdate: TTimer 121 | Enabled = False 122 | Interval = 100 123 | OnTimer = TimerUpdateTimer 124 | Left = 64 125 | Top = 224 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/FMain.pas: -------------------------------------------------------------------------------- 1 | unit FMain; 2 | 3 | interface 4 | 5 | uses 6 | System.Math, 7 | System.SysUtils, 8 | System.Types, 9 | System.UITypes, 10 | System.Classes, 11 | System.Variants, 12 | System.Diagnostics, 13 | FMX.Types, 14 | FMX.Controls, 15 | FMX.Forms, 16 | FMX.Graphics, 17 | FMX.Dialogs, 18 | FMX.Objects, 19 | FMX.Controls.Presentation, 20 | FMX.StdCtrls, 21 | FMX.Layouts, 22 | FMX.ListBox, 23 | FMX.Edit, 24 | FMX.EditBox, 25 | FMX.SpinBox, 26 | MandelbrotGenerator; 27 | 28 | const 29 | PALETTE_BITS = 7; 30 | PALETTE_SIZE = 1 shl PALETTE_BITS; 31 | PALETTE_MASK = PALETTE_SIZE - 1; 32 | 33 | type 34 | TFormMain = class(TForm) 35 | PaintBox: TPaintBox; 36 | LayoutOptions: TLayout; 37 | LabelPrecision: TLabel; 38 | ComboBoxPrecision: TComboBox; 39 | ComboBoxMagnification: TComboBox; 40 | LabelMagnification: TLabel; 41 | ButtonUpdateOrCancel: TButton; 42 | LabelGradientOffset: TLabel; 43 | LabelTime: TLabel; 44 | TrackBarGradientOffset: TTrackBar; 45 | TimerUpdate: TTimer; 46 | procedure FormCreate(Sender: TObject); 47 | procedure FormDestroy(Sender: TObject); 48 | procedure PaintBoxPaint(Sender: TObject; Canvas: TCanvas); 49 | procedure ButtonUpdateOrCancelClick(Sender: TObject); 50 | procedure TrackBarGradientOffsetChange(Sender: TObject); 51 | procedure PaintBoxClick(Sender: TObject); 52 | procedure FormResize(Sender: TObject); 53 | procedure FormClose(Sender: TObject; var Action: TCloseAction); 54 | procedure TimerUpdateTimer(Sender: TObject); 55 | private 56 | { Private declarations } 57 | FPalette: array [0..PALETTE_SIZE - 1] of TAlphaColor; 58 | FBitmap: TBitmap; 59 | FGenerator: TMandelbrotGenerator; 60 | FSurface: TSurface; 61 | FStopwatch: TStopwatch; 62 | FOrigOptionsWidth: Single; 63 | procedure CreatePalette; 64 | procedure Update; 65 | procedure UpdateStats; 66 | procedure UpdateDisplay; 67 | procedure EnableControls(const Enable: Boolean); 68 | procedure Generate(const APrecision: TPrecision; 69 | const AMagnification: Double; const AMaxIterations: Integer); 70 | procedure GeneratorTerminate(Sender: TObject); 71 | procedure ShutdownGenerator; 72 | public 73 | { Public declarations } 74 | end; 75 | 76 | var 77 | FormMain: TFormMain; 78 | 79 | implementation 80 | 81 | {$R *.fmx} 82 | {$R palette.res} 83 | 84 | procedure TFormMain.ButtonUpdateOrCancelClick(Sender: TObject); 85 | begin 86 | if (ButtonUpdateOrCancel.Text = 'Update') then 87 | Update 88 | else 89 | ShutdownGenerator; 90 | end; 91 | 92 | procedure TFormMain.CreatePalette; 93 | var 94 | Stream: TStream; 95 | Palette: array [0..PALETTE_SIZE * 3 - 1] of Byte; 96 | I: Integer; 97 | C: TAlphaColorRec; 98 | begin 99 | Stream := TResourceStream.Create(HInstance, 'PALETTE', RT_RCDATA); 100 | try 101 | Assert(Stream.Size = Length(Palette)); 102 | Stream.ReadBuffer(Palette[0], Length(Palette)); 103 | finally 104 | Stream.Free; 105 | end; 106 | for I := 0 to PALETTE_SIZE - 1 do 107 | begin 108 | {$IFDEF MSWINDOWS} 109 | C.R := Palette[I * 3 + 0]; 110 | C.G := Palette[I * 3 + 1]; 111 | C.B := Palette[I * 3 + 2]; 112 | {$ELSE} 113 | C.R := Palette[I * 3 + 2]; 114 | C.G := Palette[I * 3 + 1]; 115 | C.B := Palette[I * 3 + 0]; 116 | {$ENDIF} 117 | C.A := 255; 118 | FPalette[I] := C.Color; 119 | end; 120 | end; 121 | 122 | procedure TFormMain.EnableControls(const Enable: Boolean); 123 | begin 124 | LabelPrecision.Enabled := Enable; 125 | ComboBoxPrecision.Enabled := Enable; 126 | 127 | LabelMagnification.Enabled := Enable; 128 | ComboBoxMagnification.Enabled := Enable; 129 | 130 | if (Enable) then 131 | ButtonUpdateOrCancel.Text := 'Update' 132 | else 133 | ButtonUpdateOrCancel.Text := 'Cancel'; 134 | end; 135 | 136 | procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction); 137 | begin 138 | ShutdownGenerator; 139 | end; 140 | 141 | procedure TFormMain.FormCreate(Sender: TObject); 142 | var 143 | I: Integer; 144 | S: String; 145 | begin 146 | { To test the use of TFormatSettings, set the default format settings to a 147 | non-English locale. } 148 | FormatSettings.DecimalSeparator := ','; 149 | FormatSettings.ThousandSeparator := '.'; 150 | 151 | FBitmap := TBitmap.Create; 152 | FBitmap.SetSize(TMandelbrotGenerator.WIDTH, TMandelbrotGenerator.HEIGHT); 153 | FOrigOptionsWidth := LayoutOptions.Width; 154 | CreatePalette; 155 | 156 | ComboBoxMagnification.Items.BeginUpdate; 157 | try 158 | ComboBoxMagnification.Items.Add('1'); 159 | for I := 1 to 38 do 160 | begin 161 | S := '1e' + I.ToString; 162 | if (I = 6) then 163 | S := S + ' (need Double)' 164 | else if (I = 14) then 165 | S := S + ' (need DoubleDouble)' 166 | else if (I = 31) then 167 | S := S + ' (need QuadDouble)'; 168 | ComboBoxMagnification.Items.Add(S) 169 | end; 170 | finally 171 | ComboBoxMagnification.Items.EndUpdate; 172 | end; 173 | ComboBoxMagnification.ItemIndex := 0; 174 | end; 175 | 176 | procedure TFormMain.FormDestroy(Sender: TObject); 177 | begin 178 | FBitmap.Free; 179 | end; 180 | 181 | procedure TFormMain.FormResize(Sender: TObject); 182 | begin 183 | if (ClientWidth > ClientHeight) then 184 | begin 185 | { Landscape } 186 | LayoutOptions.Align := TAlignLayout.Left; 187 | LayoutOptions.Width := FOrigOptionsWidth; 188 | end 189 | else 190 | begin 191 | { Portrait } 192 | LayoutOptions.Align := TAlignLayout.Top; 193 | LayoutOptions.Height := TrackBarGradientOffset.Position.Y + 194 | TrackBarGradientOffset.Height + LabelTime.Height + 16; 195 | end; 196 | end; 197 | 198 | procedure TFormMain.Generate(const APrecision: TPrecision; 199 | const AMagnification: Double; const AMaxIterations: Integer); 200 | begin 201 | ShutdownGenerator; 202 | EnableControls(False); 203 | 204 | FBitmap.Clear(TAlphaColors.Black); 205 | FStopwatch := TStopwatch.StartNew; 206 | 207 | FGenerator := TMandelbrotGenerator.Create(AMaxIterations, AMagnification, 208 | APrecision); 209 | FGenerator.OnTerminate := GeneratorTerminate; 210 | FSurface := FGenerator.Surface; 211 | 212 | UpdateStats; 213 | UpdateDisplay; 214 | TimerUpdate.Enabled := True; 215 | end; 216 | 217 | procedure TFormMain.GeneratorTerminate(Sender: TObject); 218 | begin 219 | TimerUpdate.Enabled := False; 220 | 221 | UpdateStats; 222 | UpdateDisplay; 223 | EnableControls(True); 224 | 225 | FGenerator := nil; 226 | end; 227 | 228 | procedure TFormMain.PaintBoxClick(Sender: TObject); 229 | begin 230 | {$IF Defined(DEBUG) and Defined(MSWINDOWS)} 231 | { Switch between portrait and landscape layout } 232 | SetBounds(Left, Top, Height, Width); 233 | {$ENDIF} 234 | end; 235 | 236 | procedure TFormMain.PaintBoxPaint(Sender: TObject; Canvas: TCanvas); 237 | var 238 | SR, DR: TRectF; 239 | begin 240 | if (FBitmap <> nil) then 241 | begin 242 | SR := RectF(0, 0, FBitmap.Width, FBitmap.Height); 243 | DR := RectF(0, 0, PaintBox.Width, PaintBox.Height); 244 | DR := SR.CenterAt(DR); 245 | Canvas.DrawBitmap(FBitmap, SR, DR, 1); 246 | end; 247 | end; 248 | 249 | procedure TFormMain.ShutdownGenerator; 250 | begin 251 | if (FGenerator <> nil) then 252 | begin 253 | FGenerator.Terminate; 254 | FGenerator.WaitFor; 255 | FGenerator.Free; 256 | FGenerator := nil; 257 | end; 258 | end; 259 | 260 | procedure TFormMain.TimerUpdateTimer(Sender: TObject); 261 | begin 262 | UpdateStats; 263 | UpdateDisplay; 264 | end; 265 | 266 | procedure TFormMain.TrackBarGradientOffsetChange(Sender: TObject); 267 | begin 268 | LabelGradientOffset.Text := Format('Gradient offset: %.0f', [TrackBarGradientOffset.Value]); 269 | UpdateDisplay; 270 | end; 271 | 272 | procedure TFormMain.Update; 273 | var 274 | Magnification: Double; 275 | Precision: TPrecision; 276 | Iterations: Integer; 277 | begin 278 | case ComboBoxPrecision.ItemIndex of 279 | 0: Precision := TPrecision.Single; 280 | 1: Precision := TPrecision.Double; 281 | 2: Precision := TPrecision.DoubleDouble; 282 | 3: Precision := TPrecision.QuadDouble; 283 | else 284 | Assert(False); 285 | Precision := TPrecision.Single; 286 | end; 287 | 288 | Magnification := Power(10, ComboBoxMagnification.ItemIndex); 289 | 290 | if (Magnification >= 1e11) then 291 | Iterations := 5000 292 | else if (Magnification >= 1e10) then 293 | Iterations := 1000 294 | else 295 | Iterations := 200; 296 | 297 | Generate(Precision, Magnification, Iterations); 298 | end; 299 | 300 | procedure TFormMain.UpdateDisplay; 301 | var 302 | Data: TBitmapData; 303 | X, Y, PaletteOffset: Integer; 304 | Iter: PInteger; 305 | Dst: PAlphaColor; 306 | begin 307 | if (FSurface.Data <> nil) and (FBitmap.Map(TMapAccess.Write, Data)) then 308 | try 309 | PaletteOffset := System.Trunc(TrackBarGradientOffset.Value); 310 | Iter := @FSurface.Data[0]; 311 | for Y := 0 to Data.Height - 1 do 312 | begin 313 | Dst := Data.GetScanline(Y); 314 | for X := 0 to Data.Width - 1 do 315 | begin 316 | if (Iter^ < 0) then 317 | Dst^ := TAlphaColors.Black 318 | else 319 | Dst^ := FPalette[(Iter^ + PaletteOffset) and PALETTE_MASK]; 320 | 321 | Inc(Iter); 322 | Inc(Dst); 323 | end; 324 | end; 325 | finally 326 | FBitmap.Unmap(Data); 327 | end; 328 | 329 | PaintBox.Repaint; 330 | end; 331 | 332 | procedure TFormMain.UpdateStats; 333 | var 334 | Seconds: Double; 335 | begin 336 | Seconds := FStopwatch.Elapsed.TotalSeconds; 337 | LabelTime.Text := Format('Elapsed: %.3f seconds', [Seconds]); 338 | end; 339 | 340 | end. 341 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/LaunchScreen.TemplateiOS/Assets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | <%AppIconImages%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/LaunchScreen.TemplateiOS/Assets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "RAD Studio" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/LaunchScreen.TemplateiOS/Assets/LaunchScreenBackgroundColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | <%LaunchScreenBackgroundColors%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/LaunchScreen.TemplateiOS/Assets/LaunchScreenImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | <%LaunchScreenImages%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/LaunchScreen.TemplateiOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/Mandelbrot.dpr: -------------------------------------------------------------------------------- 1 | program Mandelbrot; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | FMain in 'FMain.pas' {FormMain}, 7 | Neslib.MultiPrecision in '..\..\Neslib.MultiPrecision.pas', 8 | MandelbrotGenerator in 'MandelbrotGenerator.pas'; 9 | 10 | {$R *.res} 11 | 12 | begin 13 | Application.Initialize; 14 | Application.CreateForm(TFormMain, FormMain); 15 | Application.Run; 16 | end. 17 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/Mandelbrot.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Samples/Mandelbrot/Mandelbrot.res -------------------------------------------------------------------------------- /Samples/Mandelbrot/MandelbrotGenerator.pas: -------------------------------------------------------------------------------- 1 | unit MandelbrotGenerator; 2 | 3 | {$SCOPEDENUMS ON} 4 | 5 | interface 6 | 7 | uses 8 | System.Classes; 9 | 10 | type 11 | TPrecision = (Single, Double, DoubleDouble, QuadDouble); 12 | 13 | type 14 | TSurface = record 15 | public 16 | Width: Integer; 17 | Height: Integer; 18 | Data: TArray; 19 | end; 20 | 21 | type 22 | TMandelbrotGenerator = class(TThread) 23 | public const 24 | WIDTH = 300; 25 | HEIGHT = 300; 26 | private 27 | FSurface: TSurface; 28 | FMaxIterations: Integer; 29 | FMagnification: Double; 30 | FPrecision: TPrecision; 31 | private 32 | procedure GenerateSingle; 33 | procedure GenerateDouble; 34 | procedure GenerateDoubleDouble; 35 | procedure GenerateQuadDouble; 36 | protected 37 | procedure Execute; override; 38 | public 39 | constructor Create(const AMaxIterations: Integer; 40 | const AMagnification: Double; const APrecision: TPrecision); 41 | 42 | property Surface: TSurface read FSurface; 43 | end; 44 | 45 | implementation 46 | 47 | uses 48 | System.SysUtils, 49 | Neslib.MultiPrecision; 50 | 51 | const 52 | CENTER_RE = '-0.00677652295833245729642263781984627256356509565412970431582937'; 53 | CENTER_IM = '1.00358346588202262420197968965648988617755127635794148856757956'; 54 | 55 | var 56 | USFormatSettings: TFormatSettings; 57 | 58 | { TMandelbrotGenerator } 59 | 60 | constructor TMandelbrotGenerator.Create(const AMaxIterations: Integer; 61 | const AMagnification: Double; const APrecision: TPrecision); 62 | begin 63 | inherited Create(False); 64 | FMaxIterations := AMaxIterations; 65 | FMagnification := AMagnification; 66 | FPrecision := APrecision; 67 | FSurface.Width := WIDTH; 68 | FSurface.Height := HEIGHT; 69 | SetLength(FSurface.Data, WIDTH * HEIGHT); 70 | end; 71 | 72 | procedure TMandelbrotGenerator.Execute; 73 | begin 74 | case FPrecision of 75 | TPrecision.Single : GenerateSingle; 76 | TPrecision.Double : GenerateDouble; 77 | TPrecision.DoubleDouble: GenerateDoubleDouble; 78 | TPrecision.QuadDouble : GenerateQuadDouble; 79 | end; 80 | end; 81 | 82 | procedure TMandelbrotGenerator.GenerateDouble; 83 | var 84 | CenterRe, CenterIm, Radius, XStart, YStart, X, Y, Step: Double; 85 | ZRe, ZIm, ZReSq, ZImSq, NewIm: Double; 86 | Row, Col, Iter, MaxIter: Integer; 87 | Data: PInteger; 88 | begin 89 | CenterRe := StrToFloat(CENTER_RE, USFormatSettings); 90 | CenterIm := StrToFloat(CENTER_IM, USFormatSettings); 91 | Radius := 2.5 / FMagnification; 92 | MaxIter := FMaxIterations; 93 | 94 | XStart := CenterRe - (Radius * 0.5); 95 | YStart := CenterIm - (Radius * 0.5); 96 | 97 | Step := Radius / FSurface.Width; 98 | Data := @FSurface.Data[0]; 99 | 100 | for Row := 0 to FSurface.Height - 1 do 101 | begin 102 | Y := YStart + (Row * Step); 103 | for Col := 0 to FSurface.Width - 1 do 104 | begin 105 | X := XStart + (Col * Step); 106 | 107 | ZRe := X; 108 | ZIm := Y; 109 | Iter := 0; 110 | while (Iter < MaxIter) do 111 | begin 112 | ZReSq := ZRe * ZRe; 113 | ZImSq := ZIm * ZIm; 114 | if ((ZReSq + ZImSq) > 4) then 115 | Break; 116 | 117 | NewIm := 2 * ZRe * ZIm; 118 | 119 | ZRe := X + (ZReSq - ZImSq); 120 | ZIm := Y + NewIm; 121 | 122 | Inc(Iter); 123 | end; 124 | 125 | if (Iter = MaxIter) then 126 | Data^ := -1 127 | else 128 | Data^ := Iter; 129 | Inc(Data); 130 | 131 | if (Terminated) then 132 | Exit; 133 | end; 134 | end; 135 | end; 136 | 137 | procedure TMandelbrotGenerator.GenerateDoubleDouble; 138 | var 139 | CenterRe, CenterIm, Radius, XStart, YStart, X, Y, Step: DoubleDouble; 140 | ZRe, ZIm, ZReSq, ZImSq, NewIm: DoubleDouble; 141 | Row, Col, Iter, MaxIter: Integer; 142 | Data: PInteger; 143 | begin 144 | MultiPrecisionInit; 145 | CenterRe := CENTER_RE; 146 | CenterIm := CENTER_IM; 147 | Radius := Divide(2.5, FMagnification); 148 | MaxIter := FMaxIterations; 149 | 150 | XStart := CenterRe - (Radius * 0.5); 151 | YStart := CenterIm - (Radius * 0.5); 152 | 153 | Step := Radius / FSurface.Width; 154 | Data := @FSurface.Data[0]; 155 | 156 | for Row := 0 to FSurface.Height - 1 do 157 | begin 158 | Y := YStart + (Row * Step); 159 | for Col := 0 to FSurface.Width - 1 do 160 | begin 161 | X := XStart + (Col * Step); 162 | 163 | ZRe := X; 164 | ZIm := Y; 165 | Iter := 0; 166 | while (Iter < MaxIter) do 167 | begin 168 | ZReSq := ZRe * ZRe; 169 | ZImSq := ZIm * ZIm; 170 | if ((ZReSq + ZImSq).ToDouble > 4) then 171 | Break; 172 | 173 | NewIm := 2 * ZRe * ZIm; 174 | 175 | ZRe := X + (ZReSq - ZImSq); 176 | ZIm := Y + NewIm; 177 | 178 | Inc(Iter); 179 | end; 180 | 181 | if (Iter = MaxIter) then 182 | Data^ := -1 183 | else 184 | Data^ := Iter; 185 | Inc(Data); 186 | 187 | if (Terminated) then 188 | Exit; 189 | end; 190 | end; 191 | end; 192 | 193 | procedure TMandelbrotGenerator.GenerateQuadDouble; 194 | var 195 | CenterRe, CenterIm, Radius, XStart, YStart, X, Y, Step: QuadDouble; 196 | ZRe, ZIm, ZReSq, ZImSq, NewIm: QuadDouble; 197 | Row, Col, Iter, MaxIter: Integer; 198 | Data: PInteger; 199 | begin 200 | MultiPrecisionInit; 201 | CenterRe := CENTER_RE; 202 | CenterIm := CENTER_IM; 203 | Radius.Init(2.5 / FMagnification); 204 | MaxIter := FMaxIterations; 205 | 206 | XStart := CenterRe - (Radius * 0.5); 207 | YStart := CenterIm - (Radius * 0.5); 208 | 209 | Step := Radius / FSurface.Width; 210 | Data := @FSurface.Data[0]; 211 | 212 | for Row := 0 to FSurface.Height - 1 do 213 | begin 214 | Y := YStart + (Row * Step); 215 | for Col := 0 to FSurface.Width - 1 do 216 | begin 217 | X := XStart + (Col * Step); 218 | 219 | ZRe := X; 220 | ZIm := Y; 221 | Iter := 0; 222 | while (Iter < MaxIter) do 223 | begin 224 | ZReSq := ZRe * ZRe; 225 | ZImSq := ZIm * ZIm; 226 | if ((ZReSq + ZImSq).ToDouble > 4) then 227 | Break; 228 | 229 | NewIm := 2 * ZRe * ZIm; 230 | 231 | ZRe := X + (ZReSq - ZImSq); 232 | ZIm := Y + NewIm; 233 | 234 | Inc(Iter); 235 | end; 236 | 237 | if (Iter = MaxIter) then 238 | Data^ := -1 239 | else 240 | Data^ := Iter; 241 | Inc(Data); 242 | 243 | if (Terminated) then 244 | Exit; 245 | end; 246 | end; 247 | end; 248 | 249 | procedure TMandelbrotGenerator.GenerateSingle; 250 | var 251 | CenterRe, CenterIm, Radius, XStart, YStart, X, Y, Step: Single; 252 | ZRe, ZIm, ZReSq, ZImSq, NewIm: Single; 253 | Row, Col, Iter, MaxIter: Integer; 254 | Data: PInteger; 255 | begin 256 | CenterRe := StrToFloat(CENTER_RE, USFormatSettings); 257 | CenterIm := StrToFloat(CENTER_IM, USFormatSettings); 258 | Radius := 2.5 / FMagnification; 259 | MaxIter := FMaxIterations; 260 | 261 | XStart := CenterRe - (Radius * 0.5); 262 | YStart := CenterIm - (Radius * 0.5); 263 | 264 | Step := Radius / FSurface.Width; 265 | Data := @FSurface.Data[0]; 266 | 267 | for Row := 0 to FSurface.Height - 1 do 268 | begin 269 | Y := YStart + (Row * Step); 270 | for Col := 0 to FSurface.Width - 1 do 271 | begin 272 | X := XStart + (Col * Step); 273 | 274 | ZRe := X; 275 | ZIm := Y; 276 | Iter := 0; 277 | while (Iter < MaxIter) do 278 | begin 279 | ZReSq := ZRe * ZRe; 280 | ZImSq := ZIm * ZIm; 281 | if ((ZReSq + ZImSq) > 4) then 282 | Break; 283 | 284 | NewIm := 2 * ZRe * ZIm; 285 | 286 | ZRe := X + (ZReSq - ZImSq); 287 | ZIm := Y + NewIm; 288 | 289 | Inc(Iter); 290 | end; 291 | 292 | if (Iter = MaxIter) then 293 | Data^ := -1 294 | else 295 | Data^ := Iter; 296 | Inc(Data); 297 | 298 | if (Terminated) then 299 | Exit; 300 | end; 301 | end; 302 | end; 303 | 304 | initialization 305 | USFormatSettings := TFormatSettings.Create('en-US'); 306 | USFormatSettings.DecimalSeparator := '.'; 307 | USFormatSettings.ThousandSeparator := ','; 308 | 309 | end. 310 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/info.plist.TemplateOSX.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%VersionInfoPListKeys%> 6 | <%ExtraInfoPListKeys%> 7 | 8 | 9 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/info.plist.TemplateiOS.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%VersionInfoPListKeys%> 6 | <%ExtraInfoPListKeys%> 7 | <%StoryboardInfoPListKey%> 8 | 9 | 10 | -------------------------------------------------------------------------------- /Samples/Mandelbrot/palette.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Samples/Mandelbrot/palette.raw -------------------------------------------------------------------------------- /Samples/Mandelbrot/palette.rc: -------------------------------------------------------------------------------- 1 | PALETTE RCDATA palette.raw -------------------------------------------------------------------------------- /Samples/Mandelbrot/palette.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/Samples/Mandelbrot/palette.res -------------------------------------------------------------------------------- /UnitTests/AndroidManifest.template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | <%uses-permission%> 11 | 12 | 22 | 23 | <%provider%> 24 | <%application-meta-data%> 25 | <%uses-libraries%> 26 | <%services%> 27 | 29 | 33 | 34 | 36 | 37 | 38 | 39 | 40 | 41 | <%activity%> 42 | <%receivers%> 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /UnitTests/Entitlement.TemplateOSX.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | <%appSandboxKeys%> 6 | 7 | 8 | -------------------------------------------------------------------------------- /UnitTests/Entitlement.TemplateiOS.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | <%getTaskAllowKey%> 6 | <%applicationIdentifier%> 7 | <%pushNotificationKey%> 8 | <%keychainAccessGroups%> 9 | 10 | 11 | -------------------------------------------------------------------------------- /UnitTests/FMain.fmx: -------------------------------------------------------------------------------- 1 | object FormMain: TFormMain 2 | Left = 0 3 | Top = 0 4 | ActiveControl = ButtonUnitTests 5 | Caption = 'FastMath Tests' 6 | ClientHeight = 480 7 | ClientWidth = 320 8 | FormFactor.Width = 320 9 | FormFactor.Height = 480 10 | FormFactor.Devices = [Desktop] 11 | DesignerMasterStyle = 2 12 | object Memo: TMemo 13 | Touch.InteractiveGestures = [Pan, LongTap, DoubleTap] 14 | DataDetectorTypes = [] 15 | ReadOnly = True 16 | Align = Client 17 | Size.Width = 320.000000000000000000 18 | Size.Height = 430.000000000000000000 19 | Size.PlatformDefault = False 20 | TabOrder = 0 21 | Viewport.Width = 312.000000000000000000 22 | Viewport.Height = 422.000000000000000000 23 | end 24 | object ButtonUnitTests: TButton 25 | Align = Top 26 | Default = True 27 | Size.Width = 320.000000000000000000 28 | Size.Height = 50.000000000000000000 29 | Size.PlatformDefault = False 30 | TabOrder = 1 31 | Text = 'Run Unit Tests' 32 | OnClick = ButtonUnitTestsClick 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /UnitTests/FMain.pas: -------------------------------------------------------------------------------- 1 | unit FMain; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.Types, 8 | System.UITypes, 9 | System.Classes, 10 | System.Variants, 11 | System.Messaging, 12 | FMX.Types, 13 | FMX.Controls, 14 | FMX.Forms, 15 | FMX.Graphics, 16 | FMX.Dialogs, 17 | FMX.ScrollBox, 18 | FMX.Memo, 19 | FMX.Controls.Presentation, 20 | FMX.StdCtrls, 21 | FMX.Layouts, 22 | FMX.Memo.Types, 23 | UnitTest, 24 | Neslib.MultiPrecision, 25 | MultiPrecision.DoubleDouble.Tests, 26 | MultiPrecision.QuadDouble.Tests; 27 | 28 | type 29 | TFormMain = class(TForm) 30 | ButtonUnitTests: TButton; 31 | Memo: TMemo; 32 | procedure ButtonUnitTestsClick(Sender: TObject); 33 | private 34 | { Private declarations } 35 | procedure TestFailedListener(const Sender: TObject; const M: TMessage); 36 | procedure ScrollToEnd; 37 | public 38 | { Public declarations } 39 | constructor Create(AOwner: TComponent); override; 40 | destructor Destroy; override; 41 | end; 42 | 43 | var 44 | FormMain: TFormMain; 45 | 46 | const 47 | UNIT_TESTS: array [0..1] of TUnitTestClass = ( 48 | TTestDoubleDouble, TTestQuadDouble); 49 | 50 | implementation 51 | 52 | uses 53 | System.Math, 54 | System.IOUtils; 55 | 56 | {$R *.fmx} 57 | 58 | { TFormMain } 59 | 60 | procedure TFormMain.ButtonUnitTestsClick(Sender: TObject); 61 | var 62 | UnitTestClass: TUnitTestClass; 63 | UnitTest: TUnitTest; 64 | NumFailed, NumPassed: Integer; 65 | begin 66 | Memo.Lines.Clear; 67 | ButtonUnitTests.Enabled := False; 68 | try 69 | NumFailed := 0; 70 | NumPassed := 0; 71 | for UnitTestClass in UNIT_TESTS do 72 | begin 73 | UnitTest := UnitTestClass.Create; 74 | try 75 | UnitTest.Run; 76 | Inc(NumFailed, UnitTest.ChecksFailed); 77 | Inc(NumPassed, UnitTest.ChecksPassed); 78 | finally 79 | UnitTest.Free; 80 | end; 81 | end; 82 | Memo.Lines.Add(Format('%d checks completed. %d passed, %d failed', 83 | [NumPassed + NumFailed, NumPassed, NumFailed])); 84 | finally 85 | ButtonUnitTests.Enabled := True; 86 | end; 87 | end; 88 | 89 | constructor TFormMain.Create(AOwner: TComponent); 90 | begin 91 | inherited; 92 | ReportMemoryLeaksOnShutdown := True; 93 | 94 | { To test the use of TFormatSettings, set the default format settings to a 95 | non-English locale. } 96 | FormatSettings.DecimalSeparator := ','; 97 | FormatSettings.ThousandSeparator := '.'; 98 | 99 | MultiPrecisionInit; 100 | TMessageManager.DefaultManager.SubscribeToMessage(TTestFailedMessage, TestFailedListener); 101 | end; 102 | 103 | destructor TFormMain.Destroy; 104 | begin 105 | TMessageManager.DefaultManager.Unsubscribe(TTestFailedMessage, TestFailedListener); 106 | inherited; 107 | end; 108 | 109 | procedure TFormMain.ScrollToEnd; 110 | begin 111 | Memo.SelStart := Memo.Text.Length; 112 | end; 113 | 114 | procedure TFormMain.TestFailedListener(const Sender: TObject; 115 | const M: TMessage); 116 | var 117 | FailedMsg: TTestFailedMessage absolute M; 118 | begin 119 | Assert(M is TTestFailedMessage); 120 | Memo.Lines.Add(Format('%s.%s: %s', 121 | [FailedMsg.TestClassName, FailedMsg.TestMethodName, FailedMsg.Message])); 122 | ScrollToEnd; 123 | Application.ProcessMessages; 124 | end; 125 | 126 | end. 127 | -------------------------------------------------------------------------------- /UnitTests/LaunchScreen.TemplateiOS/Assets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | <%AppIconImages%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /UnitTests/LaunchScreen.TemplateiOS/Assets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "RAD Studio" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /UnitTests/LaunchScreen.TemplateiOS/Assets/LaunchScreenBackgroundColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | <%LaunchScreenBackgroundColors%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /UnitTests/LaunchScreen.TemplateiOS/Assets/LaunchScreenImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | <%LaunchScreenImages%> 4 | ], 5 | "info" : { 6 | "version" : 1, 7 | "author" : "RAD Studio" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /UnitTests/LaunchScreen.TemplateiOS/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /UnitTests/MPTests.dpr: -------------------------------------------------------------------------------- 1 | program MPTests; 2 | 3 | uses 4 | System.StartUpCopy, 5 | FMX.Forms, 6 | FMain in 'FMain.pas' {FormMain}, 7 | UnitTest in 'Tests\UnitTest.pas', 8 | MultiPrecision.DoubleDouble.Tests in 'Tests\MultiPrecision.DoubleDouble.Tests.pas', 9 | Neslib.MultiPrecision in '..\Neslib.MultiPrecision.pas', 10 | MultiPrecision.QuadDouble.Tests in 'Tests\MultiPrecision.QuadDouble.Tests.pas'; 11 | 12 | {$R *.res} 13 | 14 | begin 15 | Application.Initialize; 16 | Application.CreateForm(TFormMain, FormMain); 17 | Application.Run; 18 | end. 19 | -------------------------------------------------------------------------------- /UnitTests/MPTests.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/UnitTests/MPTests.res -------------------------------------------------------------------------------- /UnitTests/Tests/UnitTest.pas: -------------------------------------------------------------------------------- 1 | unit UnitTest; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, 7 | System.Messaging, 8 | System.Math.Vectors; 9 | 10 | type 11 | TTestFailedMessage = class(TMessage) 12 | {$REGION 'Internal Declarations'} 13 | private 14 | FTestClassName: String; 15 | FTestMethodName: String; 16 | FMessage: String; 17 | {$ENDREGION 'Internal Declarations'} 18 | public 19 | constructor Create(const ATestClassName, ATestMethodName, AMessage: String); 20 | 21 | property TestClassName: String read FTestClassName; 22 | property TestMethodName: String read FTestMethodName; 23 | property Message: String read FMessage; 24 | end; 25 | 26 | type 27 | {$M+} 28 | TUnitTest = class 29 | {$REGION 'Internal Declarations'} 30 | private 31 | FCurrentTestMethodName: String; 32 | FChecksPassed: Integer; 33 | FChecksFailed: Integer; 34 | FChecksTotal: Integer; 35 | {$ENDREGION 'Internal Declarations'} 36 | protected 37 | procedure Fail(const AMsg: String); overload; 38 | procedure Fail(const AMsg: String; const AArgs: array of const); overload; 39 | procedure CheckEquals(const AExpected, AActual: String; 40 | const AMsg: String = ''); overload; 41 | procedure CheckEquals(const AExpected, AActual, AEpsilon: Double; 42 | const AMsg: String = ''); overload; 43 | procedure CheckTrue(const ACondition: Boolean); 44 | procedure CheckFalse(const ACondition: Boolean); 45 | procedure ShouldRaise(const AExceptionClass: ExceptClass; 46 | const AProc: TProc); 47 | public 48 | constructor Create; virtual; 49 | procedure Run; 50 | 51 | property ChecksPassed: Integer read FChecksPassed; 52 | property ChecksFailed: Integer read FChecksFailed; 53 | end; 54 | TUnitTestClass = class of TUnitTest; 55 | {$M-} 56 | 57 | var 58 | USFormatSettings: TFormatSettings; 59 | 60 | implementation 61 | 62 | uses 63 | System.Math, 64 | System.Rtti, 65 | System.TypInfo; 66 | 67 | { TTestFailedMessage } 68 | 69 | constructor TTestFailedMessage.Create(const ATestClassName, ATestMethodName, 70 | AMessage: String); 71 | begin 72 | inherited Create; 73 | FTestClassName := ATestClassName; 74 | FTestMethodName := ATestMethodName; 75 | FMessage := AMessage; 76 | end; 77 | 78 | { TUnitTest } 79 | 80 | procedure TUnitTest.CheckEquals(const AExpected, AActual, AMsg: String); 81 | begin 82 | Inc(FChecksTotal); 83 | if (AExpected <> AActual) then 84 | Fail('%s: Expected: %s, Actual: %s', [AMsg, AExpected, AActual]); 85 | end; 86 | 87 | procedure TUnitTest.CheckEquals(const AExpected, AActual, AEpsilon: Double; 88 | const AMsg: String); 89 | var 90 | ExpectedIsExtreme, ActualIsExtreme, OK: Boolean; 91 | begin 92 | Inc(FChecksTotal); 93 | 94 | { FastMath treats all extreme values (Infinite and Nan) the same. } 95 | ExpectedIsExtreme := IsInfinite(AExpected) or IsNan(AExpected); 96 | ActualIsExtreme := IsInfinite(AActual) or IsNan(AActual); 97 | if (ExpectedIsExtreme) then 98 | OK := ActualIsExtreme 99 | else if (ActualIsExtreme) then 100 | OK := ExpectedIsExtreme 101 | else if (AEpsilon = 0) then 102 | OK := SameValue(AExpected, AActual) 103 | else 104 | OK := (Abs(AExpected - AActual) <= AEpsilon); 105 | 106 | if (not OK) then 107 | Fail('%s: Expected: %.6f, Actual: %.6f', [AMsg, AExpected, AActual]); 108 | end; 109 | 110 | procedure TUnitTest.CheckFalse(const ACondition: Boolean); 111 | begin 112 | Inc(FChecksTotal); 113 | if (ACondition) then 114 | Fail('Expected False but was True'); 115 | end; 116 | 117 | procedure TUnitTest.CheckTrue(const ACondition: Boolean); 118 | begin 119 | Inc(FChecksTotal); 120 | if (not ACondition) then 121 | Fail('Expected True but was False'); 122 | end; 123 | 124 | constructor TUnitTest.Create; 125 | begin 126 | inherited; 127 | end; 128 | 129 | procedure TUnitTest.Fail(const AMsg: String; const AArgs: array of const); 130 | begin 131 | Fail(Format(AMsg, AArgs)); 132 | end; 133 | 134 | procedure TUnitTest.Fail(const AMsg: String); 135 | begin 136 | Inc(FChecksFailed); 137 | TMessageManager.DefaultManager.SendMessage(Self, 138 | TTestFailedMessage.Create(ClassName, FCurrentTestMethodName, AMsg)); 139 | end; 140 | 141 | procedure TUnitTest.Run; 142 | var 143 | Context: TRttiContext; 144 | TestType: TRttiType; 145 | Method: TRttiMethod; 146 | begin 147 | FChecksPassed := 0; 148 | FChecksFailed := 0; 149 | FChecksTotal := 0; 150 | FCurrentTestMethodName := ''; 151 | Context := TRttiContext.Create; 152 | TestType := Context.GetType(ClassType); 153 | if (TestType = nil) then 154 | Fail('Internal test error: cannot get test class type'); 155 | 156 | for Method in TestType.GetMethods do 157 | begin 158 | if (Method.Visibility = TMemberVisibility.mvPublished) 159 | and (Method.ReturnType = nil) and (Method.GetParameters = nil) 160 | and (not Method.IsConstructor) and (not Method.IsDestructor) 161 | and (not Method.IsClassMethod) and (not Method.IsStatic) then 162 | begin 163 | FCurrentTestMethodName := Method.Name; 164 | try 165 | Method.Invoke(Self, []); 166 | except 167 | on E: Exception do 168 | Fail('Unexpected exception of type "%s"', [E.ClassName]); 169 | end; 170 | end; 171 | end; 172 | FChecksPassed := FChecksTotal - FChecksFailed; 173 | end; 174 | 175 | procedure TUnitTest.ShouldRaise(const AExceptionClass: ExceptClass; 176 | const AProc: TProc); 177 | begin 178 | try 179 | AProc(); 180 | except 181 | on E: Exception do 182 | begin 183 | if (E.ClassType = AExceptionClass) then 184 | Exit 185 | else 186 | Fail('Expected exception of type "%s", but got exception of type "%s"', 187 | [AExceptionClass.ClassName, E.ClassName]); 188 | end; 189 | end; 190 | Fail('Expected exception of type "%s"', [AExceptionClass.ClassName]); 191 | end; 192 | 193 | initialization 194 | USFormatSettings := TFormatSettings.Create('en-US'); 195 | USFormatSettings.ThousandSeparator := ','; 196 | USFormatSettings.DecimalSeparator := '.'; 197 | 198 | end. 199 | -------------------------------------------------------------------------------- /UnitTests/info.plist.TemplateOSX.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%VersionInfoPListKeys%> 6 | <%ExtraInfoPListKeys%> 7 | 8 | 9 | -------------------------------------------------------------------------------- /UnitTests/info.plist.TemplateiOS.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%VersionInfoPListKeys%> 6 | <%ExtraInfoPListKeys%> 7 | <%StoryboardInfoPListKey%> 8 | 9 | 10 | -------------------------------------------------------------------------------- /libmp-accurate_android32.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/libmp-accurate_android32.a -------------------------------------------------------------------------------- /libmp-accurate_android64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/libmp-accurate_android64.a -------------------------------------------------------------------------------- /libmp_android32.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/libmp_android32.a -------------------------------------------------------------------------------- /libmp_android64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/libmp_android64.a -------------------------------------------------------------------------------- /mp-accurate_ios64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/mp-accurate_ios64.a -------------------------------------------------------------------------------- /mp-accurate_mac64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/mp-accurate_mac64.a -------------------------------------------------------------------------------- /mp_ios64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/mp_ios64.a -------------------------------------------------------------------------------- /mp_mac64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/mp_mac64.a -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Neslib.MultiPrecision 2 | 3 | ## High-Precision Floating-Point Types for Delphi 4 | 5 | Neslib.MultiPrecision adds two additional floating-point types for use with Delphi. These offer a precision that is up to 4 times larger than that of the `Double` type. 6 | 7 | Neslib.MultiPrecision is build on top of the [QD 2.3.22](https://www.davidhbailey.com/dhbsoftware/) and works on: 8 | 9 | * Windows (32-bit and 64-bit) 10 | * MacOS (64-bit) 11 | * iOS (64-bit, *no* simulator) 12 | * Android (32-bit and 64-bit) 13 | 14 | The algorithms used for these types were developed by David H. Bailey, Yozo Hida and Xiaoye S. Li. Take a look the the [QD.pdf](C/qd.pdf) file in the C subdirectory if you are interested in the details. 15 | 16 | ## Installation 17 | 18 | To install: 19 | 20 | ```shell 21 | > git clone https://github.com/neslib/Neslib.MultiPrecision 22 | ``` 23 | 24 | This library has no dependencies on other libraries. There are also no run-time dependencies. The underlying C/C++ QD library is linked into the executable using object files or static libraries. 25 | 26 | ## Two new Floating-Point Types 27 | 28 | This library defines two additional floating-point types: 29 | 30 | * `DoubleDouble`: this is a 128-bit type that has twice the precision of the `Double` type. 31 | * `QuadDouble`: this is a 256-bit type that has four times the precision of the `Double` type. 32 | 33 | Both types have the same range as the Double type (about ± 10308) but much higher precision. Compared to `Single` and `Double`: 34 | 35 | | Type | Exponent
Bits | Mantissa
Bits | Precision
(decimal digits) | 36 | | ------------ | :----------------: | :----------------: | :-----------------------------: | 37 | | Single | 9 | 24 | 7 | 38 | | Double | 12 | 53 | 16 | 39 | | DoubleDouble | 12 | 106 | 32 | 40 | | QuadDouble | 12 | 212 | 64 | 41 | 42 | > The names `DoubleDouble` and `QuadDouble` come from the underlying QD library. I considered naming these `Float128` and `Float256` instead, but there are already official IEEE specifications for such (hardware) types. And since these are not compatible with `DoubleDouble` and `QuadDouble`, I didn't want to add confusion. 43 | 44 | The underlying QD library does *not* use emulation for calculations. Instead, it uses the existing floating-point capabilities of the CPU to use either 2 or 4 `Double` values to increase the precision. As a result, these types are much faster than other arbitrary/high precision math libraries using the same precision. Also, as opposed to many other libraries, these types don't require dynamic memory allocations, which further helps performance and also reduces memory fragmentation. 45 | 46 | ## Usage 47 | 48 | The `DoubleDouble` and `QuadDouble` types can be used much the same way as the `Double` type. They support the usual operators (`+`, `-`, `*`, `/`, `=`, `<>`, `<`, `<=`, `>` and `>=`) as well as most methods available for the record helpers for the `Double` type (`IsNan`, `IsInfinity`, `IsNegativeInfinity`, `IsPositiveInfinity`, `ToString`, `Parse` and `TryParse`). There are methods and operators to convert to and from `Double`, `DoubleDouble`, `QuadDouble` and `String`. 49 | 50 | Since the Delphi language doesn't allow you to enter high-precision floating-point literals in source code, the value of a `DoubleDouble` or `QuadDouble` variable must be initialized in some other way. There are various options (assuming `DD` is of type `DoubleDouble` here): 51 | 52 | * Use one of the `Init` overloads. For example, `DD.Init(1.23);` to initialize a `DoubleDouble` from a `Double`. 53 | * Use an explicit cast, as in `DD := DoubleDouble(1.23);`. 54 | * Use one of the predefined constants, as in `DD := DoubleDouble.Pi;`. 55 | * Or perhaps the easiest way is to just assign a string value, as in `DD := '3.1415926535897932384626433832795';`. 56 | 57 | > I didn't add *implicit* operators, such as `DD := 1.23;`, since those can lead to unintentional conversions that impact performance. 58 | 59 | It's important that you call `MultiPrecisionInit` *before* performing any `DoubleDouble`/`QuadDouble` calculations. This prepares the FPU/CPU for high-precision math. You can use `MultiPrecisionReset` to restore the FPU/CPU to its previous state. 60 | 61 | ### Customization 62 | 63 | The default configuration of the library is suitable for most applications. This configuration sacrifices a bit of accuracy for increased speed. If accuracy is more important than speed for your purposes, then you can compile the library with the `MP_ACCURATE` define. This will make many calculations a bit slower but more accurate. 64 | 65 | ## Mathematical Functions 66 | 67 | The underlying QD library (and thus this library) supports a variety of common mathematical functions. In addition, the Neslib.MultiPrecision library adds numerous equivalents of functions found in the System.SysUtils and System.Math units. 68 | 69 | | Name | Description | 70 | | ------------------------------------------------------------ | ------------------------------------------------- | 71 | | StrToDoubleDouble, StrToQuadDouble,
StrToDoubleDoubleDef, StrToQuadDoubleDef,
TryStrToFloat | Convert from string | 72 | | FloatToStr, FloatToStrF | Convert to string | 73 | | Inverse | Calculate reciprocal | 74 | | Rem | Calculate remainder, rounding to nearest | 75 | | DivRem | Calculate result of division, including remainder | 76 | | FMod | Calculate remainder, rounded towards zero | 77 | | Sqrt, Sqr | Square root and Square | 78 | | Trunc, Floor, Ceil, Round | Various rounding methods | 79 | | Abs | Absolute value | 80 | | Min, Max | Return minimum or maximum value | 81 | | InRange, EnsureRange | Compare against range | 82 | | SameValue | Approximate equality check | 83 | | Power, IntPower, NRoot, Ldexp, Exp | Exponential functions | 84 | | Ln, LnXP1, Log2, Log10, LogN | Logarithmic functions | 85 | | Sin, Cos, SinCos, Tan | Trigonometric functions | 86 | | ArcSin, ArcCos, ArcTan, ArcTan2 | Inverse trigonometric functions | 87 | | Sinh, Cosh, SinCosh, Tanh | Hyperbolic functions | 88 | | ArcSinh, ArcCosh, ArcTanh | Inverse hyperbolic functions | 89 | | Cotan, Cot, Secant, Sec, Cosecant, Csc | Reciprocal trigonometric functions | 90 | | CotH, SecH, CscH | Reciprocal hyperbolic functions | 91 | | ArcCot, ArcSec, ArcCsc | Reciprocal inverse trigonometric functions | 92 | | ArcCotH, ArcSecH, ArcCscH | Reciprocal inverse hyperbolic functions | 93 | | RadToDeg, RadToGrad, RadToCycle | Convert from radians | 94 | | DegToRad, DegToGrad, DegToCycle | Convert from degrees | 95 | | GradToRad, GradToDeg, GradToCycle | Convert from grads | 96 | | CycleToRad, CycleToDeg, CycleToGrad | Convert from cycles | 97 | 98 | ## Samples 99 | 100 | A fun way to demonstrate high-precision math is by calculating the [Mandelbrot fractal](https://en.wikipedia.org/wiki/Mandelbrot_set). As you zoom into the fractal, you need more and more precision. The Samples subdirectory contains a FireMonkey application that generates the Mandelbrot fractal at 4 levels of precision (`Single`, `Double`, `DoubleDouble` and `QuadDouble`). 101 | 102 | The following image shows a tiny section of the fractal using a magnification of one quadrillion (1015, aka one billiard in Europe) and `Double` precision: 103 | 104 | ![](readme1.png) 105 | 106 | You can clearly see that the `Double` type doesn't provide enough precision at this magnification level. The `DoubleDouble` type offers more than enough precision though: 107 | 108 | ![](readme2.png) 109 | 110 | It's not until you reach a magnification level of 1031, that you need to switch to `QuadDouble`. 111 | 112 | ## More Information 113 | 114 | There is more to Neslib.MultiPrecision than described above. For more details you can look at the well-documented `Neslib.MultiPrecision.pas` source file. Additional usage samples can be found in the UnitTests subdirectory and the Mandelbrot sample application. 115 | 116 | If you are interested in the technical details and algorithms used for these types, you can take a look at the [QD.pdf](C/qd.pdf) file in the C subdirectory. 117 | 118 | ### Building the C/C++ Library 119 | 120 | As said, this library is build on top of the QD library. This is a C/C++ library that is linked into your Delphi executable using object files or static libraries. If you ever need or want to build these object files and static libraries yourself, then take a look at the [readme.txt](C/readme.txt) file in the C subdirectory for instructions. 121 | 122 | ## License 123 | 124 | Neslib.MultiPrecision is licensed under the Simplified BSD License. See License.txt for details. 125 | 126 | The underlying QD library is licensed under the BSD-LBNL License. See the document [BSD-LBNL-License.doc](C/BSD-LBNL-License.doc) in the C subdirectory for details. -------------------------------------------------------------------------------- /readme1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/readme1.png -------------------------------------------------------------------------------- /readme2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neslib/Neslib.MultiPrecision/33def6bbcb984d8db5a0d67d7a3c75a16bbceb3a/readme2.png --------------------------------------------------------------------------------