Skip to content

Volume.FromMilliliter(1) is 1 litre (1e-3 m³), 1000× too large: Milli prefix is applied to m³ instead of the litre #286

Description

@matt-edmondson

What's wrong

In Semantics.SourceGenerators/Metadata/units.json (around line 199), Milliliter is defined only as "magnitude": "Milli", with no conversion factor:

{ "name": "Milliliter", "symbol": "mL", "system": "SIDerived", "magnitude": "Milli" }

UnitsGenerator.BuildToBaseFactorExpression applies the magnitude to the dimension's SI base unit. For Volume that base unit is m³, not the litre, so the generated ToBaseFactor is MetricMagnitudes.Milli = 1e-3 m³. That is one litre. The correct factor is 1e-6 m³.

The same pattern gives correct results elsewhere only because those units are prefixed forms of the base unit itself. For example, Gram = Milli × kg = 1e-3 kg is correct, and Millimeter = Milli × m is correct. The litre is not the base unit of Volume, so the prefix alone is wrong here.

Failure scenario

  • Volume<double>.FromMilliliter(1.0).Value returns 0.001 (m³). It should return 1e-6.
  • Everything that goes through the unit's factor is off by 1000×: Capacity.FromMilliliter, IUnit.ToBaseFactor, ToBaseFactorAs<T>(), and every In(new Milliliter()).

For example, 5 mL of a dose or reagent comes out as 5 L. No test references Milliliter, so nothing catches this.

Suggested fix

Give the unit both parts:

"magnitude": "Milli",
"conversionFactor": "LiterToCubicMeters"

BuildToBaseFactorExpression already handles magnitude × factor, which produces 1e-3 × 1e-3 = 1e-6. Then regenerate.

Acceptance criteria

  • Volume<double>.FromMilliliter(1000).In(new Liter()) equals 1 (within tolerance).
  • Volume<double>.FromMilliliter(1).Value equals 1e-6 m³.
  • Check the other units in units.json that carry a magnitude in dimensions whose base unit is not the unprefixed form of that unit. Any new ones found get the same treatment and a test.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    readyFully specified; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions