Skip to content

Fix #11131, #10509: std.conv.to: check float to integer range after truncation - #11132

Open
Sarthak-Shreshtha01 wants to merge 1 commit into
dlang:masterfrom
Sarthak-Shreshtha01:fix/conv-float-truncate
Open

Sarthak-Shreshtha01 wants to merge 1 commit into
dlang:masterfrom
Sarthak-Shreshtha01:fix/conv-float-truncate

Conversation

@Sarthak-Shreshtha01

@Sarthak-Shreshtha01 Sarthak-Shreshtha01 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Rationale

to checked a floating value against T.min and T.max before the fraction was dropped, so to!uint(-0.5), to!ubyte(255.5) and to!int(-2147483648.5) threw although the documented truncating conversion gives 0, 255 and int.min.

The upper check also compared in the floating type, where long.max rounds up to 2^63. So to!long(9223372036854775296.0) (which is 2^63 as a double) returned long.min instead of throwing, which is #10509.

For floating to integral conversions, a value now fits when it is in (T.min - 1, T.max + 1). T.max + 1 is a power of two, so it is exact in every floating type. Infinities and out-of-range values still throw ConvOverflowException, and NaN still throws ConvException.

New unittests cover float, double and real at the edges of byte, ubyte, uint, int and long. Both new unittests fail without the change. One existing test accepted a wrong result for to!int(float(int.max)) (that float is 2^31); it now expects the overflow exception when the floating type cannot hold Integral.max. make std/conv.test passes (148 unittests), as do std/json, std/math/rounding and std/datetime/systime.

Feature request or issue tracking

Closes #11131.
Closes #10509.

Pre-review checklist

  • I have performed a self-review of my code.
  • If my PR fixes a bug or introduces a new feature, I have added thorough tests.
  • If my changes are non-trivial and do not concern a reported issue, I have added a changelog entry.

LLM/AI disclosure

This PR was written entirely by an LLM/AI.

…ge after truncation

to!T(value) checked the floating value against T.min and T.max before the
fraction was dropped, so to!uint(-0.5) and to!ubyte(255.5) threw although
the truncated value fits. The check against T.max also compared in the
floating type, where long.max rounds up to 2^63, so 2^63.to!long returned
long.min instead of throwing.

A floating value now fits when it is in (T.min - 1, T.max + 1).

Signed-off-by: Sarthak <sarthakshreshtha345@gmail.com>
Copilot AI balanced review requested due to automatic review settings October 19, 2026 22:34

This comment was marked as low quality.

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

Projects

None yet

3 participants