Repository navigation
[fp] fp32mp2 math: native float-float implementations to 45-48 bits, exact pair rounding and remainder, C99 special values - #12641
Draft
akolesov-nvidia wants to merge 24 commits into
Conversation
exp: 41 -> 46 bits on the working range, 43/41 -> 46 on the normal and special datasets, same throughput, latency 328 -> 308 clk/ev. Results below FLT_MIN now underflow to subnormals instead of zero. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
exp2: 41 -> 46 bits. exp10: 44 -> 46 bits, +37 % throughput. log, log1p, log2, log10: 43-44 -> 45 bits near 1, 45 -> 46-48 elsewhere, 10-26 % faster. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bits on the work/normal/special/pattern datasets (L4): sin 37/41/41/25 -> 46/46/46/45, cos 38/41/41/28 -> 46/46/46/45, tan 37/41/41/25 -> 45/45/45/44, sinpi 41/41/41/23 -> 46/46/46/25, cospi 41/41/41/41 -> 46/46/46/45; throughput +8-26 %. The exp/log kernels give bit-identical results at 10-23 % more throughput. Fixes: atan2 returned 0 for operands above 2^126, atan(+-inf) returned NaN instead of +-pi/2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
asin, acos: 44 -> 46 bits. atan: 45 -> 47 bits, +17 % throughput. atan2: 45 -> 46 bits, +11 %. sqrt: fp32mp2 9.5 -> 2.8 u^2 (44 -> 46 bits), now the same on host and device. The error-bounds page is updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fp64mp2 sqrt returns to its original form (106 bits, 25 % faster than the previous commit's). fp32mp2 rsqrt: 44 -> 47 bits (13.4 -> 2.0 u^2), the same on host and device, at 2.12 instead of 4.97 ev/clk/SM on the L4. The error-bounds page is updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
No functional change: exp, expm1, sinh, cosh, tanh and the log family give identical SASS, accuracy and throughput. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pow: normal dataset 41 -> 44 bits, special 39 -> 41, work 30 -> 33, pattern 27 -> 32 (the last three limited by results below 2^-102). Throughput 0.30 -> 0.25 ev/clk/SM, accepted for the accuracy gain. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
cbrt: 45 -> 47 bits, +17 % throughput. rcbrt: 46 -> 47 bits, +58 % throughput. hypot, rhypot: native fp32mp2 implementations instead of the double fallback, 46 bits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sinh: 45-46 -> 46 bits (4.4 -> 3.6 u^2). tanh: 45 -> 46 bits (6.9 -> 3.1 u^2). atanh: 44-45 -> 46 bits (8.6 -> 3.6 u^2), throughput 0.53 -> 0.44 ev/clk/SM. Fixes: sinh and cosh returned NaN above |x| = 88.72, now +-inf; atanh returned NaN for arguments just inside +-1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…air; round fix fdim, remquo and the four integer roundings no longer go through double: exact on the limb pair (remquo over remainder's reduction, the roundings over rint / round). The predicates, copysign, frexp, modf, ilogb and logb test the float limbs instead of widening to double. Fix: round was off by one on integer-valued pairs with |lo| >= 2^23; now 0 error on the ts, 190 -> 166 clk/ev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
isfinite, isinf, isnan and signbit classify both limbs and combine the answers by logic alone, so a loose pair with an infinity or a NaN in lo, or (+inf, -inf), is reported correctly; no arithmetic involved. The function list no longer labels them as placeholders. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…mcdf, erfinv, erfcinv erfc: 40-41 -> 45 bits (136 -> 4.8 u^2). boys_f0: 43 -> 46 bits, +27 % throughput. normcdfinv: 41 -> 45 bits at the old size and throughput. erfcx, normcdf, erfinv, erfcinv: native fp32mp2 implementations instead of the device-only double fallbacks, 45-46 bits, 1.3-3x lower latency. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
normcdfinv(1 - 2^-53), (1 - 2^-40) and 2^-40 against CUDA's double normcdfinv, and +-inf at 1 and 0.
… fpmp2_accuracy::high The remainder family of the former dev/akolesov/fp32mp2_remainder_fix line, replayed as one commit on the rebase onto main (its three commits built on an older base of the math line and no longer apply one by one): - fpmp: fp32mp2 fmod exact on sparse pairs; remainder exact in high (3ee7818) - fpmp: fp32mp2 fmod exact in fpmp2_accuracy::high only (0652edc) - fpmp: fp32mp2 remquo on remainder's reduction, exact in fpmp2_accuracy::high (35e2622) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Twenty expression sites in exp, the hyperbolic functions, the special functions and asin/acos promoted a float that one limb holds exactly to a pair first (__ffloat(0.5f), __ffloat(1.0f), __ffloat(__y0), ...) or doubled a pair as x + x. They now pass the scalar to the mixed-type operators, or multiply by 2.0f. Today the operators promote the scalar themselves, so values and code are unchanged (verified: identical maximum errors on the accuracy suite); once NVIDIA/cccl PR NVIDIA#12519 lands, the same sites take its single-limb kernels (6 operations and a 2u^2 bound for the product), measured at 1.053x throughput over the fp32mp2 math set. Coefficient tables and pairs built from two limbs are unchanged. (cherry picked from commit 47c0752) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rounding functions, normcdfinv and boys_f0 After NVIDIA/cccl issue NVIDIA#12550. Wrong results for special arguments, now C99 Annex F: - log, log2, log10 returned finite numbers for x <= 0, +inf and NaN (log(-2) = 0.693, log(0) = -104.7, log(+inf) = 88.7): +-0 -> -inf, +inf -> +inf, negative or NaN -> NaN. - atan turned NaN into pi/2 in its reciprocal range: NaN propagates. - floor, ceil, trunc, round, rint returned NaN for +-inf (inf - inf in the lo-limb accumulate): the infinity itself. - normcdfinv returned +-inf outside [0, 1]: NaN; exactly 0 and 1 still give -inf and +inf. - boys_f0 returned NaN below about -94, where F0 exceeds FLT_MAX: +inf. All guards are branch-free: the core runs and a few selects pick the special value afterwards (a uniform branch to a cold path cost two to three times more in these throughput-bound kernels, its convergence barrier more than its comparisons). Measured on an RTX A6000 against the previous tip: atan, floor, ceil, trunc, round within 1%, boys_f0 -2%, rint/nearbyint -3%, log/log2 -3.5%, normcdfinv -4.5%, log10 -7%; bit counts unchanged on every cell. sqrt and rsqrt are deliberately left without special-value handling (see the docs); signed-zero results of the odd functions are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
State what the two core-header roots do for zero, infinity, negative, NaN and (on the device) subnormal arguments, and the scaling workaround, since they are deliberately kept free of the special-value handling the math functions have. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 806124c)
Adds libcudacxx/test/libcudacxx/cuda/fp/units/fpmp/math_special_values.pass.cpp, which checks the class and the sign of the result at the arguments of C99 Annex F: zero, a negative argument, the largest finite values, the infinities and NaN, for log/log2/log10, atan, the six rounding functions (fp32mp2 and fp64mp2), normcdfinv and boys_f0. sqrt and rsqrt are left out (documented behavior), and so is the sign of a zero result. The test runs on the host and in a kernel through force_include.h and fails on the code before the special-value fixes (log(0) was the first assertion to trip). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Documents, next to the sqrt/rsqrt note, that fpmp2 arithmetic and math do not track the sign of zero: renormalization adds the two limbs, so every zero result of +, -, * and fma is +0 even where IEEE 754 gives -0, while a zero from / or from a math function carries whichever sign its evaluation leaves (and fp32mp2 floor(-0) differs between host and device). Only negation, fabs, copysign and construction from a built-in -0.0 keep the sign. Measured on host and device for fp32mp2 and fp64mp2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…2548 Replaces the pow section of fpmp_math_impl_pow.h with the one from NVIDIA/cccl PR NVIDIA#12548 at 6490471 (Rasmus Munk Larsen: a triple-float ln|a| and a table-driven exp, tables with hidden visibility in host code), byte for byte, and adds its unit test math_pow.pass.cpp. The cbrt, rcbrt, hypot and norm code of this header stays as it is on this branch. Measured on an RTX A6000 with the cccl-fpdev suite, fp32mp2 pow at the default level, this implementation against the one it replaces: work 34 vs 33 bits, normal 46 vs 44, special 46 vs 41, pattern 36 vs 32 (warnings 6e-04% vs 16.85%), and 1.45x the throughput (0.45 vs 0.31 ev/clk/SM, 422 vs 672 clk/ev). cbrt, rcbrt, hypot and rhypot unchanged. When NVIDIA#12548 lands upstream, its version of the pow section is the one to keep on the next rebase of this branch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The new fp32mp2 rsqrt form of this branch read 47 bits instead of 44 but at 0.44x the throughput (2.30 vs 5.28 evaluations per clock per SM on an RTX A6000), too high a price for three bits in a core operation. __fpmp2_rsqrt goes back to the form on main; the new sqrt form (46 bits, 1.14x) stays. The special-argument behavior documented in fpmp.rst is the same for both forms (NaN for +inf, a negative argument, NaN and, on the device, a subnormal; rsqrt(0) is NaN). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…A#12530 Our Cody-Waite fast path (|x| < 2^20) folded the second- and third-order terms with error-free sums but closed with float additions whose rounding is relative to those terms, about 2^-79 in absolute value; at an argument within 2^-40 of a multiple of pi/2 that is 300 u^2 relative to the reduced argument (main's math_reduction test, sin of (0x1.b751ep+16, 0x1.a9937cp-12)). NVIDIA#12530 accumulates the corrections in fp32mp2_high, whose error is relative to the running result, and passes its test at <= 6 u^2. This takes that block as it is on main; the Payne-Hanek slow path and the sin/cos/tan kernels stay ours. Measured on an RTX A6000: bits unchanged (sin 46/45, cos 46/45, tan 45/44 on normal/pattern), sin and cos 0.49 instead of 0.54 and tan 0.45 instead of 0.48 evaluations per clock per SM. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
Two lines the pre-commit.ci clang-format check reformats: the nested conditional in __internal_fpmp2_log_special_value and an assignment alignment in normcdfinv. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This branch has not been deployed
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.
Summary
The
fp32mp2math functions are reimplemented in float-float arithmetic, with no FP64 operation on the fast paths. On the normal dataset they reach 45-47 correct bits (of 48) where the previous implementations delivered 41-45, and on the pattern dataset (powers of two, extreme exponents, special structure) the trigonometric functions go from 25-28 bits to 44-45. Functions that were double or binary128 fallbacks become native (erfcx,normcdf,erfinv,erfcinv,hypot,rhypot, 5-30x the throughput), the rounding and remainder families become exact on the whole pair, and the functions return the C99 Annex F values for infinities, NaN and arguments outside their domain.Highlights. Geomean throughput gain over the 40 changed
fp32mp2cells: 1.58x.normcdf30x,hypot13.7x,rhypot10.6x,erfcinv10x,erfcx7.5x,erfinv4.9x,frexp2.7x,rcbrt1.4x,pow1.4x,exp101.35x,sinh1.2x,atan1.16x;sin,cosandtanmatch main's throughput at 5 more bits (41 to 45-46), and the rest of the math is 0.95-1.2x at 1-3 more bits.normcdfinv(0.92x) carries its new domain checks. The exactfpmp2_accuracy::highlevel offmodandremainderis new (on main that level ran the default code), so it has no comparison.sqrtgains 2 bits and is 1.13x faster;rsqrtis unchanged.The table compares this branch with
main(778da2d, with #12519, #12530 and #12543) on an RTX A6000 (sm_86, CUDA 13.4), measured with the cccl-fpdev suite at the default accuracy level. All rows arefp32mp2at the default level. Columns: correct bits on the normal and the pattern dataset; throughput in evaluations per clock per SM (one run each on the same GPU in the same order; run-to-run noise on this setup measured at 3.6% or less); SASS instructions of the function's own code (cuobjdump --dump-sassof the bare function compiled with-O2for sm_86, out-of-line helpers included, CUDA's division and square-root slow-path subroutines excluded); ptxas registers. A dash marks a level that had no implementation of its own onmain.acosacoshasinasinhatanatan2atanhboys_f0cbrtcoscoshcospierfcerfcinverfcxerfinvexpexp10exp2expm1fmodfrexphypotloglog10log1plog2normcdfnormcdfinvpowrcbrtremainderrhypotroundsinsinhsinpisqrttantanhfmodremainderCells not listed are unchanged in bits and SASS size, with throughput within noise (8%). The pattern dataset is sign-sensitive in places where
fpmp2does not track the sign of zero (documented in this PR), which is what the low pattern bits ofatan2,sinpi,erfcand the fallback-replacing functions reflect on both sides; their normal-dataset bits are the meaningful comparison.erfinvanderfcinvcall a shared inverse-CDF kernel, which is why their SASS counts grow while the throughput rises 5-10x.The
highrows offmodandremainderare a new level rather than a replacement: onmainthehighlevel ran the default code, so the old-side cells are left empty. On dense pairs the exact path costsremainder1.98 against the default level's 2.25 evaluations per clock per SM (its wide-reduction block is present whether or not it is taken, 26 to 33 registers);fmodhigh runs at 3.10 against 2.92. What the level buys shows with sparse pairs in the dataset (one pair in 1024 with its tail 1-36 binades below the head):fmodhigh, sparse pairshighlevel ran the default code)remainderhigh, sparse pairsfmod/remainderdef, sparse pairsWhat changes, per area
expto 46 bits with gradual underflow;exp2,exp10,expm1,log,log2,log1pto 45-46 bits (log10stays at 44 on the normal dataset, 45 on the pattern dataset). Theexpkernel is split so thaterfcxand the other users scale the result themselves.sin,cos,tan,sincos,sinpi,cospito 45-46 bits;asin,acos,atan,atan2to 46-47 bits. The argument reduction keeps [fpmp] Faster fp32mp2 math functions; accurate trig near multiples of π/2 and erfc at large x #12530's fast-path accumulation infp32mp2_high, which is what holds the error at a few u² within 2^-40 of a multiple of pi/2 (math_reduction.pass.cpp); the Payne-Hanek path and the kernels are new.sinh,tanh,atanhto 46 bits andasinh,acoshto 45, with the overflow and domain fixes;coshuses the clamped0.5/ehelper from [fpmp] Faster, more accurate fpmp2 arithmetic with single-limb scalars and a shorter pair product #12519.powis the triple-float implementation of [fpmp] Accurate, C99-conforming and faster fp32mp2 pow #12548 (a triple-floatln|a|and a table-drivenexp), taken verbatim with its unit test so that the two branches do not diverge;cbrt,rcbrtto 47 bits; nativefp32mp2hypot(46 bits) andrhypot(44 bits, throughrsqrt) instead of the FP64 wrappers.erfcandnormcdfinvto 45 bits,boys_f0to 44; nativeerfcx,normcdf,erfinv,erfcinvinstead of the double and binary128 fallbacks (5-30x the throughput, at 45-46 bits where the fallbacks read 48).ceil,floor,trunc,round,rint,nearbyint,fdim,remquo,lrint,lround,llrint,llroundare exact on the pair (the previousroundmisrounded half-way pairs such as(9969168, 0.49999997));fmod,remainderandremquoare exact on sparse pairs (a tail far below the head) infpmp2_accuracy::high, and compute on the pair rounded to 53 bits in the other levels, as before; the default level is unchanged in code path, accuracy and throughput.isfinite,isinf,isnan,signbitand thefpmp_spellings look at both limbs.sqrt. A new form forfp32mp2, 46 bits at 1.13x the throughput;rsqrtis unchanged. Both take no branch for special arguments, which is now documented.log,log2,log10,atan, the six rounding functions,normcdfinvandboys_f0return the C99 Annex F values at zero, negative arguments, the infinities and NaN, through branch-free selects (cost measured at 0-7% on the affected functions). The sign of a zero result is not tracked byfpmp2, documented next to thesqrt/rsqrtnote.x * 2.0frather thanx * fp32mp2(2.0f)), so the single-limb operator overloads of [fpmp] Faster, more accurate fpmp2 arithmetic with single-limb scalars and a shorter pair product #12519 apply inside the math as well.Tests
cuda/fp/units/fpmp/math.pass.cpp:normcdfinvat the ends of (0, 1), the remainder family, more functions on both host and device.cuda/fp/units/fpmp/math_special_values.pass.cpp(new): class and sign of the result at zero, negative arguments, the largest finite values, the infinities and NaN for the functions above.cuda/fp/units/fpmp/math_pow.pass.cpp(new, from [fpmp] Accurate, C99-conforming and faster fp32mp2 pow #12548).cuda/fp/units/fpmp/math_reduction.pass.cpp(from [fpmp] Faster fp32mp2 math functions; accurate trig near multiples of π/2 and erfc at large x #12530, onmain): passes against the new kernels, worst case 5.8 u² of the 32 u² bound.Validation
With the cccl-fpdev suite against this branch: unit matrix (host, device, NVRTC, each at C++17 and C++20) all passing; the CI accuracy set (171 cells, pattern dataset, all levels) passes with 0 FAIL and 103 OK / 68 WARN cells, against 86 OK / 85 WARN on
main(the warnings are the by-design special-input classes); the special-value probe (fp32mp2, 41 functions x 19 arguments, host and device) reports no failure, only the documented warnings (sign of zero,sqrt/rsqrt, subnormal results).