Implement INumber, IFloatingPoint, and the modulus operator for the IEEE 754 decimal types#130890
Merged
tannergooding merged 14 commits intoJul 17, 2026
Conversation
E, Pi, and Tau already exist as public constants; this just declares the interface on Decimal32/64/128. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
NegativeOne already exists as a public constant; this just declares the interface on Decimal32/64/128. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Implements the truncated remainder (x - Truncate(x / y) * y) matching the C# floating-point % operator on double/float/Half, not the round-to-nearest IEEE 754 remainder. The result carries the dividend's sign and is computed exactly at the preferred exponent min(exp(x), exp(y)) by reducing the dividend coefficient modulo the divisor coefficient with word-level integer arithmetic. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
All INumber members (Clamp/Max/Min/Sign/CopySign and friends) already exist as public static members; the modulus operator and relational comparison operators satisfy the remaining IModulusOperators/IComparisonOperators requirements, so this declares the interface on Decimal32/64/128. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Collapses the IFloatingPointConstants/INumber/INumberBase/ISignedNumber declarations into IFloatingPoint<TSelf> on Decimal32/64/128 and adds the member set: Ceiling/Floor/Truncate/Round, ConvertToInteger(Native), and the IFloatingPoint exponent/significand writers. Exponent is exposed as int (its UnbiasedExponent type) so NaN/Inf exponent fields don't overflow a narrower type; the significand is the full unpacked coefficient. Round shares Number.RoundDecimalIeee754. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Covers Round (all midpoint modes, curated NaN/Inf/signed-zero/tie edge cases plus oracle-derived random vectors), operator %, the Ceiling/Floor/Truncate/ Round convenience overloads, and the exponent/significand writers + ConvertToInteger. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…tel reference vectors Wires bidNN_fmod and bidNN_round_integral_* from the Intel readtest.in vectors into the existing DecimalIeee754IntelTestData harness. The round vectors surfaced two canonicalization gaps in RoundDecimalIeee754 (non-canonical finite and infinity operands were returned verbatim), now fixed in the implementation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @dotnet/area-system-numerics |
tannergooding
marked this pull request as ready for review
July 16, 2026 17:25
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR expands the IEEE 754 decimal floating-point types (System.Numerics.Decimal32, Decimal64, Decimal128) with additional generic-math surface (notably IFloatingPoint-related members) and implements the % (truncating remainder / fmod) operator, with accompanying runtime and reference-vector-based tests.
Changes:
- Add
%operator support by introducingNumber.RemainderDecimalIeee754and wiring it intoDecimal32/64/128. - Implement
IFloatingPoint<TSelf>members (rounding helpers,ConvertToInteger*, and exponent/significand byte-writing APIs) forDecimal32/64/128using newNumber.RoundDecimalIeee754. - Extend tests and Intel reference-vector enumerators to cover modulus and integral rounding behavior, plus the new exponent/significand bit APIs.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.cs | Adds shared helpers for truncated remainder (%) and rounding to fractional digits used by decimal IEEE types. |
| src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal32.cs | Adds % operator and IFloatingPoint<Decimal32> implementations (Round/Ceiling/Floor/Truncate + exponent/significand write APIs). |
| src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal64.cs | Adds % operator and IFloatingPoint<Decimal64> implementations (Round/Ceiling/Floor/Truncate + exponent/significand write APIs). |
| src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal128.cs | Adds % operator and IFloatingPoint<Decimal128> implementations (Round/Ceiling/Floor/Truncate + exponent/significand write APIs). |
| src/libraries/System.Runtime/ref/System.Runtime.cs | Updates public ref surface for Decimal32/64/128 to include the new interfaces and members (including % and rounding APIs). |
| src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DecimalIeee754IntelTestData.cs | Adds Intel readtest.in operation families for fmod and integral-rounding vectors. |
| src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal32Tests.cs | Adds modulus, round-to-digits, convenience overload, and exponent/significand write API tests (plus Intel vector theories). |
| src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal64Tests.cs | Adds modulus, round-to-digits, convenience overload, and exponent/significand write API tests (plus Intel vector theories). |
| src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Decimal128Tests.cs | Adds modulus, round-to-digits, convenience overload, and exponent/significand write API tests (plus Intel vector theories). |
Copilot's findings
- Files reviewed: 9/9 changed files
- Comments generated: 2
The reduction loop scaled the running remainder one decimal digit at a time, so a large exponent gap spun far more iterations than necessary and kept going after the remainder reached zero. Fold as many trailing zeros per step as the running product can hold without overflowing the integer width (up to the largest cached power of ten) and stop once the remainder is zero. A small divisor now reaches the full cached power; output is bit-exact-unchanged against the Intel reference vectors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
src/libraries/System.Runtime/ref/System.Runtime.cs:11436
- This PR adds new public API surface (e.g.,
Decimal32/64/128now implement additional generic-math interfaces and expose new members like%/Round/Ceiling/Floor/Truncate/bit APIs). Issue #81376 is labeledapi-approved, but I couldn’t locate the “approved API shape” comment (code-fenced C# snippet) required by the API-approval procedure. Please link the specific approval comment (or add it) so reviewers can verify the ref changes match the approved shape.
- Files reviewed: 9/9 changed files
- Comments generated: 4
…est files Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…4 decimal types Covers GetExponentShortestBitLength (both exponent-sign branches), GetSignificandBitLength, and the big-endian significand and exponent writers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Ceiling/Floor/Round/Truncate propagated a NaN operand's bits unchanged, so a signaling or out-of-range-payload NaN escaped as a non-canonical result. Route it through PropagateNaN, matching the binary operators. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Member
|
LGTM after null propagation is fixed |
Replace the manual divide and multiply-subtract with TValue.DivRem, matching the remainder computation used elsewhere in the file. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…amily IEEE 754-2019 5.1 requires general-computational operations to produce canonical results, so a returned NaN operand must be re-canonicalized. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
tannergooding
enabled auto-merge (squash)
July 16, 2026 20:55
Member
Author
|
@PranavSenthilnathan should all be handled. Still needs explicit sign-off |
PranavSenthilnathan
approved these changes
Jul 16, 2026
Open
3 tasks
Member
Author
|
/ba-g the known net481 build break and an unrelated timeout |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Continues the incremental buildout of the IEEE 754 decimal types (part of #81376). #130807 added the conversion surface and
INumberBase<TSelf>; this one adds the next set of interfaces and the modulus operator.Adds to
Decimal32,Decimal64, andDecimal128:IFloatingPointConstants<TSelf>--E,Pi, andTau, correctly rounded to each format's precision.ISignedNumber<TSelf>--NegativeOne.INumber<TSelf>--Max/Min/MaxNumber/MinNumber/Clamp/Sign/CopySignand friends, mirroringSystem.Half's semantics (IEEE 2019minimum/maximumcohort/signed-zero/NaN handling).IFloatingPoint<TSelf>--Round(all overloads), theGetExponentByteCount/GetSignificandByteCount/TryWrite*bit APIs, and the remaining classification members.%,IModulusOperators<TSelf, TSelf, TSelf>).The
%operator follows the same truncated-remainder (fmod) semantics asfloat/double/Half--x - Truncate(x / y) * y-- which is distinct fromIEEE754Remainder(round-to-nearest quotient); the latter arrives withIFloatingPointIeee754.Non-trivial members are ported from the Intel BID reference and validated bit-exact against its reference vectors (modulus and round), plus the existing Python-oracle-generated coverage. The multi-argument
Round(value, digits, mode)overloads are the one bespoke piece -- Intel has no direct baseline for them, so they are built on the faithful single-argument rounding primitive.IFloatingPointIeee754<TSelf>/IDecimalFloatingPointIeee754<TSelf>(and the transcendental sub-interfaces) are deferred to a follow-up that stacks on this.Note
This PR description was drafted by GitHub Copilot.