sangisangi

C++23 Comprehensive Math Library

C++23 / LGPL v3 / Zero External Dependencies
Arbitrary Precision Special Functions Linear Algebra FFT Lie Groups

sangi is a C++23 math library that provides arbitrary-precision arithmetic (Int, Float, Rational), complex numbers, polynomials, matrices, special functions, FFT, and Lie groups within a single unified framework.

The library is named after 算木 (sangi), the wooden calculation rods used in Japanese wasan mathematics; the sangi digit seven, , happens to mirror the shape of the letter π.

Digit 0 1 2 3 4 5 6 7 8 9
Sangi

Digits 1–5 stack vertical rods; 6–9 add a horizontal rod — the same structure later inherited by the Japanese soroban. Zero was represented by an empty cell.

Arbitrary Precision

Three core types: Int (integer), Float (floating-point), and Rational. High-speed mpn operations via BMI2/ADX instructions, with a 7-tier multiplication pipeline (Basecase → Karatsuba → Toom-3 → Toom-4 → Toom-6 → Toom-8 → NTT).

NaN / Infinity Safe

NaN and Infinity propagate safely across Int, Float, and Rational. Division by zero never crashes.

C++23 Concepts

Defines 50+ algebraic concepts such as Ring, Field, and VectorSpace. Write type-safe generic algorithms with compile-time guarantees.

80+ Special Functions

Bessel, Airy, Gamma, Zeta, elliptic integrals, hypergeometric functions, and more. Available for double, Complex<double>, and Float (arbitrary precision).

Numerical Algorithms

Linear algebra (LU/QR/SVD), root-finding, interpolation, and FFT. Combine freely with arbitrary-precision types, e.g. Matrix<Float>.

Lie Groups / Algebras

SO(2), SE(2), SO(3), SE(3) with exp/log, Jacobians, and adjoint representations. Left-perturbation model (GTSAM convention).

Algorithm Details

In-depth explanations of the algorithms used internally. Covers thresholds, computational complexity, and design rationale.

Linear Algebra

Root Finding

Optimization

Polynomials

Spectral Transforms

Multi-precision Arithmetic

Integer

Rational

Complex

Floating Point

Examples

Int — Arbitrary-Precision Integer

#include <math/core/mp/Int.hpp>
#include <iostream>
using namespace sangi;

int main() {
    Int a("123456789012345678901234567890");
    Int b("987654321098765432109876543210");

    std::cout << "a + b = " << a + b << std::endl;
    std::cout << "a * b = " << a * b << std::endl;
    std::cout << "gcd   = " << gcd(a, b) << std::endl;

    // Primality test (Miller-Rabin)
    Int p("170141183460469231731687303715884105727");  // 2^127 - 1
    std::cout << p << " is prime: " << std::boolalpha
              << isProbablePrime(p) << std::endl;

    // NaN/Infinity safe propagation
    Int zero;
    Int nan = Int(1) / zero;
    std::cout << "1/0 = " << nan << std::endl;  // NaN
}

Float — Arbitrary-Precision Floating-Point

#include <math/core/mp/Float.hpp>
#include <iostream>
using namespace sangi;

int main() {
    int prec = 50;  // 50-digit precision
    Float::setDefaultPrecision(prec);

    // Mathematical constants (thread-local cached; instant on subsequent calls)
    Float pi = Float::pi(prec);    // π to 50 digits (Chudnovsky)

    // Transcendental functions
    Float y = exp(pi, prec);       // e^π
    Float z = log(y, prec);        // log(e^π) = π

    std::cout << "exp(pi) = " << y.toDecimalString(prec) << std::endl;
    std::cout << "log(exp(pi)) = " << z.toDecimalString(prec) << std::endl;

    // Trigonometric functions
    Float s = sin(pi / Float(6, prec), prec);  // sin(π/6) = 0.5
    std::cout << "sin(pi/6) = " << s.toDecimalString(20) << std::endl;
}

Rational — Arbitrary-Precision Rational Number

#include <math/core/mp/Rational.hpp>
#include <iostream>
using namespace sangi;

