Double precision floating-point types don’t cut it for you, then the Neslib.MultiPrecision library may be just the thing. It provides up to 4 times the precision, while still being pretty fast compared to arbitrary precision libraries.
Neslib.MultiPrecision is a personal project that 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
It is build on top of the QD 2.3.22 and works on:
- Windows (32-bit and 64-bit)
- MacOS (64-bit)
- iOS (64-bit, no simulator)
- Android (32-bit and 64-bit)
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 file in the repository if you are interested in the details.
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.
You can find the library on GitHub in my Neslib.MultiPrecision repository.
Two new Floating-Point Types
This library defines two additional floating-point types:
DoubleDouble: this is a 128-bit type that has twice the precision of the
QuadDouble: this is a 256-bit type that has four times the precision of the
Both types have the same range as the Double type (about ± 10308) but much higher precision:
|Type||Exponent Bits||Mantissa Bits||Precision (decimal digits)|
QuadDoublecome from the underlying QD library. I considered naming these
Float256instead, but there are already official IEEE specifications for such (hardware) types. And since these are not compatible with
QuadDouble, I didn’t want to add confusion.
The underlying QD library does not use emulation for calculations. Instead, it uses some interesting algorithms and 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. In addition, many other libraries have (L)GPL (like) licenses, which may not be suitable for your purposes. Neslib.MultiPrecision uses a simplified BSD license, and the underlying QD library uses a variation of the BSD license as well, making them suitable for practically all situations.
QuadDouble types can be used much the same way as the
Double type. They support the usual operators (
>=) as well as most methods available for the record helpers for the
Double type (
TryParse). There are methods and operators to convert to and from
Since the Delphi language doesn’t allow you to enter high-precision floating-point literals in source code, the value of a
QuadDouble variable must be initialized in some other way. There are various options (assuming
DD is of type
- Use one of the
Initoverloads. For example,
DD.Init(1.23);to initialize a
- Use an explicit cast, as in
DD := DoubleDouble(1.23);.
- Use one of the predefined constants, as in
DD := DoubleDouble.Pi;.
- Or perhaps the easiest way is to just assign a string value, as in
DD := '3.1415926535897932384626433832795';.
I didn’t add implicit operators, such as
DD := 1.23;, since those can lead to unintentional conversions that impact performance.
It’s important that you call
MultiPrecisionInit before performing any
QuadDouble calculations. This prepares the FPU/CPU for high-precision math. You can use
MultiPrecisionReset to restore the FPU/CPU to its previous state.
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.
The underlying QD library (and thus this library) supports a variety of common mathematical functions, such as trigonometric, exponential and logarithmic functions.
In addition, the Neslib.MultiPrecision library adds numerous equivalents of functions found in the System.SysUtils and System.Math units, such as
A fun way to demonstrate high-precision math is by calculating the Mandelbrot fractal. 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 (
The following image shows a tiny section of the fractal using a magnification of one quadrillion (1015, aka one billiard in Europe) and
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:
It’s not until you reach a magnification level of 1031, that you need to switch to
QuadDouble. The sample application allows you to enter a magnification level of up to 1038:
I know, these images don’t show a particularly interesting part of the Mandelbrot set. This is because I chose center coordinates that aren’t near the “cardioid” or other bulbs of the set. This results in fewer calculations, so the sample app can focus more on differences in precision without having to wait forever for the rendering to complete.
This sample application is build with the FireMonkey framework, so it works on all platforms natively supported by Delphi.
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.
If you are interested in the technical details and algorithms used for these types, you can take a look at the QD.pdf file in the C subdirectory.
If you need arbitrary precision, or support for big integers, decimals and rationals, then I can highly recommend Rudy Velthuis’s DelphiBigNumbers libary.