This bug was discovered by Claude Opus 5.5 and reproduced on Maxima Git commit c62924c (2026-09-26) with SBCL 2.2.9. It supersedes [#4853], which reported the same bug. Related: [#4738].
Where: src/float.lisp, FLOATTOFP
When fpprec has fewer bits than the float, the mantissa is shifted with ASH, which floors: positive floats are truncated toward zero and negative ones rounded away from zero, giving up to 1 ulp error and bfloat(-x) # -bfloat(x). The fix rounds with FPROUND and takes the shift from *M; for fpprec >= 16 the result is unchanged.
src/float.lisp as described under "Fix".tests/ulp_tests.mac, at the end of the file.* \#5354 bfloat of a float at fpprec below 16 truncates instead of rounding, and differently for negative values to ChangeLog, under "Bug fixes for numbered bugs:".Fixed by commit [1a2b3c]., with the first six characters of the commit's SHA in the brackets (git rev-parse HEAD | cut -c1-6 prints them). SourceForge links this to the commit.block([fpprec:5], bfloat(0.7) + bfloat(-0.7));
Before the fix:
-1.9073b-6
Correct result:
0.0b0
In src/float.lisp (FLOATTOFP, snippet "(let ((scale (- fpprec (integer-length frac))))"), replace
;; Scale frac to the desired number of bits, and adjust the
;; exponent accordingly.
(let ((scale (- fpprec (integer-length frac))))
(list (ash (* sign frac) scale)
(+ fpprec (- exp scale)))))))
with
;; Round frac to the desired number of bits, and adjust the
;; exponent by the shift FPROUND reports in *M.
(let ((man (fpround (* sign frac))))
(list man (+ fpprec exp *m))))))
The source file indents with tabs (8 columns); the code above shows them as spaces.
Add to tests/ulp_tests.mac:
/* FLOATTOFP: at fpprec below 16, bfloat of a float rounds to nearest,
the same for both signs */
block([fpprec: 5],
[is(bfloat(-0.7) = -bfloat(0.7)), is(bfloat(0.7) = bfloat(7/10))]);
[true, true]$
bfloat(): round a float to nearest at low fpprec
When fpprec has fewer bits than the float, FLOATTOFP shifted the
mantissa with ASH, which floors: positive floats were truncated and
negative ones rounded away from zero, so bfloat(-0.7) was not
-bfloat(0.7) at fpprec 5. The mantissa is now rounded with FPROUND and
the exponent adjusted by the shift it leaves in *M; for fpprec >= 16
nothing changes.
This fixes bug #5354.
Found and fixed by Claude Opus 5.5.