DecimalMath.Net 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package DecimalMath.Net --version 0.1.0
                    
NuGet\Install-Package DecimalMath.Net -Version 0.1.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="DecimalMath.Net" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DecimalMath.Net" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="DecimalMath.Net" />
                    
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 DecimalMath.Net --version 0.1.0
                    
#r "nuget: DecimalMath.Net, 0.1.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 DecimalMath.Net@0.1.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=DecimalMath.Net&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=DecimalMath.Net&version=0.1.0
                    
Install as a Cake Tool

DecimalMath.NET

Decimal-precision math for money: square and cube roots, powers, exponentials, logarithms, trigonometry, and penny-exact allocation, all operating on System.Decimal instead of double. Zero external dependencies.

System.Math only speaks double. The moment you call Math.Sqrt, Math.Pow, or Math.Log on a decimal amount, it round-trips through binary floating point and back, and you have quietly reintroduced the exact class of rounding bug that decimal exists to prevent. The one widely used package that filled this gap for .NET, DecimalEx, has not seen a functional release in years and its allocation helpers do not guarantee an exact-sum result. DecimalMath.NET is built for the common case that actually shows up in financial code: split an invoice into equal installments, prorate a subscription fee across a partial period, compute compound interest, without a single cent going missing or appearing from nowhere.

Install

dotnet add package DecimalMath.Net

Usage

Split an invoice so every kobo is accounted for

using DecimalMath;

decimal invoiceTotal = 100.00m;
IReadOnlyList<decimal> installments = DecimalAllocator.AllocateEvenly(invoiceTotal, count: 3);
// [33.34, 33.33, 33.33] -- sums to exactly 100.00, not 99.99

Allocate and AllocateEvenly use the largest-remainder method: every part is rounded down first, then the leftover cents are handed out one at a time to the parts with the largest fractional remainder. The result always sums to exactly the input amount, for any weights, any count, negative amounts included -- provided the amount is itself representable at the target decimalPlaces (a two-decimal-place amount when allocating to cents, say). An amount with a smaller unit than that, like Allocate(10.555m, weights) at the default two decimal places, cannot be split into cent-rounded parts that also sum back to exactly 10.555, so both methods throw ArgumentException rather than silently lose or manufacture the sub-cent fraction.

Prorate a subscription fee

using DecimalMath;

decimal monthlyFee = 29.99m;
int daysInMonth = 30;
int daysUsed = 12;

decimal proratedCharge = DecimalAllocator.Prorate(monthlyFee, daysUsed, daysInMonth);
// 11.996 rounded to 12.00

Compound interest without a double round-trip

using DecimalMath;

decimal principal = 5000.00m;
decimal annualRate = 0.045m;
int years = 10;

decimal futureValue = principal * DecimalMath.Pow(1m + annualRate, years);
// computed entirely in decimal arithmetic, no double in the pipeline

What is in the box

Roots and powers: Sqrt, Cbrt, Pow.

Exponentials and logarithms: Exp, Ln, Log10, Log2, Log(x, newBase), plus the constants Pi and E.

Trigonometry: Sin, Cos, Tan, Asin, Acos, Atan, Atan2.

Allocation: DecimalAllocator.Allocate(amount, weights), DecimalAllocator.AllocateEvenly(amount, count), DecimalAllocator.Prorate(amount, unitsUsed, totalUnits).

How the transcendental functions work

Every function stays in decimal arithmetic from input to output. Sqrt and Cbrt use Newton's method, seeded from a fast double approximation and refined in decimal until convergence. Exp and Ln use range reduction (powers of two) followed by a Taylor or Newton-friendly power series. Sin, Cos, Asin, Atan follow the same pattern, with Atan built on the identity atan(x) = asin(x / sqrt(1 + x^2)) and Atan2 composed from Atan. Pi and E are computed once, at load time, from convergent series (Machin's formula and e = sum(1/n!)) rather than hard-coded digit strings.

Every series and Newton iteration runs until successive terms differ by less than 1e-28, the smallest positive value decimal can represent, so the result is accurate to within a relative error on the order of 1e-27 to 1e-28 -- the last one or two of decimal's ~28-29 significant digits may differ from the true value; everything before that is exact. The test suite checks this four ways: exact results for inputs with an exact answer (perfect squares, integer powers, sin(pi/2)), cross-checks against System.Math's double implementations as a reference oracle (good to double's own ~15-17 digits), algebraic identities (sqrt(x) squared == x, exp(ln(x)) == x, pow(x, 0.5) == sqrt(x), sin(x)^2 + cos(x)^2 == 1) verified entirely in decimal arithmetic, and -- the layer that actually exercises digits 11 through 28, the reason this library exists over double -- 28-digit reference fixtures for Pi, E, Sqrt(2), Ln(2), Ln(10), Exp(1), Exp(5) and known trig points, computed independently via arbitrary-precision (BigInteger fixed-point) arithmetic rather than by this library's own series.

Zero dependencies, AOT-friendly

No runtime NuGet dependencies. No reflection, no dynamic code generation, nothing that needs a JIT. Every function is a static method built from arithmetic and loops, so the package works unmodified under Native AOT and trimming.

License

MIT. See LICENSE.

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 was computed.  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.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 82 8/21/2026
0.1.0 93 8/12/2026