Bodu.Numerics 1.3.0

dotnet add package Bodu.Numerics --version 1.3.0
                    
NuGet\Install-Package Bodu.Numerics -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Bodu.Numerics" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Bodu.Numerics" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Bodu.Numerics" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Bodu.Numerics --version 1.3.0
                    
#r "nuget: Bodu.Numerics, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Bodu.Numerics@1.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Bodu.Numerics&version=1.3.0
                    
Install as a Cake Addin
#tool nuget:?package=Bodu.Numerics&version=1.3.0
                    
Install as a Cake Tool

Bodu.Numerics

API stability - Stable. The public API surface is committed: breaking changes are reserved for a major-version bump per SemVer, except a deliberate break that is recorded in the release notes and in the package's CompatibilitySuppressions.xml. See versioning and support.

Numeric value primitives for .NET. The public model is exact rational numbers plus an interval algebra:

  • Fraction<T> - an immutable, exact-rational value type generic over any IBinaryInteger<T> backing component.
  • Interval<T> - an immutable connected interval over any INumber<T> endpoint type, with independent open/closed (and unbounded) endpoints and set algebra.
  • DiscreteInterval<T> - a connected integer-domain interval over IBinaryInteger<T>, with successor/predecessor-aware emptiness and adjacency.
  • IntervalSet<T> - a normalized set of disconnected Interval<T> pieces, with N-ary union / intersection / difference / complement.
  • IntervalPair<T> / DiscreteIntervalPair<T> - allocation-conscious results of a binary difference / symmetric-difference (zero, one, or two disjoint pieces), each convertible to an IntervalSet<T>.
  • BigDecimal - an immutable arbitrary-precision decimal (a BigInteger unscaled value plus an int scale), for exact decimal values beyond System.Decimal's precision or exponent range.
  • Complex<T> - an immutable complex number over any IFloatingPointIeee754<T> component type (float, double, Half), the generic counterpart of the double-only System.Numerics.Complex.
  • RunningStatistics<T> / RunningQuantile<T> - single-pass, constant-space accumulators over a sample stream: Welford count/min/max/mean/variance with a parallel Combine merge, and a P² streaming quantile estimator.
  • MovingSum<T> / MovingMinMax<T> - rolling-window companions that report the sum/mean and min/max of the most recent N samples in amortized O(1).

Money, currency, and foreign-exchange types ship in the companion Bodu.Financial package. Keeping them separate means a consumer of just Fraction<T> does not pull in the ~185-currency ISO 4217 catalogue and FX provider stack.

Installation

dotnet add package Bodu.Numerics

Targets net8.0 and net10.0.

Fraction<T>

Fraction<T> is always held in canonical form - strictly positive denominator, sign carried on the numerator, fully reduced. Arithmetic is exact: intermediate results are evaluated with BigInteger precision and narrowed back to T, throwing OverflowException when a fixed-width component cannot represent the canonical result.

using Bodu.Numerics;

Fraction<int> a = Fraction<int>.Parse("1/3");
Fraction<int> b = Fraction<int>.Parse("1/6");

Fraction<int> sum = a + b;          // 1/2 (canonical, fully reduced)
string mixed     = (a + 1).ToString("M");   // "1 1/3"
decimal asDecimal = (decimal)sum;            // 0.5m

Highlights:

  • Arithmetic and comparison operators, named methods (Add, Negate, Abs, Reciprocal, Pow, Remainder), and GreatestCommonDivisor / LeastCommonMultiple.
  • Exact conversions from decimal and double (FromDecimal / FromDouble) and nearest-value conversions to them (ToDecimal / ToDouble), plus As<TOther>() to retype the backing component.
  • Continued-fraction expansion (ToContinuedFraction / FromContinuedFraction) and bounded best-rational approximation (LimitDenominator).
  • Parsing of integer, ratio, mixed-number, Unicode vulgar-fraction, and percent forms across string, ReadOnlySpan<char>, and UTF-8 (IParsable, ISpanParsable, IUtf8SpanParsable); formatting with general, mixed (M), Unicode (U), and percent (P) specifiers.
  • The full generic-math surface - INumber<Fraction<T>>, INumberBase<Fraction<T>>, ISignedNumber<Fraction<T>> - so Fraction<T> composes with INumber<T>-constrained code.
  • ToXml() / FromXml(string) helpers; System.Text.Json converters ship in the companion Bodu.Numerics.Serialization.Json package.

Interval<T>

using Bodu.Numerics;

Interval<int> a = Interval.Closed(1, 5);      // [1, 5]
Interval<int> b = Interval.OpenClosed(4, 8);  // (4, 8]

bool overlaps          = a.Overlaps(b);       // true
Interval<int> meet     = a.Intersect(b);      // (4, 5]
bool joined            = a.TryUnion(b, out Interval<int> u); // true -> [1, 8]
bool contains          = a.Contains(3);       // true

Highlights:

  • Independent endpoint inclusivity: [a, b], (a, b), [a, b), (a, b].
  • Factory methods (Closed, Open, ClosedOpen, OpenClosed, Singleton, Empty) plus a non-generic Interval helper that infers T (Interval.Closed(1, 5)).
  • Set algebra: Contains(T), Contains(Interval<T>), Overlaps, Intersect, and TryUnion (which succeeds only when the result is a single contiguous interval).
  • IsEmpty, IsDegenerate, and Length. All empty intervals compare equal to Empty.
  • ISO 31-11 bracket-notation formatting and parsing (IFormattable / ISpanFormattable / IUtf8SpanFormattable / IParsable / ISpanParsable). Empty intervals render as the U+2205 EMPTY SET glyph.

When to use Interval<T> vs DiscreteInterval<T>