int main() {
    Rational a(1, 3);   // 1/3
    Rational b(1, 6);   // 1/6

    Rational sum = a + b;
    std::cout << "1/3 + 1/6 = " << sum << std::endl;  // 1/2 (auto-reduced)

    Rational product = a * b;
    std::cout << "1/3 * 1/6 = " << product << std::endl;  // 1/18

    // Combine with arbitrary-precision integers
    Rational big(Int("1000000000000000000"), Int("3"));
    std::cout << big << std::endl;
}

Complex — Complex Numbers

#include <math/core/Complex.hpp>
#include <iostream>
using namespace sangi;
using namespace sangi::literals;

int main() {
    Complex<double> z(3.0, 4.0);
    std::cout << "z     = " << z << std::endl;       // (3, 4)
    std::cout << "|z|   = " << abs(z) << std::endl;   // 5
    std::cout << "arg   = " << arg(z) << std::endl;   // 0.9273
    std::cout << "conj  = " << conj(z) << std::endl;  // (3, -4)

    // Euler's formula: e^(i*pi) = -1
    auto euler = exp(Complex<double>(0, std::numbers::pi));
    std::cout << "e^(i*pi) = " << euler << std::endl;  // (-1, 0)

    // User-defined literal
    auto w = 2.0 + 3.0_i;
    std::cout << "w*w = " << w * w << std::endl;      // (-5, 12)
}

Vector — Numeric Vector

#include <math/core/vector.hpp>
#include <iostream>
using namespace sangi;

int main() {
    Vector<double> a{1.0, 2.0, 3.0};
    Vector<double> b{4.0, 5.0, 6.0};

    // Expression templates: no temporaries until assignment
    Vector<double> c = 2.0 * a + b;
    std::cout << "dot(a, b) = " << dot(a, b) << std::endl;  // 32
    std::cout << "norm(a)   = " << norm(a) << std::endl;     // 3.74166

    // 3D cross product (StaticVector)
    StaticVector<double, 3> i{1, 0, 0}, j{0, 1, 0};
    auto k = cross(i, j);  // [0, 0, 1]
}

Matrix — Dense Matrix

#include <math/core/matrix.hpp>
#include <math/core/mp/Rational.hpp>
#include <math/linalg/decomposition.hpp>
#include <iostream>
using namespace sangi;
using namespace sangi::algorithms;

int main() {
    // Matrix operations
    Matrix<double> A({{2, 1, -1}, {-3, -1, 2}, {-2, 1, 2}});
    Vector<double> b({8, -11, -3});
    auto x = lu_solve(A, b);        // x = {2, 3, -1}

    // operator^: transpose, inverse, power
    auto At   = A ^ 'T';     // transpose
    auto Ainv = A ^ (-1);    // inverse
    auto A3   = A ^ 3;       // A*A*A

    // Exact inverse with Rational
    Matrix<Rational> H(3, 3);
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            H(i, j) = Rational(1, i + j + 1);  // Hilbert matrix
    auto Hinv = lu_inverse(H);               // all integer entries (exact)
    auto I = H * Hinv;                       // exactly identity
}

LinAlg — Linear Algebra

#include <math/core/matrix.hpp>
#include <math/linalg/decomposition.hpp>
#include <math/linalg/eigenvalues.hpp>
#include <iostream>
using namespace sangi;
using namespace sangi::algorithms;

int main() {
    Matrix<double> A({{4, 1, 1}, {1, 3, 0}, {1, 0, 2}});

    // SVD decomposition
    auto [U, sigma, Vt] = svd_decomposition(A);

    // Symmetric eigenvalues
    auto [evals, evecs] = eigen_symmetric(A);

    // Gaussian elimination (pivot strategy selection)
    Vector<double> b({6, 4, 3});
    auto x = gaussian_elimination(A, b, PivotStrategy::Full);

    // Bareiss: integer determinant (division-free)
    Matrix<int> M({{1, 2, 3}, {4, 5, 6}, {7, 8, 10}});
    auto det = bareiss_determinant(M);  // -3
}

Polynomial — Polynomial

#include <math/core/polynomial.hpp>
#include <iostream>
using namespace sangi;

int main() {
    // x^2 - 1 = (x-1)(x+1)
    Polynomial<double> p({-1, 0, 1});  // -1 + 0x + x^2
    Polynomial<double> q({1, 1});      //  1 + x

    auto [quot, rem] = p.divmod(q);
    std::cout << "quot = " << quot << std::endl;  // -1 + x
    std::cout << "rem  = " << rem << std::endl;   // 0

    // Differentiation and integration
    auto dp = p.derivative();    // 2x
    auto ip = p.integral();      // -x + x^3/3

    // Root finding (all complex roots)
    auto roots = findAllRoots(p);  // {-1, 1}
}

