You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SignificantNumber stores its value as a normalized PreciseNumber, which moves trailing zeros into the exponent (README "Trailing zero removal", README.md:283-290). SignificantDigits is then read straight from that value (SignificantNumber/SignificantNumber.cs:98). Multiplication, division, Pow/Exp and comparison all take the result's precision from LowestSignificantDigits (line ~185, used at ~240, ~253, ~385, ~625, ~677).
Trailing zeros are significant in a measurement, so the type loses precision the user actually has. 1.20 is treated as 2 significant figures, and 10.0, 2.0 and 4.00 as 1. The type has no way to represent a value such as 2.50 or 10.0 with its real precision.
The collapse spreads: once one operand ends in 0, every later * and / in the chain drops the digits the user supplied. The migration guide's own example, ToMeters(10.ToSignificantNumber()), returns 3 rather than the 3.048 its comment implies, for the same reason.
For a library whose purpose is significant-figure arithmetic, this is the most common way real measured inputs are written.
Suggested fix
Track precision separately from the normalized value:
Add a field for significant digits, or for the least-significant decimal place, next to Value. Parse and string input set it from the literal ("1.20" → 3 s.f.); numeric conversions set it from the source's natural digits, or from an explicit overload.
Have ToString pad with the significant trailing zeros (10.0, 2.50).
This changes the struct's equality and layout, so it is likely v3 material. A smaller first step is an opt-in Parse/constructor overload that keeps precision from the literal.
Acceptance criteria
SignificantNumber.Parse("1.20").SignificantDigits == 3, and Parse("10.0") reports 3.
What's wrong
SignificantNumberstores its value as a normalizedPreciseNumber, which moves trailing zeros into the exponent (README "Trailing zero removal",README.md:283-290).SignificantDigitsis then read straight from that value (SignificantNumber/SignificantNumber.cs:98). Multiplication, division,Pow/Expand comparison all take the result's precision fromLowestSignificantDigits(line ~185, used at ~240, ~253, ~385, ~625, ~677).Trailing zeros are significant in a measurement, so the type loses precision the user actually has.
1.20is treated as 2 significant figures, and10.0,2.0and4.00as 1. The type has no way to represent a value such as2.50or10.0with its real precision.Failure scenarios
Observed on HEAD with ktsu.PreciseNumber 2.6.4:
The collapse spreads: once one operand ends in 0, every later
*and/in the chain drops the digits the user supplied. The migration guide's own example,ToMeters(10.ToSignificantNumber()), returns3rather than the3.048its comment implies, for the same reason.For a library whose purpose is significant-figure arithmetic, this is the most common way real measured inputs are written.
Suggested fix
Track precision separately from the normalized value:
Value.Parseand string input set it from the literal ("1.20"→ 3 s.f.); numeric conversions set it from the source's natural digits, or from an explicit overload.Value.SignificantDigits. The decimal-place rule for+,-and%(Add/Subtract never round to tens or hundreds: 1.2E3 + 34 = 1234 instead of 1.2E3 #107) would use the same field.ToStringpad with the significant trailing zeros (10.0,2.50).This changes the struct's equality and layout, so it is likely v3 material. A smaller first step is an opt-in
Parse/constructor overload that keeps precision from the literal.Acceptance criteria
SignificantNumber.Parse("1.20").SignificantDigits == 3, andParse("10.0")reports 3.Parse("1.20") * Parse("1.23456")equals1.48, andParse("9.81") * Parse("10.0")equals98.1.Parse("2.50").ToString()gives2.50.Related, not duplicates: #107 (decimal-place rule for addition), #1 (closed, integer exponent).