Expand description
Port of base.py’s float/Decimal path: float2tuple and
to_cardinal_float.
§Why the f64 arrives as an f64
The float branch of float2tuple is binary arithmetic:
post = abs(value - pre) * 10**precision
if abs(round(post) - post) < 0.01:
post = int(round(post))
else:
post = int(math.floor(post))Those artefacts are load-bearing. 2.675 really does produce
674.9999999999998, and the < 0.01 heuristic is what rescues it back to
675. Re-deriving that from a decimal string would compute the right
answer and therefore the wrong one. Python floats and Rust f64 are both
IEEE-754 doubles, so passing the raw double across reproduces it exactly.
precision still comes from Python: it is abs(Decimal(str(value)) .as_tuple().exponent), which depends on repr(float) — shortest
round-trip formatting that we deliberately do not reimplement.
§The one true rounding trap
Python’s round() is round-half-to-even (round(2.5) == 2), while
Rust’s f64::round() is half-away-from-zero (2.5_f64.round() == 3.0).
Every rounding here uses round_ties_even().
Enums§
- Float
Value - The value handed to the float path, mirroring what Python’s dispatcher saw.
Functions§
- cardinal_
from_ bigdecimal - Render a
BigDecimalthrough the float path — the fractional-cents entry point.rightis e.g. 65.3 cents, so its own scale is the precision. - default_
to_ cardinal_ float - Python’s
Num2Word_Base.to_cardinal_float. - float2tuple
- Python’s
Num2Word_Base.float2tuple. Returns(pre, post). - point_
routed_ float_ entry - “Condition C” float routing —
"." in str(value)decides. Most self-contained converters route on the value’s string form: visible decimals take the language’s float grammar even when the value is whole (5.0 -> “pět čárka nula”), plain ints don’t (Decimal(“5”) -> “pět”). Languages with this shape point theircardinal_float_entryhere.