Subject: Re: bug#15859: 24.3.50; Calc - dimensionless units again

From: Roland Winkler <[email-masked]>
Date: Sun, 16 Apr 2023 23:47:23 -0500

On Fri, Apr 14 2023, Michael Heerdegen wrote:
> At least the result given by Calc is not incorrect.  It would be better
> if it would respect the units explicitly requested by the user, though.

The command `calc-convert-units' from the old calc tar ball (from before
calc became part of GNU Emacs) had been doing for me exactly what I
expected for the longest time.  The trouble only started for me when the
old code got modified.  Therefore, some time ago I grabbed the old code
of `calc-convert-units' and put it into my emacs init file.  (In the
code attached below I merely added a let-binding for the internal
variable UNITS.)  This code has been working fine for me since then with
recent versions of GNU Emacs and the likewise more recent versions of
calc they ship with.  (I use this command on a regular basis.)

I suggest to revert the changes of the command `calc-convert-units' and
go back to its old definition.

(defun calc-convert-units (&optional old-units new-units)
  (interactive)
  (calc-slow-wrapper
   (let ((expr (calc-top-n 1))
	 uoldname unew units)
     (or (math-units-in-expr-p expr t)
	 (let ((uold (or old-units
			 (progn
			   (setq uoldname (read-string "Old units: "))
			   (if (equal uoldname "")
			       (progn
				 (setq uoldname "1")
				 1)
			     (if (string-match "\\` */" uoldname)
				 (setq uoldname (concat "1" uoldname)))
			     (math-read-expr uoldname))))))
	   (if (eq (car-safe uold) 'error)
	       (error "Bad format in units expression: %s" (nth 1 uold)))
	   (setq expr (math-mul expr uold))))
     (or new-units
	 (setq new-units (read-string (if uoldname
					  (concat "Old units: "
						  uoldname
						  ", new units: ")
					"New units: "))))
     (if (string-match "\\` */" new-units)
	 (setq new-units (concat "1" new-units)))
     (setq units (math-read-expr new-units))
     (if (eq (car-safe units) 'error)
	 (error "Bad format in units expression: %s" (nth 2 units)))
     (let ((unew (math-units-in-expr-p units t))
	   (std (and (eq (car-safe units) 'var)
		     (assq (nth 1 units) math-standard-units-systems))))
       (if std
	   (calc-enter-result 1 "cvun" (math-simplify-units
					(math-to-standard-units expr
								(nth 1 std))))
	 (or unew
	     (error "No units specified"))
	 (calc-enter-result 1 "cvun"
			    (math-convert-units
			     expr units
			     (and uoldname (not (equal uoldname "1"))))))))))