sangi mascotsangi

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 name derives from 算木 (sangi), the wooden calculation rods used in Japanese wasan mathematics from the 8th to 19th century. Mathematicians including Seki Takakazu (1642–1708) employed them in works such as Hatsubi Sanpou (1674) — Japan's indigenous mathematical computing instrument.

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.04.28.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-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