Repository navigation
fix(libc): leave errno unchanged from ldexpf, as titles' libc.prx does - #12676
Conversation
ldexpf called the host ldexp on a float, which computes in double and sets ERANGE only when the double result leaves the double range, so ldexpf(0x1.3d1c6p-95f, 1262) set ERANGE while ldexpf(1.0f, 200) did not. The titles' ldexpf never sets errno, as their scalbnf does not. ldexpf now computes like scalbnf: on 100,000 random arguments it matches the libc.prx of PPSA07923 and PPSA05916 in every value and errno, against 63,957 errno differences before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Host-only review of head Linux breaks the new test. glibc's
The bits match in every row. Only So on Linux, Suggested change. It uses the same pattern -float APS5_VABI ldexpf_nid_postfix(float x, int exp) { return std::scalbn(x, exp); }
+float APS5_VABI ldexpf_nid_postfix(float x, int exp) {
+ int saved_errno = errno;
+ float result = std::scalbn(x, exp);
+ errno = saved_errno;
+ return result;
+}With this change, the same standalone passes all 8 rows on glibc (bits identical, |
glibc's scalbnf sets ERANGE on overflow and on underflow to zero, so on Linux the scalbn body still changed errno and CheckLdexpfErrno failed 5 of its 8 rows (reported by rooklz). ldexpf now saves and restores errno around the call, as fmod does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@rooklz thanks, you're right: on glibc Rechecked on Windows at that head: I'll take AI-assisted: yes (Claude Code). |
|
Follow-up opened as #12681: AI-assisted: yes (Claude Code). |
|
@JJenkx Thanks for the careful differential. A Linux run on this PR (the host-only review comment) shows |
|
@oneandonlydean thanks. That change is already on the PR: the current head float APS5_VABI ldexpf_nid_postfix(float x, int exp) {
const int saved_errno = errno;
const float result = std::scalbn(x, exp);
errno = saved_errno;
return result;
}So it doesn't depend on #12681's guard, and the two can land in either order. The Linux failure you describe matches the earlier head AI-assisted: yes (Claude Code). |
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Linux run at this PR's exact head Arch Linux, kernel 7.2.9, Ryzen 9 7950X, g++ (GCC) 16.2.1 20260810, glibc 2.44, x86-64. Release,
|
The titles' scalbn and scalbnf never set errno, at any exponent. On Windows the host scalbn already matches, but glibc's scalbn and scalbnf set ERANGE on overflow and on underflow to zero (found by rooklz while reviewing #12676), so on Linux they did. Both now keep errno across the host call, as scalbln and scalblnf already do. CheckScalbnErrno checks results read from the titles' libc.prx. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Checked the diff, the 8 |
What
ldexpfseterrnotoERANGEfor some overflows and underflows. Thelibc.prxthat titles ship never setserrnofromldexpf.ldexpfcalled the hoststd::ldexpon a float. That computes in double and setsERANGEonly when the double result leaves the double range. Soldexpf(0x1.3d1c6p-95f, 1262)setERANGE, whileldexpf(1.0f, 200), which overflows the float just the same, did not.The titles'
ldexpfleaveserrnoalone in both cases, as theirscalbnfdoes. On Windows,main'sscalbnf(std::scalbnon a float) already matches the titles exactly. Soldexpfnow computes withstd::scalbnand keepserrnoacross the call, asfmoddoes: glibc'sscalbnfsetsERANGEon overflow and on underflow to zero (found by rooklz). The doubleldexpalready matches the titles and is unchanged.Tested
Windows 11, WinLibs GCC 15.2.0 UCRT r7, Release,
main3a2b919816.Native comparison: a scratch loader calls the titles' functions by NID next to this build's, on 100,000 random
(x, n)pairs.xis half any bit pattern and half exponent within[-20, 60);nis a quarter anyintand three quarters within[-2200, 2200). PPSA07923 and PPSA05916 agree:mainldexpferrnodifferldexp,scalbn,scalbnfRegression:
guest_mathgainsCheckLdexpfErrno. Its 8 cases are inputs and results read from the titles'ldexpf: overflow atn = 200andn = 1262, negative overflow, underflow to zero atn = -200andn = -2000, the smallest subnormal, a rounded subnormal and a subnormal input. Each must give the titles' bits and leaveerrnounchanged. Withmain'sMath.cpp,guest_mathfails.Test set:
guest_math,guest_math_exact,guest_dinkumware_internalsandpublic_headerspass 3/3. Conventions pass.tools/pr_overlap.py: 51 open PRs share a file. Two conflict at theldexpfline, both mine: fix(libc): compute log10 with fdlibm's algorithm, as titles' libc.prx does #10247 (log10) and fix(libc): compute log2 with fdlibm's algorithm, as titles' libc.prx does #10317 (log2). They add code next to it without changingldexpf, so whichever lands second needs only a trivial rebase. Six more already conflict withmainand couldn't be compared (feat(libc): export _FDsign/_Dsign like MSVC CRT (PPSA34015) #6085, feat(libc): implement the nextafter and nexttoward families #6295, feat(libc): implement fesetenv #8937, fix(libc): compute asin and acos with FreeBSD msun's algorithm, as titles' libc.prx does #10253, fix(libc): set EDOM in fmod and fmodf where titles' libc.prx does #10345, fix(libc): set ERANGE for decimal subnormals in wcstod as strtod does #11892); none of their diffs touchesldexpf.Linux and macOS: not built or run by me. rooklz ran the 8
CheckLdexpfErrnorows standalone. glibc 2.39 failed 5 of them with the plainstd::scalbnbody (errno = 34), andmainfailed the same 5. With theerrnosave and restore, all 8 pass on glibc and on macOS. On Linux,main'sscalbnfandscalbnalso setERANGEwhere the titles don't; that's a separate gap for a follow-up.Exception flags: a separate sweep of 100,000 random pairs compared the raised exception flags.
ldexpf(with this PR),scalbnandscalbnfmatch the titles on every pair.Noticed, not changed here: double
ldexpdiffers in flags on 1,172 pairs, with the same values anderrno. In each case shown the result is an inexact subnormal (for exampleldexp(1.5, -1074)): the titles raise no flags, while this build raises underflow and inexact. For an underflow all the way to zero, both raise underflow and inexact.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code