FFT — Fast Fourier Transform

#include <math/fft/fft.hpp>
#include <math/fft/fft_utils.hpp>
#include <iostream>
using namespace sangi;

int main() {
    // Complex FFT (in-place)
    std::vector<Complex<double>> data = {1, 2, 3, 4};
    FFT<Complex<double>>::fft(data);   // forward
    FFT<Complex<double>>::ifft(data);  // inverse (recovers original)

    // Real FFT (N -> N/2+1 complex spectrum)
    std::vector<double> signal = {1, 0, -1, 0, 1, 0, -1, 0};
    auto spectrum = RealFFT<double>::fft(signal);
    auto amp = amplitude_spectrum<double>(spectrum);

    // Polynomial multiplication (convolution)
    std::vector<double> a = {1, 2, 3}, b = {4, 5};
    auto c = RealFFT<double>::convolve(a, b);  // {4, 13, 22, 15}
}

Roots — Root-Finding Algorithms

#include <math/roots/roots.hpp>
#include <math/core/polynomial.hpp>
#include <iostream>
using namespace sangi;

int main() {
    // Brent's method: root of f(x) = x^3 - 2  (= ∛2)
    auto f = [](double x) { return x * x * x - 2.0; };
    double root = brentRoot(f, 1.0, 2.0);
    std::cout << "cbrt(2) = " << root << std::endl;  // 1.25992...

    // Newton's method: root of f(x) = sin(x) - 0.5
    auto g  = [](double x) { return std::sin(x) - 0.5; };
    auto dg = [](double x) { return std::cos(x); };
    double r2 = newtonRoot(g, dg, 0.5);
    std::cout << "arcsin(0.5) = " << r2 << std::endl;  // π/6

    // All complex roots of a polynomial (Aberth-Ehrlich)
    Polynomial<double> p({6, -5, 1});  // x^2 - 5x + 6 = (x-2)(x-3)
    auto roots = findAllRoots(p);
    for (auto& z : roots)
        std::cout << z << std::endl;  // 2, 3
}

Optimization — Optimization

#include <math/optimization/optimization_nd.hpp>
#include <iostream>
using namespace sangi;

int main() {
    using V = Vector<double>;
    using M = Matrix<double>;

    // BFGS minimization of the Rosenbrock function
    auto f  = [](const V& x) { return (1-x[0])*(1-x[0]) + 100*(x[1]-x[0]*x[0])*(x[1]-x[0]*x[0]); };
    auto df = [](const V& x) {
        return V{-2*(1-x[0]) - 400*x[0]*(x[1]-x[0]*x[0]),
                 200*(x[1]-x[0]*x[0])};
    };
    auto result = bfgs_minimize<double, V, M>(f, df, V{-1, -1});
    std::cout << "min at " << result.point << std::endl;   // [1, 1]
    std::cout << "f(min) = " << result.value << std::endl;  // ~0
}

Build

Requirements

  • 64-bit OS (x86_64 / AArch64)
  • CMake 3.20 or later

Supported Compilers

CompilerMinimum VersionASM OptimizationStatus
MSVC (Visual Studio 2022)17.6+MASM (AVX2 + BMI2 + ADX)Tested
GCC14+GAS (AVX2 + BMI2 + ADX)Tested
Clang17+GAS (AVX2 + BMI2 + ADX)Tested

Supported Platforms and Performance

sangi requires a 64-bit (x86_64 / AArch64) environment. The internal arbitrary-precision arithmetic relies on 64-bit limbs and 128-bit wide multiplication (_umul128 / __uint128_t), so 32-bit platforms are not supported.

The following hardware features are automatically utilized when available:

Fast Path Enabled When Fallback
AVX2 NTT Butterfly AVX2-capable CPU (Intel Haswell+ / AMD Zen+) Scalar Montgomery NTT
MULX/ADCX/ADOX
mpn Primitives
BMI2 + ADX CPU, x64 (Windows: MASM / Linux: GAS) C++ generic implementation
NTT Parallelization NTT length ≥ 4096 (auto-detected) Single-threaded
  • Windows x64 + AVX2: All fast paths enabled. Best performance.
  • Linux x64 + AVX2: GAS assembly (BMI2 + ADX) + AVX2 NTT enabled. Performance on par with Windows.
  • ARM / Apple Silicon: AVX2 and ASM both disabled. All features work via __uint128_t-based C++ implementation. Estimated 2-3x slower than x64 ASM.

