Skip to content

Form a complex product past the exponent range before rounding it - #2348

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
a-complex-overflow-is-not-nan
Nov 3, 2026
Merged

Rafael-SOWNet merged 2 commits into
masterfrom
a-complex-overflow-is-not-nan

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

A complex number's parts are decimals in the precision context, whose exponents end at 1e1000. A product or a whole power of finite numbers that had a part pass that end had oo - oo in it and came out NaN, which says the value does not exist. Simplify returned the same NaN. 2.6.0 does the same. A compilesweep follow-up found it; no issue was filed.

2.6.0 and master now
"(3+4i)^2000".EvalNumerical() NaN +oo + +ooi (each part the sign of the exact part)
"(1+i)^(10^6)".EvalNumerical() NaN +oo
"(1e600+1e600i)*(1e600+1e600i)".EvalNumerical() NaN +ooi
"(3+4i)^2000".Simplify() NaN (3 + 4i) ^ 2000
(3+4i)^1400, (3+4i)^(-2000) finite, 0 unchanged
  • Product. When the parts of a complex product of finite factors leave the range, the parts are formed with unbounded exponents and each is rounded into the context. The bounded result is used whenever it is finite, so a value in range takes no new path.
  • Power. A complex power that leaves the range on the way is raised the same way.
  • Division needs nothing. Smith's method only adds terms of like sign, and the near-one route ends in the product above. (1e600+1e600i)/(1e-600+1e-600i) is still NaN, because 1e-600 is below the context's exponent floor and the divisor evaluates to 0. That is a separate, known limit.
  • Simplification. Evaluate an exact power too large to build as the decimal #2347's guard against an infinity that only rounding made now covers any sum, product or power of exact finite operands (a power's base not zero). Their value is exact and finite. An operand that is already a decimal is not covered. The integrator reads a decimal sample past the range as +oo, and the first version of this guard took that away: one Rubi antiderivative came back 23,030 characters long.

Allocation. The kernel gate failed SolveHard at +5.1% on the first commit. #2347 had already moved it +2.6%, inside the 3% limit. Both halves came from reading IsFinite, a cache built on each entity's first read: #2347's guard read it on every exact value, and this branch's power check on every power built. The second commit reads finiteness from the parts instead, and computes #2347's size bound in longs. SolveHard allocates 9,549,209 B, against 9,546,434 B before #2347.

Tests: AComplexOverflowIsNotNaNTest, 12 cases. For each Gaussian power, the test checks the sign of every part against the exact Gaussian integer. 10 fail on master; the 2 controls pass on both. The full suite, AOT and the nine harnesses pass. There is a BREAKING-CHANGES entry, measured on 2.6.0.

🤖 Generated with Claude Code

A complex number's parts are decimals in the precision context, whose
exponents end at 1e1000. A product or a whole power of finite numbers, a
part of which passed that end on the way, had oo - oo in it and was NaN:
(3+4i)^2000, (1+i)^(10^6) and (1e600+1e600i)^2, and Simplify returned the
NaN as well. 2.6.0 does the same.

A complex product whose parts leave the range is formed with unbounded
exponents and each part rounded into the context, and a complex power that
does is raised the same way. Each part past the range is the infinity of
its sign, as a real past it is +oo; within the range nothing changes, since
the bounded result is used whenever it is finite. (1+i)^(10^6) is +oo and
(1e600+1e600i)^2 is +oo i.

The guard against an infinity only rounding made now covers any sum,
product or power of exact finite operands (a power's base not zero), which
is exact and finite, so an exact simplification leaves (3+4i)^2000 as
written. An operand that is already a decimal is not covered: the
integrator reads a decimal sample past the range as +oo, and taking that
away made one Rubi antiderivative 23,030 characters long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet added this to the 2.7.0 milestone Nov 3, 2026
@Rafael-SOWNet Rafael-SOWNet moved this from Todo to In review in AngouriMath Nov 3, 2026
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.22222% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 86.76%. Comparing base (fb99ffe) to head (dc07fd1).

Files with missing lines Patch % Lines
...uriMath/Functions/Evaluation/Evaluation.Classes.cs 80.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2348      +/-   ##
==========================================
- Coverage   86.77%   86.76%   -0.01%     
==========================================
  Files         312      312              
  Lines       68645    68664      +19     
  Branches    19980    19987       +7     
==========================================
+ Hits        59567    59577      +10     
- Misses       4910     4918       +8     
- Partials     4168     4169       +1     
Flag Coverage Δ
cpp 37.77% <ø> (ø)
csharp 87.30% <97.22%> (-0.01%) ⬇️
fsharp 32.97% <ø> (ø)
interactive 40.72% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...uriMath/Core/Entity/Continuous/Number/Operators.cs 90.87% <100.00%> (+0.35%) ⬆️
...uriMath/Functions/Evaluation/Evaluation.Classes.cs 84.90% <80.00%> (-0.48%) ⬇️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

IsFinite is a cache made on an entity's first read of it, and each number
an evaluation or a power produces is a new entity. Asked of every exact
value in the exact-evaluation shortcut (the guard #2347 added) and of
every power built (the check this branch added), it cost about 250 KB and
237 KB on each solve of the kernel benchmark's SolveHard, +5.1% against
the gate's baseline. The parts answer the same question without the
cache, a rational part being finite as it is.

The size bound #2347 added is computed in longs as well; it measured free
as EIntegers, but it is asked of every exact power. SolveHard allocates
9,549,209 B, against 9,546,434 B before #2347 and 10,027,870 B before
this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rafael-SOWNet
Rafael-SOWNet merged commit 0e96927 into master Nov 3, 2026
35 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in AngouriMath Nov 3, 2026
@Rafael-SOWNet
Rafael-SOWNet deleted the a-complex-overflow-is-not-nan branch November 3, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant