Parse/TryParse ignore the IFormatProvider, so a value formatted with ToString(culture) cannot be parsed back with the same culture #106
Description
What's wrong
Formatting honours the culture. TryWriteDigits (PreciseNumber/PreciseNumber.cs:~1300) writes numberFormat.NumberDecimalSeparator and numberFormat.NegativeSign from the provider.
Parse(ReadOnlySpan<char>, NumberStyles, IFormatProvider?) (PreciseNumber/PreciseNumber.cs:1114) never reads either style or provider. It hard-codes '.' as the decimal separator and '-' as the sign, and it rejects every other character. The INumberBase overloads pass NumberStyles.Any by default, but a leading +, surrounding whitespace and group separators are all rejected anyway.
The IParsable/ISpanParsable contract is that the provider supplies culture-specific formatting. Every BCL numeric type honours it, and this type's own ToString(provider) does too.
Failure scenario
var de = CultureInfo.GetCultureInfo("de-DE");
string s = PreciseNumber.Parse("1.5", CultureInfo.InvariantCulture).ToString(de); // "1,5"
PreciseNumber.Parse(s, de); // FormatException
PreciseNumber.TryParse("2,5", de, out _); // false (double.Parse("2,5", de) == 2.5)
PreciseNumber.Parse("+5", null); // FormatException despite NumberStyles.AnyThe same happens with fr-FR ("-0,25"). Any application running under a comma-decimal culture that persists or displays values with ToString(CultureInfo.CurrentCulture) and reads them back with Parse(..., CultureInfo.CurrentCulture) fails.
Suggested fix
Resolve NumberFormatInfo.GetInstance(provider) in Parse, and:
- match
NumberDecimalSeparator(which may be several characters) instead of'.' - match
NegativeSign/PositiveSigninstead of'-' - honour at least
AllowLeadingWhite/AllowTrailingWhite,AllowLeadingSign,AllowDecimalPoint,AllowExponentandAllowThousandsfromstyle
If full NumberStyles support is out of scope, at minimum use the provider's separator and sign, so that Parse(x.ToString(p), p) round-trips. Add a round-trip test for de-DE.
Activity
matt-edmondson commentedon Sep 26, 2026
Triage
PreciseNumber.Parse(ReadOnlySpan<char>, NumberStyles, IFormatProvider?)and theIParsable/ISpanParsablesurfaceNotes:
ToString(culture)output cannot be parsed back with the same culture, which breaks theIParsablecontract for every comma-decimal locale. The minimum fix is to use the provider's decimal separator and signs, so values round-trip. FullNumberStylessupport can follow later.Generated by Claude Code