High-performance cross-platform 128-bit arithmetic for SIMD applications.
Project description
High-performance cross-platform 128-bit arithmetic for SIMD applications.
simd-f128
Read the Official Documentation: docs/index.md
Try the Live WebAssembly Demo: https://tiw302.github.io/simd-f128/demo/
Verified Compatibility — 11/11 Platforms Passing
| Architecture | Platform | Verified Backend |
|---|---|---|
| x86_64 (Modern) | Linux / Windows | AVX2 (Vectorized) |
| x86_64 (Legacy) | Linux | SSE2 (Emulated SIMD) |
| ARM64 (Apple) | macOS (M1/M2/M3) | NEON (Vectorized) |
| ARM64 (Android) | Mobile | NEON (Vectorized) |
| ARMv7 (Android) | Mobile | Scalar C11 |
| WebAssembly | Chrome / Node.js | WASM-SIMD128 |
| WebAssembly | Universal Web | WASM Scalar |
| RISC-V64 | Linux (QEMU) | Scalar C11 |
| General Desktop | Linux / Windows | Scalar C11 Fallback |
Table of Contents
| Introduction | Setup & Build | Components | Resources | Community |
|---|---|---|---|---|
| Overview | Requirements | Core Engine | API Docs | CI Status |
| Why? | Toolchains | Constants | Math Theory | Contributing |
| Philosophy | Installation | I/O Utilities | Examples | License |
| Math Functions | Limitations & Technical Notes | |||
| Utilities & Comparisons | ||||
| C++ Wrapper |
Introduction
simd-f128 is a professional-grade, header-only C library for 128-bit (Double-Double) floating-point arithmetic. It targets the precision gap between standard 64-bit IEEE 754 doubles and heavyweight arbitrary-precision libraries, providing approximately 31-32 decimal digits of accuracy with zero heap allocation overhead.
Designed for demanding workloads such as fractal rendering, physical simulations, and orbital mechanics — where double precision falls short but libquadmath or GMP would be excessive.
Why simd-f128?
Ever zoomed into a Mandelbrot set and watched the detail dissolve into grey mush? That's double precision dying — at zoom levels beyond ~10^-14, two distinct coordinates become the same value and the image collapses entirely. The same silent failure happens in long-running simulations, ill-conditioned linear algebra, and anywhere small errors compound over time.
The usual fixes each carry a significant cost:
| Option | Precision | Allocation | Portability | Complexity |
|---|---|---|---|---|
double |
~15 digits | None | Universal | None |
long double |
18-19 digits (x87) | None | Compiler-dependent | Low |
__float128 (GCC) |
~33 digits | None | GCC/Clang only | Medium |
| GMP / MPFR | Arbitrary | Heap | Portable | High |
| [x] simd-f128 | ~31 digits | None | Universal | Low |
__float128 gets close on precision but locks you into GCC/Clang and is noticeably slower in tight loops. GMP/MPFR are powerful but heap-allocating inside a render loop is a non-starter.
simd-f128 occupies the exact gap: it doubles usable precision with zero allocation, zero dependencies, and no compiler lock-in — proven in practice by mandelbrot-c, which achieves stable deep-zoom rendering at coordinates down to 10^-28, far beyond what standard double can represent.
Design Philosophy
The library is built around three constraints that were never relaxed during development:
Zero allocation. Every operation executes entirely in CPU registers. There are no calls to malloc, no temporary buffers, and no GC pressure. This makes simd-f128 suitable for use inside tight render loops, interrupt handlers, and embedded firmware where heap allocation is prohibited.
No configuration required. The correct SIMD backend — AVX2, NEON, WASM-SIMD, or scalar — is selected automatically at compile time based on the target architecture. Passing the wrong flag produces a compile error immediately rather than silently degrading precision at runtime.
Standard C foundation. The library is built entirely on IEEE 754 double arithmetic and C11 standard library functions. It does not rely on compiler extensions, non-standard intrinsics outside of guarded #ifdef blocks, or platform-specific ABI assumptions. The scalar fallback compiles and produces correct results on any C99-compliant toolchain.
Limitations & Technical Notes
Double-Double vs IEEE 754 128-bit:
Please note that simd-f128 uses Double-Double arithmetic (an unevaluated sum of two standard 64-bit double values) to achieve approximately 31 decimal digits of precision. It is not a strictly compliant IEEE 754 binary128 implementation.
While this approach offers massive performance benefits and is perfect for deeply zooming into fractals (like in mandelbrot-c, it is susceptible to Catastrophic Cancellation in specific scenarios (e.g., subtracting two nearly identical values). If you are building highly sensitive physics simulations or rigorous numerical analysis tools where IEEE 754 edge-case compliance is strictly required, a heavier library like GMP/MPFR or compiler-specific __float128 may be more appropriate.
Requirements
| Component | Requirement |
|---|---|
| C Standard | C11 or later (C99 compatible for scalar path) |
| C++ Standard | C++11 or later (for simd_f128.hpp only) |
| Compiler | GCC 4.9+, Clang 3.5+, MSVC 2019+, Emscripten 3.0+ |
| Math library | -lm required on Linux/UNIX (for fma()) |
Verified Toolchains
The following toolchains are tested on every commit via CI. All others fall back to the scalar path and are expected to produce correct results.
| Toolchain | Version | Platform | Backend |
|---|---|---|---|
| GCC | 11+ | Linux x86_64 | Scalar, AVX2 |
| GCC (aarch64-linux-gnu) | 11+ | Linux ARM64 (QEMU) | NEON |
| GCC (arm-linux-gnueabihf) | 11+ | Linux ARMv7 (QEMU) | Scalar + VFPv4 |
| GCC (riscv64-linux-gnu) | 11+ | Linux RISC-V64 (QEMU) | Scalar |
| Clang | 14+ | macOS Apple Silicon | NEON |
| Clang | 14+ | macOS Intel | Scalar, AVX2 |
| MSVC | 2022 | Windows x64 | Scalar |
| Emscripten | 3.0+ | WASM (Node.js) | WASM-SIMD, Scalar |
Build and Installation
simd-f128 can be integrated natively via C/C++ headers, Python, or JavaScript (WebAssembly).
Python (PyPI)
pip install simd-f128
JavaScript / Node.js (NPM)
npm install @tiw302/simd-f128
C/C++ (Header Only)
simd-f128 is header-only. The simplest integration is copying the include/ directory directly into your project, then defining the implementation macro in exactly one translation unit:
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.h>
#include <simd_f128_io.h> // optional
All other translation units include the headers without the macro.
For C++ projects, include the convenience wrapper instead:
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.hpp> // pulls in all headers automatically
CMake
System Install (Recommended)
You can install the library system-wide to easily use find_package in other projects:
cmake -S . -B build
sudo cmake --install build
Then in your project's CMakeLists.txt:
find_package(simd_fp REQUIRED)
target_link_libraries(my_app PRIVATE simd_fp::simd_fp)
Local Build Options
# Scalar backend (default - works everywhere)
cmake -S . -B build
cmake --build build
# AVX2 backend (Intel/AMD Haswell+)
cmake -S . -B build -DSIMD_F128_AVX2=ON
cmake --build build
# WebAssembly + SIMD128 (Chrome 91+, Firefox 89+, Safari 16.4+, Node.js 16+)
emcmake cmake -S . -B build -DSIMD_F128_WASM=ON
cmake --build build
# WebAssembly Scalar (maximum browser compatibility)
emcmake cmake -S . -B build
cmake --build build
# ARMv7 - optional flag for hardware FMA on VFPv4 cores
cmake -S . -B build -DCMAKE_C_FLAGS="-mfpu=neon-vfpv4 -mfloat-abi=hard"
cmake --build build
AArch64 (Apple Silicon, Graviton, Android ARM64) requires no flags - NEON is auto-detected. Run tests after building:
ctest --test-dir build
simd_f128.h (Core)
The central engine of the library. Implements the Double-Double type and all fundamental arithmetic operations. All functions are static inline - no separate compilation unit is needed beyond the SIMD_F128_IMPLEMENTATION guard.
Key properties:
- ~106-bit mantissa - roughly 31-32 decimal digits of precision.
- Zero heap allocation - all operations execute directly in CPU registers, suitable for tight inner loops.
- Automatic SIMD dispatch - selects AVX2 (
__m128d) on Intel/AMD, NEON (float64x2_t) on ARM64/Apple Silicon, WASM-SIMD (v128_t) on the web, or falls back to scalar C99. - Branchless implementation - consistent execution time, no pipeline stalls.
- Strict IEEE 754 foundation - built on standard
double, fully compatible with existing hardware.
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.h>
int main() {
simd_f128 a = simd_f128_from_double(1.234567890123456789);
simd_f128 b = simd_f128_from_double(2.0);
simd_f128 sum = simd_f128_add(a, b);
simd_f128 diff = simd_f128_sub(a, b);
simd_f128 prod = simd_f128_mul(a, b);
simd_f128 quot = simd_f128_div(a, b);
simd_f128 root = simd_f128_sqrt(a);
return 0;
}
simd_f128_consts.h
Pre-computed, high-precision mathematical constants stored as Double-Double pairs. Each constant captures the full ~106-bit mantissa, avoiding the precision loss inherent in standard 64-bit initialisers.
#include <simd_f128.h>
#include <simd_f128_consts.h>
int main() {
simd_f128 pi = SIMD_F128_PI; // 3.14159265358979323846...
simd_f128 e = SIMD_F128_E; // 2.71828182845904523536...
simd_f128 sqrt_2 = SIMD_F128_SQRT2; // 1.41421356237309504880...
simd_f128 ln2 = SIMD_F128_LN2; // 0.69314718055994530941...
return 0;
}
simd_f128_io.h
Handles conversion between the internal Double-Double representation and human-readable decimal strings. Standard printf formatting cannot faithfully render 128-bit values; this header uses an iterative high-precision extraction algorithm to produce up to 32 correct decimal places.
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.h>
#include <simd_f128_io.h>
int main() {
simd_f128 val = simd_f128_from_double(3.141592653589793);
// direct console output
simd_f128_print(val);
// string conversion for logging or ui
char buffer[128];
simd_f128_to_string(buffer, sizeof(buffer), val);
return 0;
}
simd_f128_math.h
Advanced mathematical functions built on top of the core Double-Double primitives. All functions are static inline and require no additional compilation unit.
Algorithms used:
exp— range reduction to $N=16$ intervals followed by a 12-degree Chebyshev minimax polynomial, then exact scaling vialdexpand a 16-entry lookup table. Handles overflow (> 709) and underflow (< -745) explicitly.log— seeds from the standarddoublelog(), then refines with 2 iterations of Halley's method (cubic convergence), which is sufficient to recover all 31-32 digits.pow— computed asexp(exp * log(base)). ReturnsNaNfor negative bases.sin— range-reduces to quadrant ($[-\pi/4, \pi/4]$) then evaluates a 11-degree Chebyshev minimax polynomial.cos— range-reduces to quadrant ($[-\pi/4, \pi/4]$) then evaluates a 11-degree Chebyshev minimax polynomial.
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.h>
#include <simd_f128_consts.h>
#include <simd_f128_math.h>
int main() {
simd_f128 x = SIMD_F128_PI;
// e^π
simd_f128 epi = simd_f128_exp(x);
// ln(e) == 1
simd_f128 one = simd_f128_log(SIMD_F128_E);
// 2^10 == 1024
simd_f128 base = simd_f128_from_double(2.0);
simd_f128 exp = simd_f128_from_double(10.0);
simd_f128 pw = simd_f128_pow(base, exp);
// sin(π/6) == 0.5
simd_f128 half_pi = simd_f128_mul(x, simd_f128_from_double(1.0 / 6.0));
simd_f128 s = simd_f128_sin(half_pi);
// cos(0) == 1
simd_f128 c = simd_f128_cos(simd_f128_from_double(0.0));
return 0;
}
Note:
sinandcosuse a simplified range reduction suitable for moderate arguments. For very large inputs (|x| > ~10^15), consider applying Payne-Hanek argument reduction externally before calling these functions.
simd_f128_utils.h
Comparison operators and utility functions. All are static inline and work with any SIMD backend.
The foundation is simd_f128_cmp, which compares the hi components first and only falls through to the lo components when hi values are identical — matching the canonical Double-Double ordering rule.
#include <simd_f128.h>
#include <simd_f128_utils.h>
int main() {
simd_f128 a = simd_f128_from_double(1.0);
simd_f128 b = simd_f128_from_double(2.0);
// comparisons
int lt = simd_f128_lt(a, b); // 1
int eq = simd_f128_eq(a, b); // 0
int ge = simd_f128_ge(b, a); // 1
// utility
simd_f128 neg = simd_f128_from_double(-3.14);
simd_f128 abs_val = simd_f128_abs(neg); // 3.14...
simd_f128 lo = simd_f128_min(a, b); // 1.0
simd_f128 hi = simd_f128_max(a, b); // 2.0
return 0;
}
simd_f128.hpp
A modern C++ wrapper that makes simd_f128 feel like a native arithmetic type. Include this single header in C++ projects — it pulls in all other headers automatically.
Features:
f128::float128class with full operator overloading (+,-,*,/,+=,-=,*=,/=).- Full interoperability with
std::complex<double>viaf128::complex128. - Seamless integration with the Eigen matrix library via
simd_f128_eigen.hpp. - All six comparison operators (
==,!=,<,>,<=,>=). - Unary negation (
-x). std::ostreamintegration (std::cout << val).- Free functions mirroring
<cmath>:f128::exp,f128::log,f128::pow,f128::sin,f128::cos,f128::sqrt,f128::abs. - Predefined constants:
f128::pi,f128::e,f128::sqrt2,f128::ln2.
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.hpp>
#include <iostream>
int main() {
f128::float128 a(1.5);
f128::float128 b(2.5);
// natural arithmetic
f128::float128 sum = a + b;
f128::float128 prod = a * b;
// math functions
f128::float128 root = f128::sqrt(a);
f128::float128 s = f128::sin(f128::pi);
// stream output
std::cout << "a + b = " << sum << "\n";
std::cout << "a * b = " << prod << "\n";
std::cout << "sqrt(a) = " << root << "\n";
// comparisons
if (a < b) {
std::cout << "a is smaller\n";
}
return 0;
}
The float128 class stores a simd_f128 data member publicly, so it can be passed directly to any C API function when needed:
f128::float128 val(3.14);
simd_f128_print(val.data); // call c api directly
API Reference
simd_f128.h
| Function | Signature | Description |
|---|---|---|
simd_f128_from_double |
simd_f128 simd_f128_from_double(double d) |
Promote a double to 128-bit. lo is initialised to 0.0. |
simd_f128_extract |
void simd_f128_extract(simd_f128 x, double* hi, double* lo) |
Extract the hi and lo components into separate doubles. |
simd_f128_add |
simd_f128 simd_f128_add(simd_f128 a, simd_f128 b) |
Double-Double addition via Knuth's TwoSum. |
simd_f128_sub |
simd_f128 simd_f128_sub(simd_f128 a, simd_f128 b) |
Double-Double subtraction (negates b, then adds). |
simd_f128_mul |
simd_f128 simd_f128_mul(simd_f128 a, simd_f128 b) |
Double-Double multiplication via Dekker's TwoProd + FMA. |
simd_f128_div |
simd_f128 simd_f128_div(simd_f128 a, simd_f128 b) |
Double-Double division via Newton-Raphson reciprocal refinement. |
simd_f128_sqrt |
simd_f128 simd_f128_sqrt(simd_f128 x) |
Square root via inverse-sqrt Newton-Raphson + residual correction. |
simd_f128_consts.h
| Constant | Value (first 32 digits) |
|---|---|
SIMD_F128_PI |
3.14159265358979323846264338327950... |
SIMD_F128_E |
2.71828182845904523536028747135266... |
SIMD_F128_SQRT2 |
1.41421356237309504880168872420969... |
SIMD_F128_LN2 |
0.69314718055994530941723212145817... |
simd_f128_io.h
| Function | Signature | Description |
|---|---|---|
simd_f128_print |
void simd_f128_print(simd_f128 x) |
Print the value to stdout followed by a newline. |
simd_f128_to_string |
void simd_f128_to_string(char* buf, size_t buf_size, simd_f128 x) |
Write up to 32 decimal digits into buf. buf must be at least 64 bytes. Handles nan, inf, and negative values. |
simd_f128_math.h
| Function | Signature | Description |
|---|---|---|
simd_f128_exp |
simd_f128 simd_f128_exp(simd_f128 x) |
e^x. Returns +Inf for x > 709, 0 for x < -745. |
simd_f128_log |
simd_f128 simd_f128_log(simd_f128 x) |
Natural logarithm. Returns NaN for x ≤ 0. |
simd_f128_pow |
simd_f128 simd_f128_pow(simd_f128 base, simd_f128 exp) |
base^exp. Returns 0 for base == 0, NaN for base < 0. |
simd_f128_sin |
simd_f128 simd_f128_sin(simd_f128 x) |
Sine (radians). Best accuracy for moderate arguments. |
simd_f128_cos |
simd_f128 simd_f128_cos(simd_f128 x) |
Cosine (radians). Implemented as sin(x + π/2). |
simd_f128_utils.h
| Function | Signature | Description |
|---|---|---|
simd_f128_cmp |
int simd_f128_cmp(simd_f128 a, simd_f128 b) |
Returns -1 if a < b, 1 if a > b, 0 if equal. |
simd_f128_eq |
int simd_f128_eq(simd_f128 a, simd_f128 b) |
1 if a == b. |
simd_f128_gt |
int simd_f128_gt(simd_f128 a, simd_f128 b) |
1 if a > b. |
simd_f128_lt |
int simd_f128_lt(simd_f128 a, simd_f128 b) |
1 if a < b. |
simd_f128_ge |
int simd_f128_ge(simd_f128 a, simd_f128 b) |
1 if a >= b. |
simd_f128_le |
int simd_f128_le(simd_f128 a, simd_f128 b) |
1 if a <= b. |
simd_f128_abs |
simd_f128 simd_f128_abs(simd_f128 x) |
Absolute value. Correctly handles -0.0 in the lo component. |
simd_f128_min |
simd_f128 simd_f128_min(simd_f128 a, simd_f128 b) |
Returns the lesser of a and b. |
simd_f128_max |
simd_f128 simd_f128_max(simd_f128 a, simd_f128 b) |
Returns the greater of a and b. |
simd_f128.hpp (C++ only)
| Symbol | Kind | Description |
|---|---|---|
f128::float128 |
Class | C++ wrapper around simd_f128. |
f128::float128(double) |
Constructor | Construct from a double. |
f128::float128(simd_f128) |
Constructor | Construct from a raw simd_f128. |
float128::extract(hi, lo) |
Method | Extract hi and lo components. |
+, -, *, / |
Operators | Arithmetic operators. |
+=, -=, *=, /= |
Operators | Compound assignment operators. |
==, !=, <, >, <=, >= |
Operators | Comparison operators. |
operator-() |
Unary | Negation. |
float128::to_string() |
Method | Returns std::string with 32-digit representation. |
operator<< |
Stream | std::ostream integration. |
f128::exp, f128::log, f128::pow |
Free functions | Transcendental math. |
f128::sin, f128::cos, f128::sqrt, f128::abs |
Free functions | Trigonometric and utility math. |
f128::pi, f128::e, f128::sqrt2, f128::ln2 |
Constants | High-precision constants as float128. |
Precision Demonstration & Test Results
The core advantage of simd-f128 is preserving small values that standard 64-bit doubles silently discard. All operations execute strictly within SIMD registers without heap allocation.
Here is an actual test run and precision comparison from the Extreme Performance build:
~/Public/simd-f128 master* ⇡
❯ ctest --test-dir build -C Release
Test project /simd-f128/build
Start 1: arithmetic_test
1/2 Test #1: arithmetic_test .................. Passed 0.00 sec
Start 2: arithmetic_test_cpp
2/2 Test #2: arithmetic_test_cpp .............. Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
~/Public/simd-f128 master* ⇡
❯ ./build/example_precision
--- precision comparison: double vs simd-fp ---
[double] 1.0 + 1e-17 = 1.00000000000000000000
precision lost: yes
[simd-fp] 1.0 + 1e-17 = 1.00000000000000001000000000000000
precision lost: no
~/Public/simd-f128 master* ⇡
❯ ./build/example_mandelbrot
--- mandelbrot core loop (128-bit precision) ---
did not escape after 500 iterations (point is inside the Mandelbrot set)
final |z| components:
zx = -0.78124578860038387003505655582563
zy = 0.35443468442007221298624089031401
Benchmark: Raw Speed (Google Benchmark)
Because simd-f128 operations are purely CPU-register bound, they are extremely fast. A single simd_f128_mul completes in ~12 nanoseconds, and advanced math functions run in the ~200-600ns range.
Run on (12 X 2445.27 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x6)
L1 Instruction 32 KiB (x6)
L2 Unified 512 KiB (x6)
L3 Unified 16384 KiB (x1)
-----------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------
BM_Double_Add 3.07 ns 3.06 ns 228461238
BM_Double_Mul 3.07 ns 3.06 ns 228446705
BM_SimdF128_Add 14.3 ns 14.3 ns 46529427
BM_SimdF128_Mul 12.0 ns 12.0 ns 59734955
BM_SimdF128_Div 0.422 ns 0.421 ns 1000000000
BM_SimdF128_Sqrt 0.434 ns 0.432 ns 1000000000
BM_SimdF128_Exp 217 ns 217 ns 3234247
BM_SimdF128_Log 634 ns 632 ns 1118796
BM_SimdF128_Sin 219 ns 218 ns 3207477
BM_SimdF128_Cos 230 ns 230 ns 3029368
BM_SimdF128_Atan 1831 ns 1825 ns 384206
BM_SimdF128_Pow 977 ns 973 ns 753952
Double-Double Arithmetic
simd-f128 represents a value $x$ as the unevaluated sum of two IEEE 754 doubles:
$$x = x_{hi} + x_{lo}, \quad |x_{lo}| \leq \frac{1}{2} , \text{ulp}(x_{hi})$$
This non-overlapping constraint provides ~106 bits of mantissa — approximately double the precision of a single double.
Implementation basis:
- Addition: TwoSum (Knuth) — An error-free transformation (EFT) for addition that captures the exact rounding residual.
- Multiplication: TwoProd (Dekker) — Exploits hardware FMA (Fused Multiply-Add) where available. On platforms lacking FMA, it seamlessly falls back to Veltkamp's Split to divide 53-bit mantissas into 26-bit halves, calculating the exact error product natively without precision loss.
- Division: Newton-Raphson Iteration — Approximates the reciprocal $1/b_{hi}$ and refines it quadratically. Includes rigorous guards against
NaNpropagation during division-by-zero scenarios. - Square Root: Fast Inverse Square Root (
rsqrt) — A heavily optimized 128-bit variant of the famous algorithm used in 3D physics engines. Computes $1/\sqrt{x}$ directly via Newton-Raphson to save CPU cycles in deep-zoom Mandelbrot escapes. - Normalisation — Every arithmetic operation rigidly re-establishes the non-overlapping property before returning.
No memory allocation is required. The entire number lives in two registers.
Known limitations:
- Numerical range is identical to IEEE 754
double(~1.8 × 10^308). The library extends mantissa precision only; exponent range is unchanged. NaNandInfinitypropagate through standarddoublerules.sinandcosuse simplified range reduction. For large arguments (|x| ≫ 2π), apply Payne-Hanek reduction externally before calling.powdoes not support negative bases; usesimd_f128_mul+simd_f128_expfor integer powers of negative numbers.- On ARMv7, FMA requires VFPv4 hardware (Cortex-A7, A15, A17, A53+) and the
-mfpu=neon-vfpv4flag.
Examples
Three runnable examples are provided under examples/.
basic_arithmetic.c — entry point for new users. Loads SIMD_F128_PI and SIMD_F128_E from simd_f128_consts.h, performs addition, subtraction, and multiplication, then prints all three results at full 32-digit precision.
precision_demo.c — demonstrates the core motivation for using this library. Adds 1e-17 to 1.0 using both a standard double and a simd_f128, then prints both results side by side. The double result silently loses the small value; the simd_f128 result preserves it in the lo component.
mandelbrot_core.c — a realistic use case. Runs the Mandelbrot iteration z = z^2 + c at a deep-zoom coordinate that exceeds 64-bit precision, with the correct escape condition (|z|^2 > 4). Reports whether the point escapes and prints the final zx/zy values at full precision.
Quick example — circle area at 32-digit precision:
#include <stdio.h>
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.h>
#include <simd_f128_consts.h>
#include <simd_f128_io.h>
int main() {
simd_f128 r = simd_f128_from_double(10.0);
simd_f128 r2 = simd_f128_mul(r, r);
simd_f128 area = simd_f128_mul(SIMD_F128_PI, r2);
// output: 314.15926535897932384626433832795028
printf("Circle Area: ");
simd_f128_print(area);
return 0;
}
Same example using the C++ wrapper:
#define SIMD_F128_IMPLEMENTATION
#include <simd_f128.hpp>
#include <iostream>
int main() {
f128::float128 r(10.0);
f128::float128 area = f128::pi * r * r;
// output: 314.15926535897932384626433832795028
std::cout << "Circle Area: " << area << "\n";
return 0;
}
Platform Support & CI Status
Every commit is tested across all backends via GitHub Actions. The table below maps each workflow to the platforms and backends it covers.
Project Structure
.
├── assets/images/ # Logo and documentation media
├── examples/ # Runnable usage examples
│ ├── basic_arithmetic.c
│ ├── precision_demo.c
│ └── mandelbrot_core.c
├── tests/ # Arithmetic unit tests
│ └── test_arithmetic.c
├── .github/workflows/ # CI pipelines (linux, macos, windows, wasm, mobile)
├── include/ # Core library and headers
│ ├── simd_f128.h # Double-Double arithmetic engine
│ ├── simd_f128_consts.h # High-precision mathematical constants
│ ├── simd_f128_io.h # String conversion and console output
│ ├── simd_f128_math.h # Advanced mathematical functions (exp, log, sin, cos, pow)
│ ├── simd_f128_utils.h # Comparison and utility functions (cmp, abs, min, max)
│ └── simd_f128.hpp # Modern C++ wrapper with operator overloading
├── CMakeLists.txt # Cross-platform build configuration
└── LICENSE # MIT License
Used By
| Project | Description |
|---|---|
| mandelbrot-c | Deep-zoom Mandelbrot renderer in C, using simd-f128 for 128-bit precision coordinates |
Contributing
I am still a learner in the field of numerical computing and low-level C programming. If you spot a precision bug, an incorrect algorithm, or an edge case I have missed — especially around FMA behaviour, normalisation stability, or platform-specific SIMD quirks — I would be genuinely grateful for the feedback. Every correction and suggestion is a lesson I would not have found on my own.
If you would like to help:
- Open an issue to discuss bugs, inaccuracies, or potential improvements.
- To contribute code, please fork the repository and open a pull request with a clear description of what was changed and why.
- If you have expertise in Double-Double arithmetic or compiler-level float optimisation, architectural feedback is especially welcome.
Thank you for taking the time to read this far, and for helping make this project more correct.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simd_f128-1.2.4-cp313-cp313-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp313-cp313-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.13, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
401ac99a7d701c174e1bdc9e9099833bc7dc0f62a7acbce390d890ecda30b84d
|
|
| MD5 |
dd83e3341f6425e59eaa5ac8fedb8560
|
|
| BLAKE2b-256 |
5ef16c872546523229aa0bc7cd9d1c4ccf0ede678bd55fac2e3789395eb8a41f
|
File details
Details for the file simd_f128-1.2.4-cp313-cp313-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp313-cp313-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.13, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
196f2f40355e72b702b7cadd07e9742e42a883972eeac959efc00ca3aaf520fa
|
|
| MD5 |
135882a4907194eaa33d68603cb35629
|
|
| BLAKE2b-256 |
16ad9461c4d86151ed7b39a1eacfa731d3bd10650b3ed335f64043f32bf679ae
|
File details
Details for the file simd_f128-1.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a99ab3f90ceabde887d39298b8533e4a9341c20605233c0fa454f037b325bbdb
|
|
| MD5 |
ec13abd1b1b69f828f96bf2234439b9f
|
|
| BLAKE2b-256 |
69d71c715f7c1c66b1fde9e4589cdd96c9b4f66dc5f6289459c96c557dd26e37
|
File details
Details for the file simd_f128-1.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
db6a657cc0b5528424bce7814a3d6dd300370d9b9afab1298e2e7a662cd5df7b
|
|
| MD5 |
d90cb52bf49a0fb2d2caae7731602a94
|
|
| BLAKE2b-256 |
1a9c13f46806f82244e5943e68d5f1d13137c9fe25c75f973ed485bfe047a6cc
|
File details
Details for the file simd_f128-1.2.4-cp312-cp312-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp312-cp312-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.12, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1555cc6647d813f0cd32bf3a54af3840210c43cfbbaf8fb6adc81fecf258c4db
|
|
| MD5 |
83f66fc92b55ce7fe8eb0442e958b550
|
|
| BLAKE2b-256 |
9e3748ac7c006768d5fe920dd4527ee8177f837a0b180c6f025248b16790c742
|
File details
Details for the file simd_f128-1.2.4-cp312-cp312-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp312-cp312-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.12, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a922536d0ef9e7eeeb1b5db1f235ccc0f9d84a4241d86659ac4e881fcb4a017
|
|
| MD5 |
94e09486ac8256f038f9d28be93ce4d4
|
|
| BLAKE2b-256 |
0f7ffd2ae4052daa1c13f3f7f8ba56926106a44206529be4dc1e4e73c96589d4
|
File details
Details for the file simd_f128-1.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00357c056b9117ae33bf8565b78ba2c3822d791d0ad95bd5f1972f84d4a31953
|
|
| MD5 |
0ada49e389f970eb09647bbf0800c2c4
|
|
| BLAKE2b-256 |
31884b4a92a11190f839a84f545acea9ea5bd1eb81182248f83b36d31e73be8a
|
File details
Details for the file simd_f128-1.2.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3a38f5e1060d633484e1366a81ee500e331ab5b90111b51d70bdb8c2bc1b417
|
|
| MD5 |
c4ccc90fc6ac16fcf4b39479f1def025
|
|
| BLAKE2b-256 |
62f82a30ab3181bb26cc7f09c70d72d7cb16e9edb67884a3d3f01bb714b09020
|
File details
Details for the file simd_f128-1.2.4-cp311-cp311-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp311-cp311-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.11, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2b69d1369af94bca1be9fa64e6c8b4ff2b3eb47c0ce0de0369d0af125a29004
|
|
| MD5 |
c213fbb5761bc920a62dc9e55152be04
|
|
| BLAKE2b-256 |
c98e482e5128ac1b82b242a18bfe2e0530ac7f8674965a87c00f6448c88fb418
|
File details
Details for the file simd_f128-1.2.4-cp311-cp311-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp311-cp311-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.11, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d2a96fde50e267d32b889eaae1059a1240f6aae6f3233ece02c629783b0d880
|
|
| MD5 |
131d1f743ae7fbc6cb20a5277ab7e5d3
|
|
| BLAKE2b-256 |
4763f5efda7cb488094872fb1acd276a4d0c27fc79184b6e66f9c7cc5b714e32
|
File details
Details for the file simd_f128-1.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33655614737f05496c1ea799005ec608e73c232e4ab7f454c0c686696e696c2b
|
|
| MD5 |
23c30861b27f88599a54a5c8abc31e06
|
|
| BLAKE2b-256 |
c18d0f053acb37fb9f593df7175be7ba5a58f2ea4fb347a5755eec60bf15db98
|
File details
Details for the file simd_f128-1.2.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd8c664a607d07d521199a0089e8efe9757af37607164106fad11926a64e92a0
|
|
| MD5 |
688cf6834af0fee8302618b3497ee7f2
|
|
| BLAKE2b-256 |
9e4502cf89d9082e7b4219317438ca9d6a42fd70819159aa830a001f15cadebd
|
File details
Details for the file simd_f128-1.2.4-cp310-cp310-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp310-cp310-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.10, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cee5d61a816c20c6e8403be561e839f4946b2e1356f2d737b4db9f001cd5e70
|
|
| MD5 |
8bc11b3780035a83fc9a0b96dc2635d2
|
|
| BLAKE2b-256 |
9c6f7a449b18687fdcd3acd0de707da15007705ff88158a853d71ae5d55e4bbe
|
File details
Details for the file simd_f128-1.2.4-cp310-cp310-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp310-cp310-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.10, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7fe5893ee7130c2e09ad5eca97837e41605b205ece0b089facd739b01bec3094
|
|
| MD5 |
269e44b5743eb7216f72deef8bb8b702
|
|
| BLAKE2b-256 |
49cf177a37927a0c611218f453ac5065c63bc888c1d13934a1a4f81b6045c3e6
|
File details
Details for the file simd_f128-1.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
416cee3abb6d06585d5547c580949a1565d8b5ef9e7c18b4ca1954c0c0cbb716
|
|
| MD5 |
f14c8e5c0ea6dfd5ea6d635fdd0c4900
|
|
| BLAKE2b-256 |
e684434516e3dc75f0660b68290d3c7e8f704d5208126030bb21b3ffbf1e201e
|
File details
Details for the file simd_f128-1.2.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e21ba32e6ba411cb0cc557ce6f7528fa34487b9b2085fc49f5a50243b53b7ef
|
|
| MD5 |
3663ecaf31d5920cc5b7d9dff6c7aa77
|
|
| BLAKE2b-256 |
a70aae54e7a59c191bf61e2777d42eede0924ff9a6887d01b97544cbbae062a9
|
File details
Details for the file simd_f128-1.2.4-cp39-cp39-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp39-cp39-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.9, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7867d7a71d972a48d608eeacdca50b174c1d00882c2b5647029fec1c59da79b2
|
|
| MD5 |
b82fd76826fc6e4465cec81c9692cb38
|
|
| BLAKE2b-256 |
6968b39ba79d971ee468e7953d6d786de30e935d889bbba0d0ff6eafa9fa95a6
|
File details
Details for the file simd_f128-1.2.4-cp39-cp39-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp39-cp39-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.9, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b88c6ed16bd85f6985e266154b02802cc8f094f75a1ab6e43594749a49dc6755
|
|
| MD5 |
f5a2cb854731a38acdc75aa0101bf2a8
|
|
| BLAKE2b-256 |
0bb76593fd148ef31200dca39f1505759f51589064f1664bbb9ddd951013ced5
|
File details
Details for the file simd_f128-1.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63ef97b26697336931b6fff6342bbaea6c252698220ba3722e1290dfd09add3e
|
|
| MD5 |
fcaf9bd113286d09f2ffad5c75bbdbe1
|
|
| BLAKE2b-256 |
e7d6d4e9f82a5b5bbca0f7bd4e066ad670bcf87c9d7bd9ca05e4f98bb9dbf566
|
File details
Details for the file simd_f128-1.2.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
108e375aaf508ce816808583a0f1ae82f250f20fff33a3afeb5e28389dec9034
|
|
| MD5 |
9b7de67c17443a7b818a990046a325d4
|
|
| BLAKE2b-256 |
cc95936bc1602d53313da5e86e36a2fd38fbd08d358b2655e4303323309baf7b
|
File details
Details for the file simd_f128-1.2.4-cp38-cp38-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp38-cp38-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.8, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b909f6de20c518f2e71900ac62e962b5d3cb59095f19ab4818aa9fdaa398812
|
|
| MD5 |
8f425f7e770b351cdfb65d34d2fc7ca3
|
|
| BLAKE2b-256 |
bc768d4e1844990818ab67e2a4b5e59876d41a5128f0a9a822b77a88cdc888fd
|
File details
Details for the file simd_f128-1.2.4-cp38-cp38-musllinux_1_2_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp38-cp38-musllinux_1_2_i686.whl
- Upload date:
- Size: 2.8 MB
- Tags: CPython 3.8, musllinux: musl 1.2+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b24054e44e7b13fc08b73dd9bf4a8e6237471db6a8f55e9ab1b12c7cc9d37d7
|
|
| MD5 |
61f872c917ed275692afcfa41a6a69b8
|
|
| BLAKE2b-256 |
6f2130d2e7a91043336283f12d3b55b7e5d739c2f3f2ef30a9b0b593ef9e200a
|
File details
Details for the file simd_f128-1.2.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.8, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec44ed1fc2c9fcc537f272def57e626a2403729a7e101663a948affd757beb12
|
|
| MD5 |
a46a74da331e95cd7ea4a4aa79adc3e2
|
|
| BLAKE2b-256 |
a4b81a24196598c409abf2ea3a80c2a125253b1b93c29955b20c1982918bf9bf
|
File details
Details for the file simd_f128-1.2.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl.
File metadata
- Download URL: simd_f128-1.2.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.8, manylinux: glibc 2.17+ i686
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c531e9a7ac9c50971d94142b137bdd015409547b5c9fc429c48ab80613f2a07a
|
|
| MD5 |
e3e69130c53ed305fbb531c6303297fb
|
|
| BLAKE2b-256 |
68ad1efd1b2a38914470c5d549d9d7ff09e0ff795d8a1da7e82ba8073cbfb930
|