This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ktsu.PreciseNumber is a high-precision numeric type for .NET that provides arbitrary precision arithmetic. It combines the scale benefits of scientific notation with the precision of BigInteger, storing values internally as significand × 10^exponent.
dotnet build # Build the solution
dotnet test # Run all tests
dotnet test --filter "FullyQualifiedName~TestName" # Run specific test
# Benchmarks (Release only; BenchmarkDotNet refuses to measure a debug build)
dotnet run -c Release --project PreciseNumber.Benchmarks # Pick from a list
dotnet run -c Release --project PreciseNumber.Benchmarks -- --filter '*Compar*' # One class
dotnet run -c Release --project PreciseNumber.Benchmarks -- --filter '*' --job short-
PreciseNumber (
PreciseNumber/PreciseNumber.cs): The main numeric type, areadonly partial record structimplementingINumber<PreciseNumber>. ItsdefaultisZero, whichPreciseNumberValueTypeTestspins. Stores values using:Significand: ABigIntegercontaining all significant digitsExponent: Anintdetermining the decimal placeSignificantDigits: Count of significant digits
-
Generic conversions (
PreciseNumber/PreciseNumber.Conversions.cs): TheTryConvertFrom*andTryConvertTo*members behindCreateChecked,CreateSaturating, andCreateTruncating, for every built-in numeric type andBigInteger.To<T>()uses them too -
PreciseNumberExtensions (
PreciseNumber/PreciseNumberExtensions.cs): Extension methods providingToPreciseNumber<T>()for converting anyINumber<T>to PreciseNumber
- Factory methods
CreateFromInteger<T>()andCreateFromFloatingPoint<T>()handle type-specific conversion logic - Addition, subtraction and modulus align exponents before calculating; multiplication and division work on the significands directly
Divideis exact when the quotient terminates, and otherwise rounds to a precision that never falls below the wider operand orMinimumDivisionPrecision.Expand non-integerPowstill route throughdouble- The
sanitizeconstructor parameter controls whether trailing zeros are removed (default: true) - Constants (
Zero,One,Pi,E,Tau) are pre-computed static instances - As a value type it can't be null or inherited. Don't add null checks for
PreciseNumberparameters, and don't reintroduceprotectedmembers - Conversions to integer types go through
BigInteger, so range checks, clamping, and wrapping follow its conventions. Conversions todouble,float,Half, anddecimalrendersignificand E exponentand parse it, because the runtime parsers round correctly, with Clinger's fast path for small values. NaN and infinity coming in followBigIntegertoo
Tests use MSTest. PreciseNumber.Test/PreciseNumberTests.cs covers arithmetic, parsing, and formatting, PreciseNumberConversionTests.cs covers generic math conversion in every mode, and PreciseNumberValueTypeTests.cs pins default as zero and asserts that small-value addition, subtraction, multiplication, and comparison allocate nothing. The test project targets only .NET 10.0 while the main library multi-targets net7.0, net8.0, net9.0, and net10.0.
PreciseNumber.Benchmarks is a BenchmarkDotNet suite, one class per area (construction,
comparison, arithmetic, pow, rounding, text, conversion). The library exposes its internals to it
so construction can be measured directly.
Most classes are parameterised by Digits (8, 30, 200). That axis is the point: digits live in a
BigInteger, so anything that touches them one at a time looks fine at 8 digits and collapses at
200. Read results across the Digits column, not down one value of it.
Allocation is reported alongside time and matters just as much. The number is a value type, so the
only allocations are BigInteger digit arrays, and avoiding an intermediate shows up in Allocated
before it shows up in Mean. Comparisons, and addition, subtraction, and multiplication of
significands that fit in an int, should allocate nothing at all.
Run the relevant benchmarks before and after any change to the library's internals. See
PreciseNumber.Benchmarks/README.md for details.