Conversation
?rotg sets Z = ONE only when C = A/R underflows to zero, which needs A negligible against B; a ninth case built from powers of two reaches it exactly. ?rotmg zeroes H, D and DX1 when DD1 is negative, which no existing input triggered; a tenth case supplies one. ?rotg is now fully covered. ?rotmg keeps two gaps: the DU <= 0 branch its own comment describes as unreachable outside rounding edge cases, and the DFLAG rescaling arms, which need inputs that rescale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The complex Level 1 testers had no case for either routine, so both were entirely unexercised. ?ROTG gets a CHECK0 of its own, covering the branches its argument pair selects: B zero, A zero with B real, imaginary or general, and the ordinary path. Every expected value satisfies C*A + S*B = R and C**2 + ABS(S)**2 = 1. ?ROT is driven over unit, non-unit and negative strides with the expected vectors indexed explicitly, so the stride arithmetic in the routine is what is checked rather than restated. CHECK2 returns before its main loop for the new case: that loop's dispatch has no arm for it and would reach its STOP, which Fortran exits successfully, so the failure would show only as an 'other error' in the summary rather than a nonzero exit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tabulated cases all sit inside the window where ?ROTG uses its unscaled algorithm, so none of the scaling code ran. Five further cases place the operands below, above and astride that window. Their results are awkward to tabulate, so these check the identities that define the rotation instead: C*A + S*B = R and C**2 + ABS(S)**2 = 1. That is a stronger statement than a table of expected digits and needs no reference values. ?ROTG goes from 47% to 88% of lines. What is left is the arm taken when C = F2/SQRT(F2*H2) underflows below SAFMIN, which the guards selecting the unscaled algorithm appear to make unreachable: they bound C below by SAFMIN exactly, so C > SAFMIN always holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three more ?ROTG pairs reach the scaled F2 < H2*SAFMIN arm and both guards against SQRT(F2*H2) leaving range. ?ROT gains a negative INCY and an N = 0 call. What is left in ?ROTG is the C < SAFMIN arm, which SAFMIN*SAFMAX = 2 makes unreachable: it needs F2/H2 < SAFMIN**2, and the guards bound F2/H2 below by exactly that. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The scale check rewrites H into the DFLAG = -1 form with one arm per incoming flag, and no case had rescaled D1 holding DFLAG = 1, or D2 holding DFLAG = 0. Two cases built from powers of two do, which keeps the expected values exact enough to tabulate alongside the rest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1414 +/- ##
==========================================
+ Coverage 69.36% 69.41% +0.05%
==========================================
Files 6122 6122
Lines 486711 487029 +318
Branches 23268 23268
==========================================
+ Hits 337584 338062 +478
+ Misses 148689 148533 -156
+ Partials 438 434 -4
... and 8 files with indirect coverage changes Continue to review full report in Codecov by Harness.
|
ABS(SQ1) > ABS(SQ2) is decided on (SD*SX)*SX while SU comes from two separately rounded quotients, so one ulp inside that boundary SU can round to zero. The reference guard then zeroes H, D and X1; without it the scale check loops on Inf forever, as MKL 2025.3 and OpenBLAS 0.3.27 do on this input. The rounded quotients' exact product is at least one, so an FMA for ONE - SH12*SH21 changes nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
R comes back real, so passing it to CTEST as the size asked the imaginary part of C*A + S*B for an exact zero. Near either end of the range that part is a cancellation of two quantities of size ABS(A)+ABS(B), which is the scale the residual belongs to: CI saw 1.6E+11 against 1.3E+19, half an ulp, on every aarch64 target and on gfortran 14 and 15. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Description
CROTG,ZROTG,CSROTandZDROThad no case in the complex Level 1 testers at all, so all four were entirely unexercised.CHECK0gains a?ROTGcase covering the branches the argument pair selects (B zero, A zero with B real, imaginary or general, and the ordinary path), plus eight more whose operands sit below, above and astride the window in which?ROTGuses its unscaled algorithm, and astride the points at which each algorithm changes how it forms S. Their results are awkward to tabulate, so every case checks the identities that define the rotation,C*A + S*B = RandC**2 + ABS(S)**2 = 1. That is a stronger statement than a table of expected digits and needs no reference values.?ROTis driven over unit, non-unit and negative strides in both arguments, with the expected vectors indexed explicitly, so the stride arithmetic in the routine is what gets checked rather than restated, and once withN = 0to pin its quick return.CHECK2returns before its main loop for the new?ROTcase, whose dispatch has no arm for it and would otherwise reach aSTOPthat Fortran exits successfully.In the real testers,
?ROTGgains a ninth case with A small enough against B thatC = A/Runderflows to zero, the only way to reach theZ = ONEbranch. Both values are powers of two, so the expected results are exact.?ROTMGgains a tenth case withDD1 < 0, the input that makes it zero H, D and DX1 and returnDFLAG = -1, and two more that enter its scale check holding a flag no earlier input paired with it: one rescales D1 having setDFLAG = 1, the other rescales D2 having setDFLAG = 0, and each of those arms rewrites H into theDFLAG = -1form before scaling. Their inputs are powers of two, so the expected values stay exact enough to tabulate with the rest rather than needing an identity check. A thirteenth case reaches the guard the routine keeps for safety against rounding: one ulp inside the boundary at whichABS(SQ1) > ABS(SQ2)flips, the two separately rounded quotients behindSUmake it exactly zero, and the guard returnsD = 0,H = 0,DFLAG = -1.Coverage
gcov under gfortran 13.3.0 at
-O0, each?blat1driver linked against an otherwise uninstrumented BLAS. Single and complex shown; double and double complex are identical.SROTGCROTGCSROTSROTMGWhat is left uncovered:
C/ZROTGkeep the twoC < SAFMINarms, which needF2/H2 < SAFMIN**2. On the scaled path both operands are scaled to components of magnitude at most one, soF2/H2 >= SAFMIN/4and that arm is dead by a factor of about2**62. On the unscaled path the window guards boundF2/H2below by2*SAFMIN/SAFMAX, andSAFMIN*SAFMAXis exactly 2 in both single and double, so the bound isSAFMIN**2itself: unreachable in exact arithmetic, with a margin of about one ulp, and a sweep of the last ulps at both edges of the window did not reach it.?ROTMGis fully covered, and its guard is not dead code: without itD1/SUis infinite on the thirteenth input and the scale check loops on infinity forever. That is exactly what MKL and OpenBLAS do;xblat1sandxblat1dlinked against either pass the first ten subprograms and then hang at?ROTMG(each was run under a 60 s timeout). Checked on MKL 2025.3, 2026.0 and 2026.1, and on OpenBLAS 0.3.27 anddevelop. I'll file additional issues and link them here later.