Benchmarks
This section reports the runtime overhead of the Boost.SafeNumbers types relative to the equivalent built-in types, and shows how to run the benchmarks yourself.
Each table compares three contenders at a fixed width:
-
the built-in C++ type, which is the baseline (
std::uint32_t,int128_t,double, and so on), -
Boost.SafeNumbers (
boost::sn::u32,boost::sn::i128,boost::sn::f64, and so on), and -
Boost.SafeNumerics (
safe<uint32_t>and similar) for the integer benchmarks.
Each cell reports the time per element in nanoseconds (ns/op), taken as the median across repetitions.
The Ratio column is how many times longer the wrapper takes than the built-in type of the same width: 1.00 means parity with the built-in type, and a larger value means the wrapper is slower.
Because the baseline differs by width, every table states the type it is measured against.
| Boost.SafeNumerics has no floating-point type and no 128-bit type, so the floating-point and 128-bit tables list only the built-in type and Boost.SafeNumbers. See Comparisons to Other Libraries and Languages for the details of that limitation. |
How to run the Benchmarks
The benchmarks live in test/benchmarks/ and are built with Google Benchmark.
They are not part of the default build: configure with -DBOOST_SAFE_NUMBERS_BUILD_BENCHMARKS=ON, which pulls Google Benchmark in with CMake FetchContent so no system install is required.
From a Boost tree that has the dependencies in place:
cmake -S . -B __build__ -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF \
-DBOOST_INCLUDE_LIBRARIES="safe_numbers;safe_numerics;random" \
-DBOOST_SAFE_NUMBERS_BUILD_BENCHMARKS=ON
cmake --build __build__ --config Release \
--target benchmark_unsigned_operations benchmark_signed_operations benchmark_float_operations
./__build__/libs/safe_numbers/test/benchmarks/benchmark_unsigned_operations --benchmark_repetitions=5
The benchmarks.yml GitHub Actions workflow runs the same build across a spread of native runners, emits each suite’s JSON, and renders the per-platform sections below with test/benchmarks/render_results.py.
Methodology
Each benchmark fills a vector of 1,000,000 random values once, outside the timed region, and then for every operation evaluates op(vec[i], vec[i + 1]) across the whole vector.
Each element’s result is passed through benchmark::DoNotOptimize, so the work cannot be elided, while the code is compiled at -O2 with inlining intact.
That distinction matters: compiling the loop without optimization would turn the wrapper’s inline operators into real function calls and grossly overstate their cost, so the benchmarks deliberately measure optimized code.
Google Benchmark picks the iteration count automatically and repeats the timing; the reported figure is the median time per element.
The integer benchmarks draw values uniformly from [1, width_in_bits - 1] and sort them in descending order.
Keeping the operands small and ordered means addition, subtraction, multiplication, division, and modulo all stay on the non-overflow, non-throwing path, so the measurement reflects the cost of the safety checks rather than the cost of throwing.
The floating-point benchmarks draw values uniformly from [1, 100] and measure addition, subtraction, multiplication, and division.
| The numbers come from shared CI runners and reflect a single run each, so treat small differences as noise. The repetition count and median reporting keep the central figure stable, but they cannot remove the variance inherent to a shared virtual machine. |
Device Benchmarks (CUDA and SYCL)
All of the safe types run inside CUDA and SYCL kernels (see CUDA Support and SYCL Support), and two dedicated benchmarks measure what the safety checks cost on the device itself:
-
test/benchmarks/benchmark_cuda_operations.cu, timed with CUDA events -
test/benchmarks/benchmark_sycl_operations.cpp, timed with SYCL event profiling
Each compares every safe type against its own basis type running the identical kernel (boost::sn::u32 against std::uint32_t, boost::sn::u128 against the emulated 128-bit basis type, and so on), so the ratio isolates the cost of the safety checks.
As in the host benchmarks, the inputs are chosen so that no check ever fires: the timed regions never enter the error reporting path, and a device_error_context covering the whole run aborts the benchmark if a check does fire.
Device Methodology
Two kernel shapes are measured for every type:
- Streaming
-
out[i] = a[i] op b[i], one checked operation per element over 4,194,304 elements. This is the shape real element-wise kernels have. On a discrete GPU it is bound by memory bandwidth, so it shows the overhead a typical kernel actually experiences. Integer operands are drawn from[1, width_in_bits - 1]witha >= b, and floating point operands from[1, 100], mirroring the host benchmarks. - Compute-bound chain
-
65,536 threads each evolve one value through a serial dependency chain held in registers (256 cycles of eight to nine checked operations), so the arithmetic cannot hide behind memory traffic and the worst case per-operation cost becomes visible.
The integer chain is a fixed mixed sequence (two modulo, two addition, two division, one subtraction, and one multiplication per cycle) rather than a single repeated operation. That is deliberate: wrapping integer arithmetic is associative, so the optimizer can legally collapse a run of additions or multiplications by loop-invariant operands for the builtin baseline, and the comparison would then measure an optimizer artifact instead of the checks. Division and modulo cannot be reassociated, and interleaving them forces every step to execute for both contenders. The floating point chains are per operation (eight operations plus one restore step of the inverse kind), because IEEE arithmetic is not associative and cannot be folded.
Every family also measures the non-throwing forms against the same raw baseline: a sat_add streaming row (saturating_add), mixed (sat) and mixed (ovf) integer chains built from the saturating_* and overflowing_* functions, and (ovf) float chains built from the deferred float family with the flags accumulated and folded into the result.
These rows show what checked arithmetic costs when the error report is deferred to a boundary instead of raised per operation.
Every timed region is verified afterwards: the safe results must match the builtin results bit for bit across all elements, a slice is recomputed on the host, and the process exit code reflects any mismatch.
Both benchmarks accept optional positional arguments [stream_elements] [chain_cycles] [launches] [chain_threads] for scaling the run to slower or faster devices.
How to Run the Device Benchmarks
CUDA (requires the CUDA toolkit):
cmake -S . -B __build__ -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF \
-DBOOST_INCLUDE_LIBRARIES="safe_numbers" \
-DBOOST_SAFE_NUMBERS_BUILD_BENCHMARKS=ON \
-DBOOST_SAFE_NUMBERS_ENABLE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=native
cmake --build __build__ --target benchmark_cuda_operations
./__build__/stage/bin/benchmark_cuda_operations
SYCL (requires oneAPI):
cmake -S . -B __build__ -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF \
-DCMAKE_CXX_COMPILER=icpx \
-DBOOST_INCLUDE_LIBRARIES="safe_numbers" \
-DBOOST_SAFE_NUMBERS_BUILD_BENCHMARKS=ON \
-DBOOST_SAFE_NUMBERS_ENABLE_SYCL=ON
cmake --build __build__ --target benchmark_sycl_operations
./__build__/stage/bin/benchmark_sycl_operations
icpx compiles with -ffp-model=fast by default, which grants the optimizer floating point associativity; the builtin baseline chains then fold algebraically and the float comparison becomes meaningless. The build therefore pins -ffp-model=precise for the SYCL benchmark, so both contenders run IEEE arithmetic exactly as they do under nvcc. The build also splits the device code per kernel (-fsycl-device-code-split=per_kernel) because at -O3 the monolithic device image of a few hundred kernels fails to JIT on the OpenCL CPU backend.
|
CUDA Results: NVIDIA RTX 3060
Run on an NVIDIA GeForce RTX 3060 (sm_86, 28 SMs) with CUDA 13.1 on Ubuntu 24.04, compiled at -O2 with --expt-relaxed-constexpr, using the default sizes.
| Type | Addition | Subtraction | Multiplication | Division | Modulo | Saturating addition |
|---|---|---|---|---|---|---|
|
1.05 |
1.04 |
1.05 |
1.03 |
1.02 |
1.02 |
|
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
0.99 |
|
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.00 |
6.77 |
1.00 |
1.00 |
1.00 |
|
1.23 |
1.22 |
1.22 |
1.16 |
1.15 |
1.04 |
|
1.05 |
1.05 |
1.04 |
1.04 |
1.03 |
1.00 |
|
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.00 |
6.79 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.00 |
1.00 |
1.00 |
n/a |
n/a |
|
1.00 |
1.00 |
1.00 |
1.44 |
n/a |
n/a |
In the streaming regime the checks are essentially free: the kernels are limited by memory bandwidth and the check instructions execute in the shadow of the loads.
The only rows above parity are the 8-bit types (up to 1.23x, since a byte of traffic buys less time to hide the check), f64 division (1.44x), and 128-bit multiplication (about 6.8x).
The multiplication overflow check on the 128-bit types is the one genuinely expensive check in the library, since it must be computed from 64-bit limbs.
| Type | Basis type (ns/op) | Throwing (ns/op) | Ratio | Saturating (ns/op) | Ratio | Overflowing (ns/op) | Ratio |
|---|---|---|---|---|---|---|---|
|
0.0030 |
0.0039 |
1.30 |
0.0037 |
1.24 |
0.0036 |
1.21 |
|
0.0030 |
0.0039 |
1.30 |
0.0037 |
1.23 |
0.0037 |
1.23 |
|
0.0012 |
0.0034 |
2.82 |
0.0030 |
2.55 |
0.0030 |
2.50 |
|
0.0031 |
0.0045 |
1.46 |
0.0044 |
1.44 |
0.0043 |
1.38 |
|
0.0094 |
0.0964 |
10.30 |
0.0884 |
9.43 |
0.0925 |
10.28 |
|
0.0020 |
0.0054 |
2.68 |
0.0056 |
2.78 |
0.0052 |
2.61 |
|
0.0020 |
0.0058 |
2.93 |
0.0058 |
2.96 |
0.0055 |
2.80 |
|
0.0018 |
0.0051 |
2.85 |
0.0052 |
2.92 |
0.0051 |
2.83 |
|
0.0031 |
0.0068 |
2.22 |
0.0071 |
2.31 |
0.0067 |
2.19 |
|
0.0121 |
0.0940 |
7.78 |
0.0921 |
7.62 |
0.0919 |
7.92 |
| Type | Operation | Basis type (ns/op) | Throwing (ns/op) | Ratio | Overflowing (ns/op) | Ratio |
|---|---|---|---|---|---|---|
|
Addition |
0.0002 |
0.0037 |
18.31 |
0.0011 |
5.39 |
|
Subtraction |
0.0002 |
0.0037 |
17.66 |
0.0011 |
5.37 |
|
Multiplication |
0.0004 |
0.0039 |
8.71 |
0.0012 |
2.69 |
|
Division |
0.0026 |
0.0057 |
2.22 |
0.0027 |
1.05 |
|
Addition |
0.0124 |
0.0495 |
4.00 |
0.0501 |
4.21 |
|
Subtraction |
0.0124 |
0.0495 |
4.01 |
0.0501 |
4.21 |
|
Multiplication |
0.0209 |
0.0579 |
2.77 |
0.0593 |
2.94 |
|
Division |
0.0779 |
0.1157 |
1.49 |
0.1196 |
1.55 |
With the arithmetic pinned in registers the checked integer types cost 1.3x to 2.9x through 64 bits, and the 128-bit chains are dominated by the multiplication check (7.8x to 10.3x).
For the floating point chains the baseline operation is a single hardware instruction, so the fixed cost of the checks multiplies it: up to 18.3x for f32, and 1.5x to 4.0x for f64, whose baseline instruction is already slow on a consumer GPU.
On a GPU the non-throwing integer forms buy little, because the throwing operators already compile to a well predicted branch; the deferred float family is the exception, cutting the f32 chains from 18.3x to 5.4x and f32 division to parity by dropping the per-operation classification.
Real kernels sit between the two regimes, and usually much closer to the streaming one.
SYCL Results: Intel OpenCL CPU Device
Run on the OpenCL CPU device of an Intel Core i9-11900K (8 cores) with oneAPI icpx 2026.0 at -O3, -ffp-model=precise, and per kernel device code split, using the default sizes.
A CPU device executes a kernel by vectorizing it across work items, and that shapes these results: a branch-free kernel body runs 8 or 16 lanes wide, and the branches of the safety checks inhibit exactly that transformation.
| Type | Addition | Subtraction | Multiplication | Division | Modulo | Saturating addition |
|---|---|---|---|---|---|---|
|
5.47 |
6.02 |
11.60 |
1.01 |
1.01 |
0.97 |
|
1.03 |
1.06 |
1.87 |
1.15 |
1.25 |
1.02 |
|
1.03 |
1.04 |
1.04 |
1.02 |
1.00 |
1.00 |
|
1.03 |
1.03 |
1.04 |
1.00 |
1.00 |
1.00 |
|
1.00 |
1.01 |
1.05 |
1.01 |
0.99 |
0.99 |
|
9.69 |
10.84 |
11.32 |
1.14 |
1.14 |
1.52 |
|
1.50 |
1.50 |
1.44 |
1.59 |
1.59 |
1.07 |
|
1.00 |
1.00 |
1.00 |
0.98 |
0.99 |
0.96 |
|
1.04 |
1.04 |
1.03 |
1.01 |
1.01 |
1.00 |
|
1.01 |
1.01 |
1.11 |
1.01 |
1.00 |
0.99 |
|
1.32 |
1.35 |
1.35 |
1.74 |
n/a |
n/a |
|
1.05 |
1.05 |
1.05 |
1.12 |
n/a |
n/a |
For 32 bits and up the streaming results match the CUDA picture: the arrays no longer fit in cache, the kernels are bound by memory, and the checks cost 0 to 7 percent.
The 8-bit rows stand out (up to 11.6x) because four million 1-byte elements fit inside the processor’s cache: those kernels are compute bound, so they measure the vectorization gap rather than memory bandwidth.
The saturating addition column shows the escape hatch: saturating_add compiles to the native saturating vector instructions, so even the 8-bit rows return to parity.
| Type | Basis type (ns/op) | Throwing (ns/op) | Ratio | Saturating (ns/op) | Ratio | Overflowing (ns/op) | Ratio |
|---|---|---|---|---|---|---|---|
|
0.0803 |
0.1198 |
1.49 |
0.1185 |
1.51 |
0.1149 |
1.43 |
|
0.0833 |
0.1567 |
1.88 |
0.1224 |
1.46 |
0.1434 |
1.72 |
|
0.0220 |
0.0941 |
4.27 |
0.0742 |
3.34 |
0.0697 |
3.16 |
|
0.1259 |
0.1317 |
1.05 |
0.1248 |
0.99 |
0.1271 |
1.00 |
|
0.3259 |
0.5082 |
1.56 |
0.4989 |
1.55 |
0.5189 |
1.59 |
|
0.1307 |
0.2153 |
1.65 |
0.1344 |
1.06 |
0.1459 |
1.11 |
|
0.0233 |
0.2057 |
8.82 |
0.1346 |
5.76 |
0.1406 |
5.90 |
|
0.0215 |
0.2025 |
9.42 |
0.1332 |
6.05 |
0.1415 |
6.46 |
|
0.1270 |
0.1858 |
1.46 |
0.1473 |
1.16 |
0.1485 |
1.17 |
|
0.4167 |
0.6075 |
1.46 |
0.8602 |
2.06 |
0.9172 |
2.22 |
| Type | Operation | Basis type (ns/op) | Throwing (ns/op) | Ratio | Overflowing (ns/op) | Ratio |
|---|---|---|---|---|---|---|
|
Addition |
0.0035 |
0.6126 |
173.03 |
0.0060 |
1.68 |
|
Subtraction |
0.0035 |
0.6066 |
171.30 |
0.0072 |
2.11 |
|
Multiplication |
0.0049 |
0.6275 |
127.59 |
0.0071 |
1.43 |
|
Division |
0.0150 |
0.7521 |
50.01 |
0.0163 |
1.13 |
|
Addition |
0.0036 |
0.6457 |
179.70 |
0.0098 |
2.73 |
|
Subtraction |
0.0036 |
0.8446 |
234.65 |
0.0108 |
2.85 |
|
Multiplication |
0.0064 |
0.6579 |
102.24 |
0.0135 |
2.05 |
|
Division |
0.0450 |
0.7644 |
17.00 |
0.0475 |
1.05 |
In the chains the dominant cost on a CPU device is lost vectorization rather than the check instructions themselves.
Where the baseline cannot vectorize either (the 64-bit and 128-bit chains, and the 8-bit chains whose narrow division defeats the vectorizer), the throwing types cost 1.0x to 1.9x, in line with the host benchmarks.
Where the baseline vectorizes and the throwing chain does not (i16, i32, and every floating point chain), the gap is the SIMD width times the check cost, up to roughly 235x for the f64 chains.
The deferred family recovers that gap almost entirely for floats: the branch-free overflowing_* operations vectorize with the baseline, so the same chains land at 1.1x to 2.9x, two orders of magnitude better than the throwing operators, while still detecting every error at the boundary (see Overflowing Arithmetic and the deferred_errors accumulator in SYCL Support).
The integer saturating_* and overflowing_* chains improve i16/i32 from about 9x to about 6x; the remaining gap is the divide by zero check that division and modulo still raise eagerly, which keeps a reporting branch in the kernel body.
| The device numbers come from one machine and a single run each, so treat small differences as noise. On a discrete GPU a SYCL build should behave like the CUDA column; this machine only exposes the CPU device. |
Linux x64
Run on the GitHub Actions ubuntu-latest runner using GCC 14 in release mode (-O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
0.94 |
1.14 |
1.21 |
Subtraction |
0.94 |
1.14 |
1.22 |
Multiplication |
0.94 |
1.11 |
1.18 |
Division |
0.94 |
1.22 |
1.29 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
0.94 |
1.12 |
1.19 |
Subtraction |
0.94 |
1.13 |
1.20 |
Multiplication |
0.94 |
1.11 |
1.18 |
Division |
1.41 |
1.42 |
1.00 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.54 |
0.62 |
1.16 |
0.67 |
1.25 |
Subtraction |
0.53 |
0.62 |
1.18 |
0.67 |
1.26 |
Multiplication |
0.62 |
0.62 |
1.00 |
0.69 |
1.10 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.50 |
0.62 |
1.25 |
0.69 |
1.37 |
Subtraction |
0.50 |
0.63 |
1.25 |
0.68 |
1.37 |
Multiplication |
0.76 |
0.72 |
0.94 |
0.72 |
0.94 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.50 |
0.63 |
1.24 |
0.64 |
1.26 |
Subtraction |
0.50 |
0.63 |
1.25 |
0.68 |
1.35 |
Multiplication |
0.59 |
0.64 |
1.08 |
0.93 |
1.58 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.63 |
1.23 |
0.70 |
1.38 |
Subtraction |
0.51 |
0.63 |
1.24 |
0.67 |
1.32 |
Multiplication |
0.59 |
0.69 |
1.16 |
2.81 |
4.72 |
Division |
2.18 |
2.18 |
1.00 |
2.18 |
1.00 |
Modulo |
2.19 |
2.19 |
1.00 |
2.18 |
1.00 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.20 |
2.11 |
0.96 |
Subtraction |
1.88 |
2.05 |
1.10 |
Multiplication |
2.90 |
3.13 |
1.08 |
Division |
5.63 |
6.26 |
1.11 |
Modulo |
6.56 |
7.19 |
1.10 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.54 |
0.65 |
1.21 |
0.73 |
1.36 |
Subtraction |
0.63 |
0.62 |
1.00 |
0.62 |
1.00 |
Multiplication |
0.43 |
0.72 |
1.66 |
0.68 |
1.58 |
Division |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
Modulo |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.50 |
0.62 |
1.25 |
0.67 |
1.33 |
Subtraction |
0.50 |
0.62 |
1.25 |
0.63 |
1.25 |
Multiplication |
0.59 |
0.94 |
1.59 |
0.94 |
1.59 |
Division |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
Modulo |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.62 |
1.24 |
0.63 |
1.24 |
Subtraction |
0.50 |
0.63 |
1.24 |
0.63 |
1.24 |
Multiplication |
0.59 |
0.94 |
1.58 |
0.64 |
1.07 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.63 |
1.23 |
0.63 |
1.23 |
Subtraction |
0.51 |
0.63 |
1.23 |
0.63 |
1.23 |
Multiplication |
0.60 |
0.94 |
1.58 |
0.82 |
1.37 |
Division |
2.18 |
2.18 |
1.00 |
2.18 |
1.00 |
Modulo |
2.18 |
2.18 |
1.00 |
2.18 |
1.00 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
1.93 |
2.70 |
1.40 |
Subtraction |
1.89 |
3.42 |
1.81 |
Multiplication |
2.83 |
2.32 |
0.82 |
Division |
4.08 |
3.76 |
0.92 |
Modulo |
4.15 |
4.09 |
0.99 |
Linux x86 (32-bit)
Run on the GitHub Actions ubuntu-latest runner using GCC 14 targeting 32-bit x86 (-m32) in release mode (-O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.09 |
2.19 |
1.05 |
Subtraction |
2.08 |
2.19 |
1.06 |
Multiplication |
2.08 |
2.19 |
1.06 |
Division |
1.89 |
2.53 |
1.34 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
6.31 |
6.38 |
1.01 |
Subtraction |
6.31 |
6.38 |
1.01 |
Multiplication |
6.31 |
6.38 |
1.01 |
Division |
6.32 |
6.21 |
0.98 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.62 |
1.90 |
3.04 |
0.67 |
1.07 |
Subtraction |
0.52 |
1.90 |
3.62 |
0.67 |
1.27 |
Multiplication |
0.62 |
1.93 |
3.09 |
0.69 |
1.10 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.63 |
0.76 |
1.20 |
0.77 |
1.22 |
Subtraction |
0.63 |
1.90 |
3.02 |
0.67 |
1.06 |
Multiplication |
0.63 |
1.96 |
3.13 |
0.88 |
1.41 |
Division |
1.87 |
1.90 |
1.02 |
1.87 |
1.00 |
Modulo |
1.87 |
1.88 |
1.00 |
1.87 |
1.00 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.52 |
0.75 |
1.43 |
0.66 |
1.25 |
Subtraction |
0.64 |
0.91 |
1.42 |
0.65 |
1.02 |
Multiplication |
0.63 |
0.74 |
1.18 |
1.29 |
2.06 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.81 |
1.79 |
0.99 |
3.22 |
1.78 |
Subtraction |
1.81 |
2.72 |
1.51 |
3.23 |
1.79 |
Multiplication |
2.20 |
3.69 |
1.67 |
7.19 |
3.26 |
Division |
4.78 |
5.89 |
1.23 |
5.68 |
1.19 |
Modulo |
5.03 |
6.25 |
1.24 |
5.21 |
1.04 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
6.33 |
7.77 |
1.23 |
Subtraction |
6.92 |
7.58 |
1.10 |
Multiplication |
13.80 |
37.51 |
2.72 |
Division |
12.30 |
13.57 |
1.10 |
Modulo |
13.47 |
16.47 |
1.22 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.63 |
0.63 |
0.99 |
1.88 |
2.97 |
Subtraction |
0.53 |
0.63 |
1.19 |
0.63 |
1.19 |
Multiplication |
0.43 |
0.64 |
1.48 |
0.63 |
1.46 |
Division |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
Modulo |
1.25 |
1.25 |
1.00 |
1.87 |
1.50 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.63 |
0.64 |
1.01 |
1.89 |
2.99 |
Subtraction |
0.63 |
0.73 |
1.16 |
0.57 |
0.91 |
Multiplication |
0.44 |
1.89 |
4.32 |
1.99 |
4.56 |
Division |
1.97 |
1.93 |
0.98 |
1.87 |
0.95 |
Modulo |
1.89 |
1.92 |
1.01 |
1.87 |
0.99 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.52 |
0.63 |
1.20 |
0.58 |
1.11 |
Subtraction |
0.63 |
0.73 |
1.15 |
0.76 |
1.20 |
Multiplication |
0.63 |
0.94 |
1.50 |
0.77 |
1.23 |
Division |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
Modulo |
1.87 |
1.87 |
1.00 |
1.87 |
1.00 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.81 |
1.81 |
1.00 |
1.81 |
1.00 |
Subtraction |
1.81 |
2.20 |
1.22 |
1.93 |
1.07 |
Multiplication |
2.21 |
2.69 |
1.21 |
2.15 |
0.97 |
Division |
4.38 |
4.61 |
1.05 |
4.53 |
1.03 |
Modulo |
4.19 |
4.50 |
1.07 |
4.45 |
1.06 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
5.88 |
7.31 |
1.24 |
Subtraction |
6.55 |
7.75 |
1.18 |
Multiplication |
10.40 |
36.02 |
3.46 |
Division |
15.65 |
21.62 |
1.38 |
Modulo |
17.33 |
24.33 |
1.40 |
Linux ARM64
Run on the GitHub Actions ubuntu-24.04-arm runner using GCC 14 in release mode (-O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
0.71 |
1.03 |
1.45 |
Subtraction |
0.71 |
1.03 |
1.45 |
Multiplication |
0.79 |
1.18 |
1.49 |
Division |
0.73 |
1.37 |
1.88 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
0.71 |
1.04 |
1.46 |
Subtraction |
0.71 |
1.04 |
1.46 |
Multiplication |
0.79 |
1.18 |
1.49 |
Division |
1.48 |
1.75 |
1.19 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.61 |
0.83 |
1.35 |
0.65 |
1.06 |
Subtraction |
0.61 |
0.83 |
1.35 |
0.65 |
1.06 |
Multiplication |
0.61 |
0.80 |
1.31 |
0.65 |
1.06 |
Division |
1.65 |
1.69 |
1.03 |
1.68 |
1.02 |
Modulo |
1.94 |
1.94 |
1.00 |
1.94 |
1.00 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.61 |
0.84 |
1.39 |
0.83 |
1.36 |
Subtraction |
0.61 |
0.84 |
1.39 |
0.83 |
1.36 |
Multiplication |
0.61 |
0.86 |
1.40 |
0.83 |
1.35 |
Division |
1.69 |
1.72 |
1.02 |
1.82 |
1.07 |
Modulo |
1.99 |
1.99 |
1.00 |
1.99 |
1.00 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.58 |
1.13 |
0.70 |
1.39 |
Subtraction |
0.51 |
0.58 |
1.14 |
0.70 |
1.38 |
Multiplication |
0.49 |
0.70 |
1.44 |
0.69 |
1.41 |
Division |
1.74 |
1.72 |
0.99 |
1.73 |
0.99 |
Modulo |
2.02 |
2.02 |
1.00 |
2.02 |
1.00 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.57 |
1.13 |
0.70 |
1.39 |
Subtraction |
0.51 |
0.57 |
1.13 |
0.71 |
1.40 |
Multiplication |
0.49 |
0.85 |
1.71 |
5.24 |
10.60 |
Division |
1.76 |
1.74 |
0.99 |
1.74 |
0.99 |
Modulo |
2.04 |
2.04 |
1.00 |
2.04 |
1.00 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
1.83 |
1.90 |
1.04 |
Subtraction |
1.85 |
1.92 |
1.04 |
Multiplication |
1.99 |
1.93 |
0.97 |
Division |
5.08 |
5.30 |
1.04 |
Modulo |
5.04 |
5.18 |
1.03 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.90 |
0.90 |
0.99 |
0.93 |
1.03 |
Subtraction |
0.90 |
0.90 |
1.00 |
0.92 |
1.02 |
Multiplication |
0.92 |
0.91 |
0.99 |
0.93 |
1.01 |
Division |
1.65 |
1.65 |
1.00 |
1.64 |
0.99 |
Modulo |
1.94 |
1.94 |
1.00 |
1.94 |
1.00 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.89 |
0.89 |
1.00 |
0.91 |
1.02 |
Subtraction |
0.88 |
0.89 |
1.00 |
0.89 |
1.00 |
Multiplication |
0.90 |
0.88 |
0.99 |
0.95 |
1.06 |
Division |
1.69 |
1.70 |
1.00 |
1.71 |
1.01 |
Modulo |
1.99 |
1.99 |
1.00 |
1.99 |
1.00 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.58 |
1.14 |
0.58 |
1.13 |
Subtraction |
0.51 |
0.58 |
1.13 |
0.57 |
1.13 |
Multiplication |
0.49 |
0.61 |
1.26 |
0.65 |
1.34 |
Division |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Modulo |
2.02 |
2.02 |
1.00 |
2.02 |
1.00 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
0.51 |
0.58 |
1.14 |
0.58 |
1.13 |
Subtraction |
0.51 |
0.57 |
1.12 |
0.57 |
1.13 |
Multiplication |
0.49 |
0.73 |
1.48 |
0.79 |
1.61 |
Division |
1.76 |
1.76 |
1.00 |
1.76 |
1.00 |
Modulo |
2.04 |
2.04 |
1.00 |
2.04 |
1.00 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
1.85 |
1.91 |
1.03 |
Subtraction |
1.85 |
1.92 |
1.04 |
Multiplication |
2.01 |
1.90 |
0.95 |
Division |
4.67 |
4.70 |
1.01 |
Modulo |
4.90 |
4.93 |
1.01 |
macOS ARM64
Run on the GitHub Actions macos-latest runner (Apple Silicon) using Apple Clang in release mode (-O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.66 |
3.76 |
1.03 |
Subtraction |
3.66 |
3.46 |
0.95 |
Multiplication |
3.66 |
3.80 |
1.04 |
Division |
3.51 |
3.48 |
0.99 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.52 |
3.58 |
1.02 |
Subtraction |
3.71 |
3.74 |
1.01 |
Multiplication |
3.78 |
3.78 |
1.00 |
Division |
3.64 |
3.69 |
1.01 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.28 |
2.06 |
0.90 |
2.25 |
0.99 |
Subtraction |
2.28 |
2.08 |
0.92 |
2.12 |
0.93 |
Multiplication |
2.27 |
2.16 |
0.95 |
2.26 |
1.00 |
Division |
2.21 |
2.06 |
0.93 |
2.29 |
1.03 |
Modulo |
2.18 |
2.06 |
0.95 |
2.21 |
1.01 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.21 |
2.44 |
1.10 |
2.05 |
0.92 |
Subtraction |
2.15 |
2.27 |
1.06 |
2.11 |
0.98 |
Multiplication |
2.08 |
2.12 |
1.02 |
2.13 |
1.02 |
Division |
2.29 |
2.28 |
0.99 |
2.08 |
0.91 |
Modulo |
2.20 |
2.09 |
0.95 |
2.10 |
0.96 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.26 |
2.87 |
1.27 |
2.08 |
0.92 |
Subtraction |
2.10 |
2.70 |
1.29 |
2.11 |
1.01 |
Multiplication |
2.09 |
2.85 |
1.37 |
2.17 |
1.04 |
Division |
2.16 |
2.88 |
1.33 |
2.11 |
0.98 |
Modulo |
2.07 |
2.70 |
1.30 |
2.06 |
1.00 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.22 |
2.83 |
1.28 |
2.21 |
0.99 |
Subtraction |
2.23 |
2.81 |
1.26 |
2.21 |
0.99 |
Multiplication |
2.23 |
2.72 |
1.22 |
2.17 |
0.97 |
Division |
2.27 |
2.69 |
1.19 |
2.19 |
0.96 |
Modulo |
2.21 |
2.73 |
1.24 |
2.19 |
0.99 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.40 |
2.62 |
1.09 |
Subtraction |
2.53 |
2.38 |
0.94 |
Multiplication |
2.51 |
7.64 |
3.05 |
Division |
6.97 |
8.22 |
1.18 |
Modulo |
7.20 |
7.92 |
1.10 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.45 |
2.23 |
0.91 |
2.25 |
0.92 |
Subtraction |
2.35 |
2.23 |
0.95 |
2.32 |
0.99 |
Multiplication |
2.45 |
2.25 |
0.92 |
2.26 |
0.92 |
Division |
2.41 |
2.24 |
0.93 |
2.26 |
0.94 |
Modulo |
2.26 |
2.24 |
0.99 |
2.30 |
1.02 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.23 |
2.33 |
1.04 |
2.26 |
1.01 |
Subtraction |
2.41 |
2.27 |
0.94 |
2.21 |
0.91 |
Multiplication |
2.57 |
2.41 |
0.94 |
2.07 |
0.81 |
Division |
2.46 |
2.79 |
1.13 |
2.27 |
0.92 |
Modulo |
2.51 |
2.21 |
0.88 |
2.19 |
0.87 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.26 |
2.52 |
1.12 |
2.27 |
1.00 |
Subtraction |
2.32 |
2.44 |
1.05 |
2.13 |
0.92 |
Multiplication |
2.42 |
2.41 |
0.99 |
2.22 |
0.91 |
Division |
2.26 |
2.44 |
1.08 |
2.24 |
0.99 |
Modulo |
2.27 |
2.63 |
1.16 |
2.15 |
0.95 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.12 |
2.65 |
1.25 |
2.07 |
0.98 |
Subtraction |
2.30 |
2.52 |
1.09 |
2.07 |
0.90 |
Multiplication |
2.38 |
2.48 |
1.04 |
2.20 |
0.93 |
Division |
2.19 |
2.73 |
1.25 |
2.09 |
0.96 |
Modulo |
2.22 |
2.70 |
1.21 |
2.21 |
0.99 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.57 |
2.43 |
0.94 |
Subtraction |
2.67 |
2.61 |
0.98 |
Multiplication |
2.55 |
2.65 |
1.04 |
Division |
4.13 |
4.40 |
1.07 |
Modulo |
4.28 |
4.47 |
1.04 |
Windows x64
Run on the GitHub Actions windows-latest runner using MSVC in release mode (/O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.65 |
3.65 |
1.00 |
Subtraction |
3.65 |
3.91 |
1.07 |
Multiplication |
3.82 |
3.65 |
0.95 |
Division |
3.52 |
3.91 |
1.11 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.52 |
4.17 |
1.19 |
Subtraction |
3.82 |
3.91 |
1.02 |
Multiplication |
3.65 |
3.65 |
1.00 |
Division |
3.82 |
3.91 |
1.02 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.91 |
2.08 |
1.09 |
2.12 |
1.11 |
Subtraction |
1.93 |
2.10 |
1.09 |
2.08 |
1.08 |
Multiplication |
2.08 |
2.10 |
1.01 |
1.91 |
0.92 |
Division |
2.26 |
2.43 |
1.08 |
2.26 |
1.00 |
Modulo |
2.26 |
2.33 |
1.03 |
2.26 |
1.00 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.93 |
2.12 |
1.10 |
1.93 |
1.00 |
Subtraction |
1.91 |
2.33 |
1.22 |
2.10 |
1.10 |
Multiplication |
2.08 |
2.08 |
1.00 |
2.08 |
1.00 |
Division |
2.33 |
2.43 |
1.04 |
2.33 |
1.00 |
Modulo |
2.26 |
2.78 |
1.23 |
2.08 |
0.92 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.91 |
1.91 |
1.00 |
1.91 |
1.00 |
Subtraction |
1.93 |
1.93 |
1.00 |
2.26 |
1.17 |
Multiplication |
1.56 |
1.91 |
1.22 |
1.91 |
1.22 |
Division |
1.91 |
2.89 |
1.52 |
2.26 |
1.18 |
Modulo |
1.93 |
2.78 |
1.44 |
2.26 |
1.17 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.93 |
1.91 |
0.99 |
1.86 |
0.96 |
Subtraction |
1.93 |
1.91 |
0.99 |
2.26 |
1.17 |
Multiplication |
1.93 |
2.78 |
1.44 |
2.89 |
1.50 |
Division |
2.10 |
2.12 |
1.01 |
2.26 |
1.08 |
Modulo |
2.10 |
2.78 |
1.32 |
2.33 |
1.11 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
9.77 |
3.13 |
0.32 |
Subtraction |
9.62 |
3.13 |
0.33 |
Multiplication |
2.78 |
13.89 |
5.00 |
Division |
10.82 |
13.89 |
1.28 |
Modulo |
15.63 |
17.36 |
1.11 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.93 |
2.08 |
1.08 |
2.08 |
1.08 |
Subtraction |
1.93 |
2.08 |
1.08 |
1.91 |
0.99 |
Multiplication |
2.08 |
1.93 |
0.93 |
1.91 |
0.92 |
Division |
1.91 |
2.31 |
1.21 |
1.93 |
1.01 |
Modulo |
2.10 |
2.26 |
1.08 |
2.08 |
0.99 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.91 |
2.08 |
1.09 |
1.91 |
1.00 |
Subtraction |
1.91 |
2.12 |
1.11 |
1.91 |
1.00 |
Multiplication |
1.91 |
2.08 |
1.09 |
2.26 |
1.18 |
Division |
2.31 |
2.12 |
0.92 |
2.26 |
0.97 |
Modulo |
1.91 |
2.26 |
1.18 |
2.33 |
1.22 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.93 |
1.91 |
0.99 |
1.56 |
0.81 |
Subtraction |
1.91 |
1.93 |
1.01 |
1.56 |
0.82 |
Multiplication |
1.56 |
1.91 |
1.22 |
1.91 |
1.22 |
Division |
1.86 |
1.91 |
1.03 |
1.91 |
1.03 |
Modulo |
1.91 |
1.93 |
1.01 |
1.93 |
1.01 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.91 |
1.91 |
1.00 |
1.91 |
1.00 |
Subtraction |
1.91 |
1.56 |
0.82 |
1.91 |
1.00 |
Multiplication |
1.93 |
2.33 |
1.21 |
2.78 |
1.44 |
Division |
2.10 |
2.12 |
1.01 |
2.10 |
1.00 |
Modulo |
2.33 |
2.26 |
0.97 |
2.33 |
1.00 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.43 |
3.13 |
1.29 |
Subtraction |
2.60 |
3.13 |
1.20 |
Multiplication |
3.47 |
12.15 |
3.50 |
Division |
2.89 |
10.82 |
3.74 |
Modulo |
4.17 |
3.91 |
0.94 |
Windows x86 (32-bit)
Run on the GitHub Actions windows-latest runner using MSVC targeting 32-bit x86 in release mode (/O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.65 |
6.37 |
1.75 |
Subtraction |
3.65 |
6.37 |
1.75 |
Multiplication |
3.82 |
6.37 |
1.67 |
Division |
3.82 |
6.94 |
1.82 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
3.82 |
13.89 |
3.64 |
Subtraction |
3.91 |
13.89 |
3.56 |
Multiplication |
3.65 |
13.89 |
3.81 |
Division |
3.82 |
17.36 |
4.55 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.60 |
3.47 |
1.33 |
2.78 |
1.07 |
Subtraction |
2.43 |
3.13 |
1.29 |
2.78 |
1.14 |
Multiplication |
3.47 |
2.78 |
0.80 |
2.78 |
0.80 |
Division |
2.78 |
3.82 |
1.38 |
2.78 |
1.00 |
Modulo |
3.47 |
3.65 |
1.05 |
2.78 |
0.80 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.08 |
2.70 |
1.30 |
2.12 |
1.02 |
Subtraction |
1.87 |
9.77 |
5.23 |
2.12 |
1.14 |
Multiplication |
2.10 |
2.12 |
1.01 |
2.10 |
1.00 |
Division |
2.08 |
2.43 |
1.17 |
2.43 |
1.17 |
Modulo |
2.08 |
2.78 |
1.33 |
2.51 |
1.20 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.08 |
2.43 |
1.17 |
2.12 |
1.02 |
Subtraction |
1.91 |
2.43 |
1.27 |
2.43 |
1.27 |
Multiplication |
1.93 |
2.43 |
1.26 |
2.78 |
1.44 |
Division |
2.33 |
2.43 |
1.04 |
2.26 |
0.97 |
Modulo |
2.26 |
2.43 |
1.08 |
2.10 |
0.93 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.78 |
5.21 |
1.87 |
3.65 |
1.31 |
Subtraction |
2.78 |
5.08 |
1.83 |
3.65 |
1.31 |
Multiplication |
4.30 |
8.33 |
1.94 |
8.33 |
1.94 |
Division |
5.73 |
6.37 |
1.11 |
6.39 |
1.12 |
Modulo |
4.97 |
6.39 |
1.29 |
5.68 |
1.14 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
8.68 |
12.15 |
1.40 |
Subtraction |
8.79 |
12.15 |
1.38 |
Multiplication |
19.10 |
62.50 |
3.27 |
Division |
26.04 |
31.25 |
1.20 |
Modulo |
26.04 |
31.25 |
1.20 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.78 |
3.09 |
1.11 |
2.78 |
1.00 |
Subtraction |
2.70 |
3.13 |
1.16 |
2.78 |
1.03 |
Multiplication |
3.65 |
2.95 |
0.81 |
2.78 |
0.76 |
Division |
3.13 |
3.82 |
1.22 |
2.60 |
0.83 |
Modulo |
3.47 |
3.82 |
1.10 |
2.78 |
0.80 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.33 |
2.57 |
1.10 |
2.08 |
0.89 |
Subtraction |
2.10 |
2.26 |
1.08 |
2.08 |
0.99 |
Multiplication |
2.08 |
2.12 |
1.02 |
2.89 |
1.39 |
Division |
2.26 |
2.60 |
1.15 |
2.08 |
0.92 |
Modulo |
2.08 |
2.78 |
1.33 |
2.10 |
1.01 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.08 |
2.33 |
1.12 |
2.12 |
1.02 |
Subtraction |
2.08 |
2.33 |
1.12 |
2.08 |
1.00 |
Multiplication |
1.93 |
2.08 |
1.08 |
2.33 |
1.21 |
Division |
2.10 |
2.12 |
1.01 |
2.10 |
1.00 |
Modulo |
2.12 |
2.08 |
0.98 |
2.10 |
0.99 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
2.78 |
3.13 |
1.12 |
3.82 |
1.38 |
Subtraction |
2.78 |
3.13 |
1.12 |
3.13 |
1.12 |
Multiplication |
4.17 |
23.44 |
5.62 |
7.81 |
1.87 |
Division |
5.21 |
5.68 |
1.09 |
5.79 |
1.11 |
Modulo |
4.69 |
4.97 |
1.06 |
4.69 |
1.00 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
7.03 |
15.63 |
2.22 |
Subtraction |
7.81 |
17.36 |
2.22 |
Multiplication |
15.63 |
70.31 |
4.50 |
Division |
13.89 |
31.25 |
2.25 |
Modulo |
13.89 |
31.25 |
2.25 |
Windows ARM64
Run on the GitHub Actions windows-11-arm runner using MSVC in release mode (/O2, C++20).
Floating-Point
| Operation | float (ns/op) |
boost::sn::f32 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.10 |
2.78 |
1.32 |
Subtraction |
2.10 |
3.13 |
1.49 |
Multiplication |
2.12 |
2.78 |
1.31 |
Division |
2.12 |
3.52 |
1.66 |
| Operation | double (ns/op) |
boost::sn::f64 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.08 |
3.13 |
1.50 |
Subtraction |
2.10 |
3.13 |
1.49 |
Multiplication |
2.08 |
3.13 |
1.50 |
Division |
2.08 |
3.65 |
1.75 |
Signed Integers
| Operation | std::int8_t (ns/op) |
boost::sn::i8 (ns/op) |
Ratio | safe<int8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.74 |
1.00 |
1.91 |
1.10 |
Modulo |
1.91 |
1.93 |
1.01 |
1.91 |
1.00 |
| Operation | std::int16_t (ns/op) |
boost::sn::i16 (ns/op) |
Ratio | safe<int16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.91 |
1.10 |
2.08 |
1.20 |
Modulo |
1.93 |
1.93 |
1.00 |
2.08 |
1.08 |
| Operation | std::int32_t (ns/op) |
boost::sn::i32 (ns/op) |
Ratio | safe<int32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.91 |
1.10 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.91 |
1.10 |
1.93 |
1.11 |
Modulo |
2.12 |
1.91 |
0.90 |
2.08 |
0.98 |
| Operation | std::int64_t (ns/op) |
boost::sn::i64 (ns/op) |
Ratio | safe<int64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.91 |
1.74 |
0.91 |
1.74 |
0.91 |
Multiplication |
1.74 |
4.30 |
2.47 |
5.21 |
3.00 |
Division |
1.74 |
1.91 |
1.10 |
1.91 |
1.10 |
Modulo |
2.08 |
2.08 |
1.00 |
2.08 |
1.00 |
| Operation | int128_t (ns/op) |
boost::sn::i128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.78 |
3.13 |
1.12 |
Subtraction |
2.78 |
2.78 |
1.00 |
Multiplication |
4.17 |
22.57 |
5.42 |
Division |
7.10 |
7.81 |
1.10 |
Modulo |
7.81 |
8.33 |
1.07 |
Unsigned Integers
| Operation | std::uint8_t (ns/op) |
boost::sn::u8 (ns/op) |
Ratio | safe<uint8_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.74 |
1.00 |
1.91 |
1.10 |
Modulo |
1.91 |
1.91 |
1.00 |
1.93 |
1.01 |
| Operation | std::uint16_t (ns/op) |
boost::sn::u16 (ns/op) |
Ratio | safe<uint16_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.74 |
1.00 |
1.91 |
1.10 |
Modulo |
1.93 |
1.91 |
0.99 |
2.08 |
1.08 |
| Operation | std::uint32_t (ns/op) |
boost::sn::u32 (ns/op) |
Ratio | safe<uint32_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Division |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Modulo |
2.10 |
2.12 |
1.01 |
2.08 |
0.99 |
| Operation | std::uint64_t (ns/op) |
boost::sn::u64 (ns/op) |
Ratio | safe<uint64_t> (ns/op) |
Ratio |
|---|---|---|---|---|---|
Addition |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Subtraction |
1.74 |
1.74 |
1.00 |
1.74 |
1.00 |
Multiplication |
1.74 |
1.74 |
1.00 |
5.21 |
3.00 |
Division |
1.74 |
1.74 |
1.00 |
1.91 |
1.10 |
Modulo |
2.12 |
2.12 |
1.00 |
2.08 |
0.98 |
| Operation | uint128_t (ns/op) |
boost::sn::u128 (ns/op) |
Ratio |
|---|---|---|---|
Addition |
2.26 |
2.60 |
1.15 |
Subtraction |
2.26 |
2.43 |
1.08 |
Multiplication |
2.43 |
19.10 |
7.86 |
Division |
4.30 |
4.97 |
1.16 |
Modulo |
4.69 |
5.68 |
1.21 |