Menu ▾ ▴

#5581 with keepfloat:true, ratsimp(1.0*%i/(1.0+1.0*%i)^2) returns 1.0 instead of 0.5

closed
nobody
5
2026-09-29
2026-09-28
No

This bug was discovered by Claude Opus 5.5 and reproduced on Maxima Git commit 0d1e40c (2026-09-27) with SBCL 2.2.9. It supersedes [#2197], which reported one of its symptoms.

Where: src/rat3e.lisp, CDISREP

CDISREP turns a rational form back into an expression. When the denominator is a float, it returns the numerator alone, as if that float were always 1.0, and for a float numerator over an integer denominator it builds ((rat) 1.0 2), which is not a valid rational number. With keepfloat: true, ratsimp(1.0*%i/(1.0+1.0*%i)^2) reduces to the rational form with numerator 1.0 and denominator 2.0 and returns 1.0, and ratsimp(1.0*%i/(1+%i)^2) reduces to 1.0 over 2, whose simplification signals a Lisp error. rectform is affected through ABSARG1, which calls SRATSIMP with keepfloat bound to true: rectform(((1.0*%i)/(1.0*%i+1.0)^2)^(1/4)) returns 1.0 instead of 2^(-1/4) = 0.8409. [#2197], where expand of the rational form -8.0/5 signals a Lisp error, is the same bug. The fix divides by a float denominator and returns a float for a float numerator.

Steps

  1. Verify that the existing behavior is incorrect: run the reproducer below; it gives the result under "Before the fix". Judge for yourself that this is wrong instead of relying on the ticket: where the bug allows it, try some related inputs of your own, or check the result another way, for example numerically or against the documentation.
  2. Edit the file src/rat3e.lisp as described under "Fix".
  3. Rebuild Maxima.
  4. Verify that the behavior is now correct: the reproducer gives the result under "Correct result". Judge for yourself that this is right, not only that it matches: where the bug allows it, try some related inputs of your own, including some that the fix should leave unchanged.
  5. Add the test case(s) under "Test cases" to tests/rtest9.mac, at the end of the file.
  6. Run the complete test suite, share tests included (make check, or run_testsuite(share_tests=true); in ./maxima-local), and check that the change breaks no test. Failures that also occur without the change (a run on the unchanged build shows which) are pre-existing and can be ignored.
  7. Add the line * \#5581 with keepfloat:true, ratsimp(1.0*%i/(1.0+1.0*%i)^2) returns 1.0 instead of 0.5 to ChangeLog, under "Bug fixes for numbered bugs:".
  8. Commit the fix; a proposed Git commit message is under "Commit message".
  9. Push the commit. Then set this ticket's status to "closed" and add a comment naming the commit, for example 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.

Reproducer

keepfloat: true$ ratsimp(1.0*%i/(1.0+1.0*%i)^2); ratsimp(1.0*%i/(1+%i)^2); rectform(((1.0*%i)/(1.0*%i+1.0)^2)^(1/4));

Before the fix:

1.0
Maxima encountered a Lisp error:
 The value 1.0 is not of type INTEGER
1.0

Correct result:

0.5, 0.5, 0.8408964152537145

Fix

In src/rat3e.lisp (CDISREP, "((or (equal 1 (cdr x)) (floatp (cdr x)))"), replace

        ((or (equal 1 (cdr x)) (floatp (cdr x))) (pdisrep (car x)))

with

        ((or (equal 1 (cdr x)) (and (floatp (cdr x)) (= (cdr x) 1)))
         (pdisrep (car x)))
        ((floatp (cdr x)) (pdisrep (pctimes (/ (cdr x)) (car x))))

In src/rat3e.lisp (CDISREP, "(list '(rat) (* sign n) d))"), replace

           (cond ((and (numberp n) (numberp d))
                  (list '(rat) (* sign n) d))

with

           (cond ((and (numberp n) (numberp d))
                  (if (floatp n)
                      (/ (* sign n) d)
                      (list '(rat) (* sign n) d)))

The source file indents with tabs (8 columns); the code above shows them as spaces.

Test cases

Add these lines to tests/rtest9.mac, separated from the tests before them by two empty lines:

/* Bug #5581: "with keepfloat:true, ratsimp(1.0*%i/(1.0+1.0*%i)^2) returns 1.0 instead of 0.5" */

block ([keepfloat : true],
  [ratsimp (1.0*%i/(1.0 + 1.0*%i)^2), ratsimp (%i/(1.0 + %i)^2),
   ratsimp (1.0*%i/(1 + %i)^2)]);
[0.5, 0.5, 0.5]$

rectform (((1.0*%i)/(1.0*%i + 1.0)^2)^(1/4));
0.8408964152537145$

block ([keepfloat : true], expand (rat (1.2)*rat (1/2) - 11/5, 0, 0));
-1.6$

Commit message

rat3e.lisp: fix CDISREP for float numbers

CDISREP returned the numerator alone when the denominator was a float,
as if it were 1.0, and built the invalid number ((rat) 1.0 2) for a
float numerator over an integer. With keepfloat: true,
ratsimp(1.0*%i/(1.0+1.0*%i)^2) returned 1.0 instead of 0.5, and
ratsimp(1.0*%i/(1+%i)^2) signalled a Lisp error. rectform(), which
simplifies with keepfloat bound to true, returned 1.0 for
((1.0*%i)/(1.0*%i+1.0)^2)^(1/4). CDISREP now divides by a float
denominator and returns a float for a float numerator.

This fixes bugs #5581 and #2197.

Found and fixed by Claude Opus 5.5.

Related

Bugs: #2197

Discussion

  • David Scherfgen

    David Scherfgen - 2026-09-29
    • Description has changed:

    Diff:

    
    
    • status: open --> closed
    • Priority: --> 5
     
  • David Scherfgen

    David Scherfgen - 2026-09-29

    Fixed by commit [56b6dc].

     

    Related

    Commit: [56b6dc]


Log in to post a comment.