ktsu.PreciseNumber
2.0.3
Prefix Reserved
dotnet add package ktsu.PreciseNumber --version 2.0.3
NuGet\Install-Package ktsu.PreciseNumber -Version 2.0.3
<PackageReference Include="ktsu.PreciseNumber" Version="2.0.3" />
<PackageVersion Include="ktsu.PreciseNumber" Version="2.0.3" />
<PackageReference Include="ktsu.PreciseNumber" />
paket add ktsu.PreciseNumber --version 2.0.3
#r "nuget: ktsu.PreciseNumber, 2.0.3"
#:package ktsu.PreciseNumber@2.0.3
#addin nuget:?package=ktsu.PreciseNumber&version=2.0.3
#tool nuget:?package=ktsu.PreciseNumber&version=2.0.3
ktsu.PreciseNumber
A high-precision numeric type for .NET that provides arbitrary precision arithmetic with a focus on accuracy. By combining the scale benefits of scientific notation with the precision of BigInteger, this library offers reliable and accurate mathematical operations where standard floating point types fall short.
Table of Contents
Features
Arbitrary Precision: Based on
BigIntegerfor the significand, allowing numbers of unlimited size.Scientific Notation: Uses an exponent and significand (the coefficient or mantissa in scientific notation) model similar to scientific notation.
Lossless Arithmetic: Preserves precision during calculations with no rounding errors.
Full .NET Integration: Implements
INumber<T>, includingCreateChecked,CreateSaturating, andCreateTruncatingin both directions, so generic math code can create and convert values.Value Type: A
readonly record structwhosedefaultvalue is zero. Adding, subtracting, multiplying, and comparing allocate nothing when the operands and every intermediate and final significand fit in anint. Exponent alignment counts, so1 + 0.0000000001allocates because it scales 1 by 10^10, and99999 * 99999allocates because its product is 9,999,800,001.Comprehensive Mathematical Support: Includes advanced mathematical functions like exponential operations (Pow, Exp, Squared, Cubed), constant values (Pi, E, Tau) with high precision, absolute value operations, and specialized numerical checks (isOdd, isEven, etc.)—all with arbitrary precision.
Balanced Performance: The design prioritizes accuracy and precision while maintaining reasonable performance. For calculations where extreme precision matters more than raw speed, PreciseNumber delivers excellent results, though built-in numeric types remain faster for standard precision needs.
Getting Started
Installation
To install PreciseNumber, you can use the .NET CLI:
dotnet add package ktsu.PreciseNumber
Or you can use the NuGet Package Manager in Visual Studio by searching for ktsu.PreciseNumber.
Requirements
This library requires .NET 8.0 or later.
Quick Usage
Basic Example
using System.Numerics;
using ktsu.PreciseNumber;
// Create PreciseNumber from various types
var precise1 = 123.456.ToPreciseNumber();
var precise2 = BigInteger.Parse("1234567890").ToPreciseNumber();
// Perform calculation with high precision
var result = precise1 * precise2 / 7.89.ToPreciseNumber();
Console.WriteLine(result); // Displays accurate result with no floating point errors
Common Operations
Create and perform operations with precise numbers:
using ktsu.PreciseNumber;
// Create PreciseNumbers from various numeric types
var a = 123.456.ToPreciseNumber();
var b = 2.ToPreciseNumber();
// Basic arithmetic operations
var sum = a + b; // 125.456
var difference = a - b; // 121.456
var product = a * b; // 246.912
var quotient = a / b; // 61.728
// Comparison
bool isGreater = a > b; // true
When to Use PreciseNumber
PreciseNumber is ideal for:
Financial calculations where exact precision is required beyond what decimal offers
Scientific computing involving very large or small numbers with many significant digits
Cryptography applications requiring arbitrary precision arithmetic
Mathematical algorithms where rounding errors would accumulate and affect results
For everyday calculations where standard precision is sufficient, built-in types like int, double, or decimal will offer better performance.
Advanced Usage
Type Conversions
The library provides seamless round-trip conversions between standard numeric types and PreciseNumber using extension methods:
using System.Numerics;
using ktsu.PreciseNumber;
// Convert FROM standard types TO PreciseNumber
int originalInt = 42;
double originalDouble = 3.14159;
decimal originalDecimal = 1234.5678m;
BigInteger originalBigInt = BigInteger.Parse("123456789012345678901234567890");
// Convert using the ToPreciseNumber() extension method
var preciseInt = originalInt.ToPreciseNumber();
var preciseDouble = originalDouble.ToPreciseNumber();
var preciseDecimal = originalDecimal.ToPreciseNumber();
var preciseBigInt = originalBigInt.ToPreciseNumber();
// Perform precise calculations if needed
preciseInt *= 10;
preciseDouble += PreciseNumber.Pi;
// Convert back FROM PreciseNumber TO standard types using To<T>()
int roundTripInt = preciseInt.To<int>(); // 420
double roundTripDouble = preciseDouble.To<double>(); // ~6.28318
decimal roundTripDecimal = preciseDecimal.To<decimal>(); // 1234.5678
BigInteger roundTripBigInt = preciseBigInt.To<BigInteger>(); // 123456789012345678901234567890
// Verify round-trip conversion (for values that weren't modified)
Console.WriteLine(originalDecimal == roundTripDecimal); // True
Console.WriteLine(originalBigInt == roundTripBigInt); // True
Generic math conversions
Code written against INumber<T> reaches PreciseNumber through CreateChecked, CreateSaturating, and CreateTruncating. They work in both directions for every built-in numeric type and BigInteger:
using System.Numerics;
using ktsu.PreciseNumber;
static T ToMeters<T>(T feet) where T : INumber<T> => feet * T.CreateChecked(0.3048);
PreciseNumber meters = ToMeters(10.ToPreciseNumber()); // exactly 3.048
double asDouble = double.CreateChecked(meters); // 3.048
int whole = int.CreateChecked(meters); // 3, truncated toward zero
- Integers,
BigInteger, anddecimalconvert in exactly.double,float, andHalfconvert through their decimal text, so0.3048arrives as exactly 0.3048. - NaN throws in a checked conversion and becomes zero otherwise. An infinity always throws. Both match
BigInteger. - Integer destinations keep the integral part. Checked throws when it's out of range, saturating clamps, and truncating wraps the way
BigIntegerdoes. double,float, andHalfdestinations are correctly rounded however many digits the number has.decimaldestinations round to the digitsdecimalholds. Checked throws when the value is out of range, and saturating and truncating clamp.
To<T>() uses the same conversions.
Mathematical Functions
PreciseNumber supports a wide range of mathematical operations:
using ktsu.PreciseNumber;
var number = 2.5.ToPreciseNumber();
// Exponentiation
var squared = number.Squared(); // 6.25
var cubed = number.Cubed(); // 15.625
var toThe4th = number.Pow(4.ToPreciseNumber()); // 39.0625
// Constants
var pi = PreciseNumber.Pi;
var e = PreciseNumber.E;
// Exponential function
var expValue = PreciseNumber.Exp(1.ToPreciseNumber()); // e^1 = e
// Rounding and precision control
var roundedValue = number.Round(1); // 2.5 (already at 1 decimal place)
var reducedValue = number.ReduceSignificance(1); // 3 (reduced to 1 significant digit)
// Min, Max, Abs, and Clamp
var absValue = (-5).ToPreciseNumber().Abs(); // 5
var maxValue = PreciseNumber.Max(2.ToPreciseNumber(), 3.ToPreciseNumber()); // 3
var minValue = PreciseNumber.Min(2.ToPreciseNumber(), 3.ToPreciseNumber()); // 2
var clampedValue = 10.ToPreciseNumber().Clamp(0, 5); // 5 (clamped to maximum)
Parsing and Formatting
Parsing from Strings
using System.Globalization;
using System.Numerics;
using ktsu.PreciseNumber;
// Parse from string using various formats
var number1 = PreciseNumber.Parse("123.456", CultureInfo.InvariantCulture);
var number2 = PreciseNumber.Parse("1.23E4", NumberStyles.Any, CultureInfo.InvariantCulture);
// Try parsing with error handling
if (PreciseNumber.TryParse("456.789", out var result))
{
Console.WriteLine($"Parsed successfully: {result}");
}
String Formatting
Convert PreciseNumber to string:
using ktsu.PreciseNumber;
var number = 123.456.ToPreciseNumber();
string formatted = number.ToString(); // "123.456"
Comparison with Built-in Types
PreciseNumber vs. double/float
- Advantages of PreciseNumber:*
No Rounding Errors: Unlike floating-point types, PreciseNumber doesn't suffer from binary representation issues (e.g., 0.1 + 0.2 ≠ 0.3 in floating point)
Arbitrary Precision: Not limited to 15-17 significant digits (double) or 6-9 significant digits (float)
Consistent Results: Mathematical operations produce identical results regardless of magnitude
No Special Values: PreciseNumber doesn't have NaN or Infinity values that can propagate through calculations
// Double arithmetic issue
double a = 0.1;
double b = 0.2;
Console.WriteLine(a + b == 0.3); // False (equals 0.30000000000000004)
// PreciseNumber solves this
var pa = 0.1.ToPreciseNumber();
var pb = 0.2.ToPreciseNumber();
Console.WriteLine((pa + pb) == 0.3.ToPreciseNumber()); // True (exactly 0.3)
PreciseNumber vs. decimal
- Advantages of PreciseNumber:*
Unlimited Range: Not constrained by decimal's ±7.9E±28 range
Unlimited Precision: Decimal is limited to 28-29 significant digits
Scientific Operations: Better suited for scientific calculations requiring extreme precision
More Flexible Format: Exponent-significand model makes it suitable for both very large and very small numbers
// Decimal range/precision limitations
decimal largeDecimal = 1.0m;
for (int i = 0; i < 30; i++)
largeDecimal *= 10; // Will throw OverflowException
// PreciseNumber handles this easily
var largePrecise = PreciseNumber.One;
for (int i = 0; i < 1000; i++)
largePrecise *= 10; // Works fine with arbitrary large values
PreciseNumber vs. BigInteger
- Advantages of PreciseNumber:*
Decimal Point Support: Represents both integer and fractional parts while BigInteger only handles integers
Scientific Notation: More convenient for very large or small numbers with fraction components
Mathematical Constants: Built-in support for constants like Pi and E with high precision
Technical Details
Internal Representation
PreciseNumber stores values in the form: significand × 10^exponent
Significand: A
BigIntegerthat contains all the significant digitsExponent: An
intthat determines the decimal place
This representation allows for:
Exact representation of integers of any size
High precision for decimal values
Accurate arithmetic without floating-point errors
A
defaultvalue that is exactly zero, since PreciseNumber is a value type
Precision Control
You can control precision using:
Round(): Rounds to a specific number of decimal places, half away from zero
ReduceSignificance(): Reduces to a specific number of significant digits, half away from zero
Divide(left, right, significantDigits): Chooses the precision of a quotient
Division produces a terminating quotient exactly, however many digits that takes — 1 / 8 is
0.125, and 1 / 2^64 keeps all 64 decimal places. A repeating quotient is produced to the
precision of the wider operand, never fewer than MinimumDivisionPrecision (50) significant
digits, with the last digit rounded half away from zero. Pass an explicit precision to the
three-argument overload when you want something other than that.
Limitations
Exp(), andPow()with a non-integer power, are computed throughdoubleand are therefore limited to its precision. Addition, subtraction, multiplication and division are notA checked conversion to an integer type or
decimalthrowsOverflowExceptionwhen the value is out of range. Conversion todouble,float, orHalfoverflows to infinity instead, as it does for every built-in typeConverting from
double,float, orHalfkeeps the shortest digits that round-trip, so converting back gives the original value, and0.3048stays exactly 0.3048. The result of0.1 + 0.2indoublearrives as 0.30000000000000004, because that's the value thedoubleholds
Performance
Values are immutable value types. Every operation returns a new value, but that value lives inline
in its variable, field, or array element, so the only heap allocation is the BigInteger digit
array, and a significand that fits in an int doesn't need one. Cost therefore tracks the number
of significant digits rather than the magnitude of the value, and allocation matters as much as
raw speed.
The repository carries a BenchmarkDotNet suite covering construction, comparison, arithmetic, rounding, text conversion and primitive conversion, each parameterised across 8, 30 and 200 significant digits:
dotnet run -c Release --project PreciseNumber.Benchmarks -- --filter '*ArithmeticBenchmarks*'
Run it before and after any change to the library's internals. A full run can also be started from the Benchmarks workflow in GitHub Actions, which archives the reports against the commit that produced them.
API Reference
PreciseNumber Class
Constants:
Zero,One,NegativeOne,Pi,E,TauArithmetic:
+,-,*,/,%,++,--Comparison:
==,!=,<,>,<=,>=Functions:
Abs(),Round(),Clamp(),Squared(),Cubed(),Pow(),Exp()Utility:
ToString(),Parse(),TryParse(),To<T>()Generic Conversion:
TryConvertFromChecked,TryConvertFromSaturating,TryConvertFromTruncating,TryConvertToChecked,TryConvertToSaturating, andTryConvertToTruncating, reached throughCreateChecked,CreateSaturating, andCreateTruncating
Upgrading from 1.x? See the 2.0 migration guide.
PreciseNumberExtensions Class
- Conversion:
ToPreciseNumber<T>()extension method for anyINumber<T>
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
Acknowledgements
Thanks to the .NET community and ktsu.dev contributors for their support.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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. |
-
net10.0
- No dependencies.
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on ktsu.PreciseNumber:
| Package | Downloads |
|---|---|
|
ktsu.SignificantNumber
High-precision arithmetic class representing numbers with a significand and exponent. Supports significant figure rules, mathematical computations, and formatting. |
|
|
ktsu.Semantics.Quantities.Precise
A comprehensive .NET library for replacing primitive obsession with strongly-typed, self-validating domain models across four pillars: semantic strings with 50+ validation attributes, polymorphic path handling, metadata-generated semantic quantities, and musical value types. The quantity system covers 60+ physical dimensions and 200+ generated types under a unified vector model, with compile-time dimensional safety, generated unit conversions and physics relationships, centralized physical constants, and optional per-storage-type alias packages. The music types provide type-safe pitches, intervals, scales and modes, chords with symbol parsing and voicing, keys with roman-numeral analysis, and rational durations and time signatures. Features factory-pattern and dependency-injection support for building robust, maintainable scientific and domain-specific applications. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.3 | 0 | 9/14/2026 |
| 2.0.2 | 0 | 9/14/2026 |
| 2.0.1 | 32 | 9/14/2026 |
| 2.0.0 | 46 | 9/13/2026 |
| 1.9.0 | 40 | 9/13/2026 |
| 1.8.0 | 43 | 9/13/2026 |
| 1.7.36 | 50 | 9/11/2026 |
| 1.7.35 | 165 | 9/3/2026 |
| 1.7.34 | 164 | 8/26/2026 |
| 1.7.33 | 169 | 8/22/2026 |
| 1.7.32 | 94 | 8/21/2026 |
| 1.7.31 | 130 | 8/20/2026 |
| 1.7.30 | 130 | 8/19/2026 |
| 1.7.29 | 119 | 8/18/2026 |
| 1.7.28 | 95 | 8/18/2026 |
| 1.7.27 | 1,210 | 8/11/2026 |
| 1.7.26 | 320 | 8/6/2026 |
| 1.7.25 | 110 | 8/5/2026 |
| 1.7.24 | 106 | 8/5/2026 |
| 1.7.23 | 679 | 7/29/2026 |
## v2.0.3 (patch)
Changes since v2.0.2:
- Write benchmark results where the workflow looks for them [patch] ([@Claude](https://github.com/Claude))