Download

Download the source code and build with CMake.

Download sangi-source-2026.05.23a.zip

You can also browse individual files from the source listing.

Antivirus False Positive Warning

Executables built from source may be falsely flagged as malware by antivirus software. sangi_int.lib contains modular exponentiation (Montgomery multiplication) and MASM assembly kernels, which are statically linked into your executable.

Quarantine happens silently and may be reported with a delay, making it appear as though the build failed and no exe was generated. If blocked, add your build directory to your antivirus exclusion list.

Other cryptographic and arbitrary-precision libraries such as GMP and OpenSSL are also affected by the same issue.

Building from Source and Running Examples

Windows (MSVC)

cd sangi
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release

After building, run the sample programs:

examples\Release\example-int.exe
examples\Release\example-float.exe
examples\Release\example-rational.exe
examples\Release\example-vector.exe
examples\Release\example-matrix.exe
examples\Release\example-linalg.exe
examples\Release\example-precision-showdown.exe
examples\Release\example-mp.exe
examples\Release\example-int-demo.exe
examples\Release\example-float-demo.exe
examples\Release\example-rational-demo.exe
examples\Release\example-vector-demo.exe
examples\Release\example-matrix-demo.exe
examples\Release\example-polynomial.exe
examples\Release\example-polynomial-factorization.exe
examples\Release\example-complex.exe
examples\Release\example-roots.exe
examples\Release\example-optimization.exe
examples\Release\example-fft.exe

Linux (GCC / Clang)

cd sangi
mkdir build && cd build
cmake .. -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_BUILD_TYPE=Release    # GCC
# cmake .. -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_BUILD_TYPE=Release  # Clang
cmake --build . -j$(nproc)

After building, run the sample programs:

./examples/example-int
./examples/example-float
./examples/example-rational
./examples/example-vector
./examples/example-matrix
./examples/example-linalg
./examples/example-precision-showdown
./examples/example-mp
./examples/example-int-demo
./examples/example-float-demo
./examples/example-rational-demo
./examples/example-vector-demo
./examples/example-matrix-demo
./examples/example-polynomial
./examples/example-polynomial-factorization
./examples/example-complex
./examples/example-roots
./examples/example-optimization
./examples/example-fft

Using sangi in Your Own Code

Once the examples work, try sangi in your own program. Link the libraries (.lib) generated by the sangi build:

// myapp.cpp
#include <math/core/mp/Int.hpp>
#include <iostream>
using namespace sangi;

int main() {
    Int a = Int::factorial(100);
    std::cout << "100! = " << a << std::endl;
}

Windows (MSVC):

cl /std:c++23 /EHsc /utf-8 /I C:\path\to\sangi\include myapp.cpp ^
    C:\path\to\sangi\build\lib\Release\sangi_int.lib ^
    C:\path\to\sangi\build\lib\Release\sangi_fft.lib
myapp.exe

Linux (GCC / Clang):

g++-14 -std=c++23 -O2 -I sangi/include myapp.cpp \
    sangi/build/lib/libsangi_int.a sangi/build/lib/libsangi_fft.a -lpthread -o myapp
./myapp

CMake:

target_include_directories(myapp PRIVATE path/to/sangi/include)
target_link_libraries(myapp PRIVATE
    path/to/sangi/build/lib/sangi_int    # or libsangi_int.a on Linux
    path/to/sangi/build/lib/sangi_fft    # required by Int multiplication
    path/to/sangi/build/lib/sangi_float  # if using Float
)
License: GNU Lesser General Public License v3.0 (LGPL-3.0). Modifications to sangi itself must be released under the LGPL, but applications that link against sangi may be proprietary.

Release History

2026-05-23Tensor released
2026-04-28Complex · Optimization released
2026-04-17Polynomial · Roots · FFT released
2026-04-10Concepts released
2026-04-03Matrix · LinAlg released
2026-03-27Vector released
2026-03-20Rational released
2026-03-13Float released
2026-03-02Int released