Skip to content

[minor] Add a PreciseNumber storage-type alias package - #232

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/magical-knuth-idzj5r
Sep 14, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/magical-knuth-idzj5r

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Summary

Semantics.Quantities.Precise joins Double, Float and Decimal as a props-only satellite, binding every quantity to ktsu.PreciseNumber.PreciseNumber so a consumer writes Mass rather than Mass<PreciseNumber>.

It is the first alias package whose storage type comes from a package rather than being a C# keyword, and that is the only real difference. The generator script learns to write a fully qualified name into the alias, and the project carries a PackageReference on ktsu.PreciseNumber so the name resolves for a consumer. Semantics.Quantities itself still has no PreciseNumber dependency — the support is opt-in through this package alone, as decided when #226 landed.

What it buys

A unit factor is applied at the precision the value carries rather than at the 15–17 significant digits a double holds:

Length.FromFoot(PreciseNumber.One).In(Units.Inch)   // exactly 12
1.0 * 0.3048 / 0.0254                               // 12.000000000000002 in double

Velocity3D.One.Length()   // 1.73205080756887729352744634150587236694280525381038

Both of those are outputs from a real consumer project built against the generated props, not illustrations.

One deviation from the plan, on purpose

PreciseNumber is deliberately not added to precision.json.

That file feeds PrecisionGenerator, which emits typeof(<storage type>) into a StorageTypes class in the core ktsu.Semantics.Quantities assembly. An entry there would force the core to reference ktsu.PreciseNumber and undo the separation this package exists to keep — and StorageTypes has no reader anywhere in the repository, so the entry would buy nothing in exchange.

Worth revisiting only if StorageTypes acquires a purpose, and then as a decision about where it should live. Happy to add it if you'd rather have it and accept the core dependency.

Testing

PreciseNumberStorageConversionTests runs the shared conversion suite over PreciseNumber with exact assertions — one derived line, as the base class intends.

Its tolerance for non-terminating answers is 1e-35 rather than something tighter, and the reason is worth recording: the limit is the expected literals, not the storage type. The knot is a repeating fraction written to 38 decimal places, and PreciseNumber answers it with 50 correct digits, so the residual being measured is the truncation of the reference value. 1e-40 failed for exactly that reason. 1e-35 is still ten orders of magnitude tighter than decimal's, so a factor arriving through a double — wrong from about the sixteenth digit — fails it by an enormous margin.

Verified in this session:

  • All 1248 tests pass (1240 succeeded, 8 skipped Windows-only; up from 1237 as the new class adds 11).
  • The full solution builds with 0 warnings, 0 errors.
  • The verify-generated steps reproduced locally: rebuilding the generated sources and regenerating the alias props leaves no diff. Generated/ is untouched, confirming the core is unaffected.
  • The package packs correctly: buildTransitive props, no lib/ assemblies, no empty .snupkg (the nuget.org HTTP 400 the sibling csproj warns about), and dependencies on both ktsu.Semantics.Quantities and ktsu.PreciseNumber 2.0.2 for each of net8.0, net9.0 and net10.0.
  • A consumer project built against the props confirmed the aliases resolve and produced the two values above.

Docs

New package README mirroring the siblings, plus the package table in the root README, the project-layout and regeneration notes in CLAUDE.md, and the "reference exactly one of" list in all three existing alias READMEs.

🤖 Generated with Claude Code

https://claude.ai/code/session_017jrnV7N94UGL8fDRRE8Xt8


Generated by Claude Code

Semantics.Quantities.Precise joins Double, Float and Decimal as a props-only
satellite, binding every quantity to ktsu.PreciseNumber.PreciseNumber so a
consumer writes Mass rather than Mass<PreciseNumber>.

It is the first alias package whose storage type comes from a package rather
than being a C# keyword, which is the only real difference. The generator script
learns to write a fully qualified name into the alias, and the project carries a
PackageReference on ktsu.PreciseNumber so the name resolves for a consumer.
Semantics.Quantities itself still has no PreciseNumber dependency: the support is
opt-in through this package alone.

What it buys is exactness. A unit factor is applied at the precision the value
carries rather than at the fifteen to seventeen significant digits a double
holds, so Length.FromFoot(1).In(Units.Inch) is exactly 12 where double gives
12.000000000000002, and Velocity3D.One.Length() is the square root of three to
fifty digits rather than to a double's worth.

PreciseNumber is deliberately not added to precision.json. That file feeds
PrecisionGenerator, which emits typeof(<storage type>) into StorageTypes in the
core ktsu.Semantics.Quantities assembly, so an entry there would force the core
to reference ktsu.PreciseNumber and undo the separation this package exists to
keep. StorageTypes has no reader anywhere in the repository, so the entry would
buy nothing in exchange. Worth revisiting only if StorageTypes acquires a
purpose, and then as a decision about where it should live.

Testing: PreciseNumberStorageConversionTests runs the shared conversion suite
over PreciseNumber with exact assertions, one derived line as the base class
intends. Its tolerance for non-terminating answers is 1e-35 rather than
something tighter because the limit is the expected literals, not the storage
type: the knot is a repeating fraction written to 38 decimal places and
PreciseNumber answers it with 50 correct digits, so the residual measured is the
truncation of the reference value. That is still ten orders of magnitude tighter
than decimal's, so a factor arriving through a double fails it by a wide margin.

All 1248 tests pass, the solution builds with no warnings, and rebuilding the
generated sources and regenerating the alias props leaves no diff. The package
was packed and checked: buildTransitive props, no lib assemblies, no empty
symbols package, and dependencies on both ktsu.Semantics.Quantities and
ktsu.PreciseNumber for each of net8.0, net9.0 and net10.0. A consumer project
built against the props confirmed the aliases resolve and the two values above.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jrnV7N94UGL8fDRRE8Xt8
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants