Subject: 31.0.50; Calc can't integrate 0

From: Michael Heerdegen <[email-masked]>
Date: Tue, 02 Jul 2024 02:47:56 +0200

Hello,

Any Calc experts around?  emacs -Q:

  M-x calc RET
  0 RET
  a i x RET

is a way to integrate 0 using Calc (with integration variable x in this
case).  Calc fails to solve it:

The result Calc gives you is "integ(0, x)" - Calc leaves the integral
unresolved, which is Calc's way to say "I can't solve this".  This
is definitely not a feature or a way to represent an integration
constant - (info "(calc) Integration"):

| Also, any indefinite integral should be considered to have an
| arbitrary constant of integration added to it, although Calc does not
| write an explicit constant of integration in its result.

So what is going on?  Other functions, including constants like 1 or a
symbol work as expected.

As far as I understand, Calc is internally perfectly able to solve this
integral but at one place in the code the correct result is rejected
because this case is so special that the authors forgot to make the code
expect a result of such a simple form.  This small change helps:

From a4351149314af2dab8f03715a9effeb2ee26490c Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <[email-masked]>
Date: Fri, 23 Jun 2023 04:44:34 +0200
Subject: [PATCH] WIP: Try to fix integration of 0

---
 lisp/calc/calcalg2.el | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/lisp/calc/calcalg2.el b/lisp/calc/calcalg2.el
index 5e9ae8a3e5a..fafbd8418ef 100644
--- a/lisp/calc/calcalg2.el
+++ b/lisp/calc/calcalg2.el
@@ -774,12 +774,13 @@ math-integral
     (setq val math-cur-record)
     (while (vectorp (nth 1 val))
       (setq val (aref (nth 1 val) 0)))
-    (setq val (if (memq (nth 1 val) '(parts parts2))
-		  (progn
-		    (setcar (cdr val) 'parts2)
-		    (list 'var 'PARTS val))
-		(and (consp (nth 1 val))
-		     (nth 1 val))))
+    (let ((val-1 (nth 1 val)))
+      (setq val (if (memq val-1 '(parts parts2))
+		    (progn
+		      (setcar (cdr val) 'parts2)
+		      (list 'var 'PARTS val))
+		  (and (or (consp val-1) (equal val '(0 0)))
+		       val-1))))
     (math-tracing-integral "Integral of "
 			   (math-format-value expr 1000)
 			   "  is  "
--
2.39.2

The problem is: I found this fix by trial and error, someone who knows
the code should verify that the fix is correct.  For example, I don't
know whether 0 is always represented as list (0 0) at this point (given
how many different settings there are...) and whether it is the correct
code place to handle this case.

TIA,

Michael.

In GNU Emacs 31.0.50 (build 15, x86_64-pc-linux-gnu, cairo version
 1.16.0) of 2024-07-02 built on drachen
Repository revision: 7b256c6118326a76e81cc004576c78ba5a475ffd
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12101007
System Description: Debian GNU/Linux 12 (bookworm)

Configured using:
 'configure --with-x-toolkit=no --with-native-compilation=no'

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LCMS2
LIBSELINUX LIBSYSTEMD LIBXML2 MODULES NOTIFY INOTIFY OLDXMENU PDUMPER
PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF WEBP X11 XDBE XIM XINPUT2
XPM ZLIB

Important settings:
  value of $LC_ALL: de_DE.utf8
  value of $LC_COLLATE: C
  value of $LC_TIME: C
  value of $LANG: de_DE.utf8
  locale-coding-system: utf-8-unix