ktsu.SignificantNumber
2.0.3
Prefix Reserved
dotnet add package ktsu.SignificantNumber --version 2.0.3
NuGet\Install-Package ktsu.SignificantNumber -Version 2.0.3
<PackageReference Include="ktsu.SignificantNumber" Version="2.0.3" />
<PackageVersion Include="ktsu.SignificantNumber" Version="2.0.3" />
<PackageReference Include="ktsu.SignificantNumber" />
paket add ktsu.SignificantNumber --version 2.0.3
#r "nuget: ktsu.SignificantNumber, 2.0.3"
#:package ktsu.SignificantNumber@2.0.3
#addin nuget:?package=ktsu.SignificantNumber&version=2.0.3
#tool nuget:?package=ktsu.SignificantNumber&version=2.0.3
ktsu.SignificantNumber
SignificantNumber is a numeric value type whose arithmetic follows the rules for significant figures. It holds a ktsu.PreciseNumber and rounds every result to the precision its operands justify.
Features
- Addition and subtraction round to the fewest decimal places among the operands, and multiplication, division, and modulus round to the fewest significant digits
- Operands of exactly -1, 0, or 1 have unlimited precision, so they never limit a result
- A
readonly record structwhosedefaultis zero, holding aPreciseNumberthat it converts to implicitly - Implements
INumber<SignificantNumber>, includingCreateChecked,CreateSaturating, andCreateTruncatingfor every built-in numeric type,BigInteger, andPreciseNumber
Upgrading from 1.x? See the 2.0 migration guide.
Table of contents
Performance
<picture> <source media="(prefers-color-scheme: dark)" srcset="docs/benchmarks/performance-dark.svg"> <img alt="Allocated bytes per operation, and time relative to a fixed reference workload, for each SignificantNumber release" src="docs/benchmarks/performance.svg"> </picture>
Every release measures a fixed set of benchmarks and adds a point to the chart; the numbers behind
it are in docs/benchmarks/history.json, and the suite is
SignificantNumber.Benchmarks.
Read the two halves differently. Allocation is exact — the same code allocates the same bytes on any machine, so a step in the top row is always a real change. Time is measured on shared CI runners, where the host a job happens to land on varies more than most releases do, so each time is divided by a reference workload measured in the same job. That cancels most of the difference between machines; what is left is indicative rather than precise.
The step at 2.0 is the type becoming a readonly record struct over PreciseNumber instead of
deriving from it. A 200-digit addition went from 54,688 bytes and 128 μs to 112 bytes and 340 ns.
Installation
Install the package with the .NET CLI:
dotnet add package ktsu.SignificantNumber
Or add the package reference directly in your project file:
<PackageReference Include="ktsu.SignificantNumber" Version="x.x.x" />
Usage
Creating a SignificantNumber
Create a SignificantNumber from any supported numeric type with the ToSignificantNumber extension method, from text with Parse, or from a PreciseNumber with an explicit cast.
Supported numeric types
ToSignificantNumber converts through INumber<T>. These types are supported:
Integer types:
intlongshortsbyteuintulongushortbyteBigInteger
Floating point types:
doublefloatHalfdecimal
ktsu types:
PreciseNumberSignificantNumber
Examples
using System.Numerics;
using ktsu.PreciseNumber;
using ktsu.SignificantNumber;
// Integer types
int intValue = 12345;
SignificantNumber significantNumberFromInt = intValue.ToSignificantNumber();
BigInteger bigIntValue = new BigInteger(9876543210);
SignificantNumber significantNumberFromBigInt = bigIntValue.ToSignificantNumber();
// Floating point types
double doubleValue = 123.45;
SignificantNumber significantNumberFromDouble = doubleValue.ToSignificantNumber();
Half halfValue = (Half)123.45;
SignificantNumber significantNumberFromHalf = halfValue.ToSignificantNumber();
float floatValue = 123.45f;
SignificantNumber significantNumberFromFloat = floatValue.ToSignificantNumber();
decimal decimalValue = 123.45m;
SignificantNumber significantNumberFromDecimal = decimalValue.ToSignificantNumber();
// A PreciseNumber, with an explicit cast because it opts into the significant figure rules
PreciseNumber precise = 12.5.ToPreciseNumber();
SignificantNumber significantNumberFromPrecise = (SignificantNumber)precise;
Arithmetic operations
SignificantNumber result1 = number1 + number2;
SignificantNumber result2 = number1 - number2;
SignificantNumber result3 = number1 * number2;
SignificantNumber result4 = number1 / number2;
// Square and cube operations, which return the unrounded PreciseNumber
PreciseNumber squared = number1.Squared();
PreciseNumber cubed = number1.Cubed();
// Power operation
SignificantNumber powerResult = number1.Pow(3.ToPreciseNumber());
The operators also accept a PreciseNumber on either side, and the result is a SignificantNumber.
Comparison operations
bool isEqual = number1 == number2;
bool isGreater = number1 > number2;
bool isLessOrEqual = number1 <= number2;
Ordering operators compare values exactly. SignificantNumber.CompareTo(left, right) and CompareTo(SignificantNumber) compare both numbers at the lower of their significant digit counts.
Formatting and parsing
Format a SignificantNumber as a string:
string formatted = number1.ToString("G", CultureInfo.InvariantCulture);
Console.WriteLine(formatted); // Outputs the formatted number
Parse one from text, including scientific notation:
SignificantNumber parsed = SignificantNumber.Parse("1.23E4", NumberStyles.Float, CultureInfo.InvariantCulture);
if (SignificantNumber.TryParse("123.45", CultureInfo.InvariantCulture, out SignificantNumber result))
{
Console.WriteLine(result);
}
TryParse yields zero when parsing fails.
Extension methods
ToSignificantNumber
Converts a supported numeric type to a SignificantNumber. An overload takes the number of significant digits to keep.
Usage
public static SignificantNumber ToSignificantNumber<TInput>(this TInput input)
where TInput : INumber<TInput>
public static SignificantNumber ToSignificantNumber<TInput>(this TInput input, int significantDigits)
where TInput : INumber<TInput>
Parameters
input: The number to convert.significantDigits: The number of significant digits to keep. It must be greater than zero.
Returns
SignificantNumber: The converted number.
Example
double floatingPointValue = 123.45;
SignificantNumber significantNumberFromFloat = floatingPointValue.ToSignificantNumber();
int integerValue = 12345;
SignificantNumber significantNumberFromInt = integerValue.ToSignificantNumber();
SignificantNumber result = significantNumberFromFloat + significantNumberFromInt;
// result = 12468.45
Conversion
To<TOutput>
Converts a SignificantNumber to the specified numeric type.
Usage
public TOutput To<TOutput>()
where TOutput : INumber<TOutput>
Returns
TOutput: The converted value of theSignificantNumber.
Example
SignificantNumber significantNumber = SignificantNumber.Parse("12345E3", NumberStyles.Float, CultureInfo.InvariantCulture);
double result = significantNumber.To<double>();
Console.WriteLine(result); // Outputs 12345000
Generic code converts the same way through CreateChecked, CreateSaturating, and CreateTruncating:
static T ToMeters<T>(T feet) where T : INumber<T> => feet * T.CreateChecked(0.3048);
SignificantNumber meters = ToMeters(10.ToSignificantNumber());
double asDouble = double.CreateChecked(meters);
A SignificantNumber converts to a PreciseNumber implicitly, and Value returns the PreciseNumber it holds.
Precision
Significand and exponent
A SignificantNumber holds a PreciseNumber, which stores two components:
- Significand: The significant digits of the number, stored as a
BigInteger. - Exponent: The power of ten that scales the significand.
Significand, Exponent, and SignificantDigits are available directly on SignificantNumber.
Precision handling
- Floating point input: A
floatkeeps up to 8 significant digits, and adoubleup to 16. - Trailing zero removal: Trailing zeros move from the significand into the exponent, so every value is stored in its most compact form.
- Rounding:
Roundrounds to a number of decimal digits, andReduceSignificanceto a number of significant digits.
Example of precision
Consider the number 123.456000:
- As a
SignificantNumber, it's stored as123456e-3after removing the trailing zeros and adjusting the exponent. - Adding
1.2to it rounds the sum to one decimal place, giving124.7, because1.2has the fewest decimal places.
API reference
Properties
PreciseNumber Value- Gets thePreciseNumberthe number holds.int Exponent,BigInteger Significand, andint SignificantDigits- Get the components of the held value.static SignificantNumber NegativeOne,One, andZero- Get -1, 1, and 0.Zerois alsodefault.static SignificantNumber E,Pi, andTau- Get the mathematical constants.static int Radix- Gets the radix, or base, for the type.static SignificantNumber AdditiveIdentity- Gets the additive identity of the type.static SignificantNumber MultiplicativeIdentity- Gets the multiplicative identity of the type.
Methods
bool Equals(SignificantNumber other)- Determines whether two numbers have the same significand and exponent.int CompareTo(object? obj)- Compares the current instance with another object.int CompareTo(SignificantNumber other)- Compares the current instance with another significant number at the lower of their significant digit counts.int CompareTo<TInput>(TInput other) where TInput : INumber<TInput>- Compares the value of the current instance with another number.PreciseNumber Abs()- Returns the absolute value of the current instance.PreciseNumber Round(int decimalDigits)- Rounds the current instance to the specified number of decimal digits.PreciseNumber ReduceSignificance(int significantDigits)- Reduces the current instance to the specified number of significant digits.PreciseNumber Clamp<TNumber>(TNumber min, TNumber max) where TNumber : INumber<TNumber>- Clamps the current instance between the minimum and maximum values.SignificantNumber Pow(PreciseNumber power)- Raises the current instance to a power.PreciseNumber ToPreciseNumber()- Returns thePreciseNumberthe number holds.string ToString(string? format, IFormatProvider? formatProvider)- Converts the current instance to a string using the specified format and format provider.bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)- Attempts to format the current instance into the provided span.TOutput To<TOutput>() where TOutput : INumber<TOutput>- Converts the current significant number to the specified numeric type.
Static methods
static SignificantNumber FromPreciseNumber(PreciseNumber value)- Creates a significant number that holds aPreciseNumber.static SignificantNumber Add,Subtract,Multiply,Divide, andMod(PreciseNumber left, PreciseNumber right)- Apply the significant figure rules to two numbers.static SignificantNumber Exp(PreciseNumber power)- Raises e to a power.static SignificantNumber Max,Min(SignificantNumber x, SignificantNumber y), andClamp(SignificantNumber value, SignificantNumber min, SignificantNumber max)- Compare by value.static SignificantNumber Round(SignificantNumber value, int decimalDigits)- Rounds a number to the specified number of decimal digits.static SignificantNumber Abs(SignificantNumber value)- Returns the absolute value of aSignificantNumber.static bool IsCanonical(SignificantNumber value)- Determines whether the specified value is canonical.static bool IsComplexNumber(SignificantNumber value)- Determines whether the specified value is a complex number.static bool IsEvenInteger(SignificantNumber value)- Determines whether the specified value is an even integer.static bool IsFinite(SignificantNumber value)- Determines whether the specified value is finite.static bool IsImaginaryNumber(SignificantNumber value)- Determines whether the specified value is an imaginary number.static bool IsInfinity(SignificantNumber value)- Determines whether the specified value is infinite.static bool IsInteger(SignificantNumber value)- Determines whether the specified value is an integer.static bool IsNaN(SignificantNumber value)- Determines whether the specified value is NaN.static bool IsNegative(SignificantNumber value)- Determines whether the specified value is negative.static bool IsNegativeInfinity(SignificantNumber value)- Determines whether the specified value is negative infinity.static bool IsNormal(SignificantNumber value)- Determines whether the specified value is normal.static bool IsOddInteger(SignificantNumber value)- Determines whether the specified value is an odd integer.static bool IsPositive(SignificantNumber value)- Determines whether the specified value is positive.static bool IsPositiveInfinity(SignificantNumber value)- Determines whether the specified value is positive infinity.static bool IsRealNumber(SignificantNumber value)- Determines whether the specified value is a real number.static bool IsSubnormal(SignificantNumber value)- Determines whether the specified value is subnormal.static bool IsZero(SignificantNumber value)- Determines whether the specified value is zero.static SignificantNumber MaxMagnitude(SignificantNumber x, SignificantNumber y)- Returns the larger of the magnitudes of two significant numbers.static SignificantNumber MaxMagnitudeNumber(SignificantNumber x, SignificantNumber y)- Returns the larger of the magnitudes of two significant numbers.static SignificantNumber MinMagnitude(SignificantNumber x, SignificantNumber y)- Returns the smaller of the magnitudes of two significant numbers.static SignificantNumber MinMagnitudeNumber(SignificantNumber x, SignificantNumber y)- Returns the smaller of the magnitudes of two significant numbers.
Operators
static implicit operator PreciseNumber(SignificantNumber value)- Converts to the heldPreciseNumber.static explicit operator SignificantNumber(PreciseNumber value)- Creates a significant number that holds aPreciseNumber.static SignificantNumber operator -(SignificantNumber value)- Negates a significant number.static SignificantNumber operator +,-,*,/, and%- Apply the significant figure rules. Each also accepts aPreciseNumberon either side.static SignificantNumber operator +(SignificantNumber value)- Returns the unary plus of a significant number.static SignificantNumber operator ++and--- Increment and decrement by one.static bool operator ==and!=- Determine whether two numbers are equal, including against aPreciseNumber.static bool operator >,<,>=, and<=- Compare two numbers, including against aPreciseNumber.
Contributing
Contributions are welcome. Submit a pull request or open an issue.
License
This project is licensed under the MIT License. See the LICENSE file for details.
| 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
- ktsu.PreciseNumber (>= 2.1.0)
-
net7.0
- ktsu.PreciseNumber (>= 2.1.0)
-
net8.0
- ktsu.PreciseNumber (>= 2.1.0)
-
net9.0
- ktsu.PreciseNumber (>= 2.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ktsu.SignificantNumber:
| Package | Downloads |
|---|---|
|
ktsu.PhysicalQuantity
Physical Quantity |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.3 | 0 | 9/16/2026 |
| 2.0.2 | 28 | 9/16/2026 |
| 2.0.1 | 53 | 9/16/2026 |
| 2.0.0 | 80 | 9/15/2026 |
| 1.4.40 | 89 | 9/14/2026 |
| 1.4.39 | 89 | 9/11/2026 |
| 1.4.38 | 115 | 9/4/2026 |
| 1.4.37 | 109 | 9/3/2026 |
| 1.4.36 | 106 | 8/28/2026 |
| 1.4.35 | 107 | 8/26/2026 |
| 1.4.34 | 116 | 8/24/2026 |
| 1.4.33 | 112 | 8/21/2026 |
| 1.4.32 | 104 | 8/20/2026 |
| 1.4.31 | 108 | 8/19/2026 |
| 1.4.30 | 105 | 8/18/2026 |
| 1.4.29 | 110 | 8/17/2026 |
| 1.4.28 | 97 | 8/11/2026 |
| 1.4.27 | 104 | 8/6/2026 |
| 1.4.26 | 94 | 8/6/2026 |
| 1.4.25 | 100 | 8/5/2026 |
## v2.0.3 (patch)
Changes since v2.0.2:
- Seed the abstraction-cost pair across every release [patch] ([@Claude](https://github.com/Claude))
- Measure this type against a bare double, and chart it per release [patch] ([@Claude](https://github.com/Claude))