Bodu.Numerics
1.3.0
dotnet add package Bodu.Numerics --version 1.3.0
NuGet\Install-Package Bodu.Numerics -Version 1.3.0
<PackageReference Include="Bodu.Numerics" Version="1.3.0" />
<PackageVersion Include="Bodu.Numerics" Version="1.3.0" />
<PackageReference Include="Bodu.Numerics" />
paket add Bodu.Numerics --version 1.3.0
#r "nuget: Bodu.Numerics, 1.3.0"
#:package Bodu.Numerics@1.3.0
#addin nuget:?package=Bodu.Numerics&version=1.3.0
#tool nuget:?package=Bodu.Numerics&version=1.3.0
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 anyIBinaryInteger<T>backing component.Interval<T>- an immutable connected interval over anyINumber<T>endpoint type, with independent open/closed (and unbounded) endpoints and set algebra.DiscreteInterval<T>- a connected integer-domain interval overIBinaryInteger<T>, with successor/predecessor-aware emptiness and adjacency.IntervalSet<T>- a normalized set of disconnectedInterval<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 anIntervalSet<T>.BigDecimal- an immutable arbitrary-precision decimal (aBigIntegerunscaled value plus anintscale), for exact decimal values beyondSystem.Decimal's precision or exponent range.Complex<T>- an immutable complex number over anyIFloatingPointIeee754<T>component type (float,double,Half), the generic counterpart of thedouble-onlySystem.Numerics.Complex.RunningStatistics<T>/RunningQuantile<T>- single-pass, constant-space accumulators over a sample stream: Welford count/min/max/mean/variance with a parallelCombinemerge, 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), andGreatestCommonDivisor/LeastCommonMultiple. - Exact conversions from
decimalanddouble(FromDecimal/FromDouble) and nearest-value conversions to them (ToDecimal/ToDouble), plusAs<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>>- soFraction<T>composes withINumber<T>-constrained code. ToXml()/FromXml(string)helpers;System.Text.Jsonconverters ship in the companionBodu.Numerics.Serialization.Jsonpackage.
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-genericIntervalhelper that infersT(Interval.Closed(1, 5)). - Set algebra:
Contains(T),Contains(Interval<T>),Overlaps,Intersect, andTryUnion(which succeeds only when the result is a single contiguous interval). IsEmpty,IsDegenerate, andLength. All empty intervals compare equal toEmpty.- 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;Dividewith a default precision or an explicit scale andMidpointRounding;Remainder. - One canonical form with trailing zeros removed, so
1.0and1.00are the same value and compare and hash equal; format withF<n>to show a fixed number of places. - Implicit lifts from
int,long,BigInteger, anddecimal; explicit conversions to/fromdoubleand toBigInteger/decimal. - Parsing of plain and scientific decimal text across
string,ReadOnlySpan<char>, and UTF-8;GandFformatting throughIFormattable/ISpanFormattable/IUtf8SpanFormattable. - The full generic-math surface -
INumber<BigDecimal>,ISignedNumber<BigDecimal>(Radix10) - so it composes withINumber<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>.Combinemerges 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 | Versions 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. |
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.