Use Interval<T> when the endpoints are coordinates in an ordered numeric continuum - even when T is an integer coordinate type - so the values between the bounds matter. Use DiscreteInterval<T> (over IBinaryInteger<T>) when the interval represents the set of integers between its bounds. The distinction is observable:

Interval<int>.Open(1, 2).IsEmpty;          // False - the real coordinates between 1 and 2
DiscreteInterval<int>.Open(1, 2).IsEmpty;  // True  - no integer lies strictly between 1 and 2

DiscreteInterval<T> is integer-only; it is not a general discrete-domain abstraction over DateOnly, char, or enum ranges. Reach for IntervalSet<T> when a set operation can produce a disconnected result.

BigDecimal

BigDecimal is an unbounded decimal: a BigInteger unscaled value paired with a non-negative int scale, so the value is unscaledValue × 10^-scale. It grows to whatever precision a value needs - there is no MinValue/MaxValue, and only an operation whose int scale would overflow throws (OverflowException). Add, subtract, and multiply are exact; division computes to a default 50-digit working precision (half-to-even) unless you pass an explicit scale and rounding mode.

using Bodu.Numerics;

BigDecimal a = BigDecimal.Add(0.1m, 0.2m);     // 0.3 exactly
BigDecimal b = BigDecimal.Divide(10m, 3m, scale: 2, MidpointRounding.ToEven); // 3.33
BigDecimal big = BigDecimal.Parse("123456789012345678901234567890.123456789",
    System.Globalization.CultureInfo.InvariantCulture);

Highlights:

  • Exact Add / Subtract / Multiply / Negate / Abs / Pow; Divide with a default precision or an explicit scale and MidpointRounding; Remainder.
  • One canonical form with trailing zeros removed, so 1.0 and 1.00 are the same value and compare and hash equal; format with F<n> to show a fixed number of places.
  • Implicit lifts from int, long, BigInteger, and decimal; explicit conversions to/from double and to BigInteger / decimal.
  • Parsing of plain and scientific decimal text across string, ReadOnlySpan<char>, and UTF-8; G and F formatting through IFormattable / ISpanFormattable / IUtf8SpanFormattable.
  • The full generic-math surface - INumber<BigDecimal>, ISignedNumber<BigDecimal> (Radix 10) - so it composes with INumber<T>-constrained code.

Running and moving statistics

The statistics aggregates summarize a sample stream in one forward pass without storing it. RunningStatistics<T> (Welford) and RunningQuantile<T> (the P² algorithm) are mutable struct accumulators over the whole stream; MovingSum<T> and MovingMinMax<T> are class-based rolling windows over the most recent N samples. All four accept any INumber<T> sample type: extrema and window sums stay exact in T, while means, variances, and quantile estimates are computed in double.

using Bodu.Numerics;

var stats = new RunningStatistics<double>();
var p95 = new RunningQuantile<double>(0.95);
var window = new MovingMinMax<double>(60);

foreach (var latency in latencies)
{
    stats.Add(latency);
    p95.Add(latency);
    window.Add(latency);
}

// stats.Mean, stats.SampleStandardDeviation, stats.Minimum, stats.Maximum
// p95.Estimate                     - streaming 95th-percentile estimate
// window.Minimum, window.Maximum  - extrema of the last 60 samples

Highlights:

  • O(1) per sample and constant space; the samples themselves are never stored (the moving types buffer at most one window).
  • RunningStatistics<T>.Combine merges independently filled accumulators losslessly (Chan et al.), so streams can be partitioned and accumulated in parallel; P² estimators are deliberately not mergeable.
  • Non-finite samples (NaN, ±∞) are rejected at Add, so an estimate can never be silently poisoned, and the rolling-sum arithmetic is checked - fixed-width integer overflow throws instead of silently wrapping.
  • The running accumulators are mutable value types: copying one snapshots it, which is also the supported checkpoint mechanism - see the guide for the usage rules.
  • No JSON converters are provided for the accumulators: their state is transient in-process progress, not a wire contract.

Documentation

See the Bodu.Numerics guide, including the dedicated Interval<T> article.

License

MIT. © Bodu Pty. Ltd.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Bodu.Numerics:

Package Downloads
Bodu.Financial

Financial primitives for .NET. Provides Money (runtime-tagged primary monetary type), Money<TCurrency> (opt-in type-parameter currency safety with implicit conversion to and explicit conversion from the runtime form), MoneyBag (mixed-currency portfolios), CurrencyInfo and CurrencyCode (canonical metadata and a source-generated ISO 4217 enum covering every shipped code, active and historic), CurrencyRegistry (runtime lookup), and a foreign-exchange provider stack with both runtime ExchangeRate and typed ExchangeRate<TBase, TQuote>. Ships the active ISO 4217 currencies (fund and special-purpose codes excluded) plus 29 historic ones, cash rounding (CHF/AUD/CAD/NZD/SEK/NOK), and an exact-arithmetic escape hatch through Fraction<BigInteger> from Bodu.Numerics.

Bodu.Numerics.Serialization.Json

System.Text.Json integration for Bodu.Numerics. Provides converters, a shared serialization policy, and the AddNumericsJsonConverters() registration helper for Fraction<T>, BigDecimal, Complex<T>, Interval<T>, DiscreteInterval<T>, and IntervalSet<T>. The IntervalPair<T> and DiscreteIntervalPair<T> result types are transient and are not serialized; convert them with ToIntervalSet() first. Keeping JSON support in this companion package leaves the core Bodu.Numerics library serialization-agnostic.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 403 10/16/2026
1.0.0 1,601 9/24/2026
0.7.0 875 9/24/2026
0.6.0 173 9/24/2026
0.5.0 137 9/23/2026