[major] Make SignificantNumber a value type - #88
Merged
Merged
Conversation
PreciseNumber 2.0 is a readonly record struct, and a struct can't be inherited, so SignificantNumber can no longer derive from it. It is now a readonly record struct that holds a PreciseNumber in its Value property and implements INumber<SignificantNumber> itself. The significant figure rules are unchanged. The helpers they relied on from the base type (LowestDecimalDigits, LowestSignificantDigits, and the check for operands of exactly -1, 0, or 1) are private statics here, because PreciseNumber 2.0 made them internal. The members callers used to inherit, such as Exponent, Significand, Round, ReduceSignificance, To<T>, and the ToString overloads, are declared on the struct and delegate to the held value with the same return types. default(SignificantNumber) is zero, and a test pins it. A SignificantNumber converts to a PreciseNumber implicitly, and the reverse is explicit because it opts into the significant figure rules. TryParse now yields zero instead of null on failure, and the TryConvertFrom and TryConvertTo members delegate to PreciseNumber, so CreateChecked, CreateSaturating, and CreateTruncating work in generic code, including to and from PreciseNumber. This also removes the explicit IUtf8SpanFormattable.TryFormat, which called itself and overflowed the stack. The implementation INumberBase provides takes its place. docs/migration-guide-2.0.md lists every breaking change. Claude-Session: https://claude.ai/code/session_01K5Bk9UjGdGUtC5C6qK5ZxD
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
SignificantNumber builds against ktsu.PreciseNumber 2.x again. PreciseNumber 2.0 became a
readonly record struct, and a struct can't be inherited, sorecord SignificantNumber : PreciseNumberno longer compiles against it. SignificantNumber is now areadonly record structthat holds aPreciseNumberand implementsINumber<SignificantNumber>itself. Generic math conversion (T.CreateCheckedand friends) works, anddefault(SignificantNumber)is a valid zero.This is a major version, because every consumer that relied on SignificantNumber being a class or a PreciseNumber is affected.
docs/migration-guide-2.0.mdcovers each change.Changes
Value. ASignificantNumberconverts toPreciseNumberimplicitly, and the reverse is explicit because it opts into the significant figure rules.FromPreciseNumberandToPreciseNumber()do the same as named methods.Valuewith the same return types:Exponent,Significand,SignificantDigits,Abs(),Round,ReduceSignificance,Clamp,Squared,Cubed,To<T>, theToStringoverloads,TryFormat, andCompareTo(object).NegativeOne,E,Pi, andTauare now typed asSignificantNumber, and there are staticMax,Min,Clamp, andRound.TryConvertFrom*andTryConvertTo*delegate to PreciseNumber, and handleSignificantNumberandPreciseNumberfirst because PreciseNumber doesn't recognizeSignificantNumber.LowestDecimalDigits,LowestSignificantDigits, and the check for -1, 0, or 1) are private statics, because PreciseNumber 2.0 made its versions internal.IUtf8SpanFormattable.TryFormatcalled itself. It's gone, andINumberBase's default implementation does the work.ktsu.PreciseNumberis pinned to 2.0.3, which includes the conversion and rounding fixes from PreciseNumber chore: update ktsu.Sdk to 2.21.1 [patch] #72.Breaking changes
CreateFromComponentsoverload that takessanitizeare removed.CompareTo(SignificantNumber?)is nowCompareTo(SignificantNumber).TryParseoverloads andTryConvertFrom*useout SignificantNumber, andTryParseyields zero instead of null on failure.PreciseNumberto aSignificantNumberneeds an explicit cast.ToSignificantNumber()returns a copy instead of the same instance.MakeCommonized, are no longer available.Testing
main. The 20 new ones inSignificantNumberValueTypeTestscoverdefault, both conversions withPreciseNumber,CreateChecked,CreateSaturating, andCreateTruncatingfrom generic code, a genericSum<T>, the static helpers, theTryParsefailure path,CompareTo(object), and UTF-8 formatting.IsNullon a failed parse became equality withZero,AreSamebecame a value check, the unsanitizedCreateFromComponentstest is gone with the overload, andIsNotNullonExpbecame a range check.ToSignificantNumberWithDigits_FromSignificantNumber_ReducesSignificancereduces123.456to three digits and expects123. It fails on PreciseNumber 2.0.1, which added 55… instead of 50… when rounding, and passes on 2.0.3.🤖 Generated with Claude Code
https://claude.ai/code/session_01K5Bk9UjGdGUtC5C6qK5ZxD