unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "Mattias Engdegård" <mattiase@acm.org>
To: Dave Gillespie <Daveg@synaptics.com>
Cc: Jelle Licht <jlicht@fsfe.org>, Stefan Kangas <stefan@marxist.se>,
	"47302@debbugs.gnu.org" <47302@debbugs.gnu.org>
Subject: bug#47302: 27.1; calc math-format-number formatting for floats without decimals is unusual
Date: Sun, 25 Apr 2021 17:53:30 +0200	[thread overview]
Message-ID: <0E7C5A4F-105A-4E1E-A103-BFB9C263F2BA@acm.org> (raw)
In-Reply-To: <BYAPR03MB359209709A97DBB74B10C1C3BC469@BYAPR03MB3592.namprd03.prod.outlook.com>

[-- Attachment #1: Type: text/plain, Size: 1685 bytes --]

22 apr. 2021 kl. 18.35 skrev Dave Gillespie <Daveg@synaptics.com>:

> Wow, it has been a long time since I got any correspondence on Calc!

Good to hear from you, Dave! I just fix the occasional Calc bug now and then.

> Calc has a C language mode ('d C' keystroke, controlled by calc-language).  It is a good point that C mode (and probably others like it) should format integer-valued floats as "123.0" even if the default mode does not.  If we apply Jelle's patch, I suggest making it conditional on calc-language so that it applies only in modes such as C mode.  Or perhaps rework it as a text transformation using calc-language-filter.
> 
> You could even create a JSON language mode, but most likely the basic C mode is close enough to serve that purpose.

These are all good suggestions. Most languages permit trailing decimal points; the only common exceptions that I can think of are Haskell, Ada and Swift. Apparently JSON is also one. Tying the float-format display to the C, Pascal (etc) modes seems a bit incongruous as it has nothing to do with the syntax of those languages.

How to display a floating-point number with zero fraction also depends on what the user wants to do with the result, so there is a good argument for letting him or her do the required post-processing. Sometimes '1.' should become '1.0', sometimes '1'. For instance, in a LaTeX document it would depend on how the author wants to represent significant digits. A JSON parser (such as the one in Emacs) will parse '1.0' and '1' differently, as a float or integer respectively.

I wrote the patch below as a possible solution but in the light of the above, perhaps it's not ideal?


[-- Attachment #2: calc-digit-after-point.diff --]
[-- Type: application/octet-stream, Size: 3710 bytes --]

diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index ec09abb34c..1e7d5e7766 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -483,6 +483,11 @@ calc-display-sci-low
   "Floating-point numbers with this negative exponent or lower are displayed
 scientific notation in calc-mode.")
 
+(defvar calc-digit-after-point nil
+  "If t, display at least one digit after the decimal point, as in `12.0'.
+If nil, the decimal point may come last in a number, as in `12.'.
+This setting only applies to floats in normal display mode.")
+
 (defvar calc-other-modes nil
   "List of used-defined strings to append to Calculator mode line.")
 
@@ -3184,7 +3189,8 @@ math-format-number
 		      exp (- exp adj)))))
 	  (setq str (int-to-string mant))
 	  (let* ((len (length str))
-		 (dpos (+ exp len)))
+		 (dpos (+ exp len))
+                 (trailing-0 (and calc-digit-after-point "0")))
 	    (if (and (eq fmt 'float)
 		     (<= dpos (+ calc-internal-prec calc-display-sci-high))
 		     (>= dpos (+ calc-display-sci-low 2)))
@@ -3194,9 +3200,11 @@ math-format-number
 		    (setq str (concat "0" point str)))
 		   ((and (<= exp 0) (> dpos 0))
 		    (setq str (concat (substring str 0 dpos) point
-				      (substring str dpos))))
+				      (substring str dpos)
+                                      (and (>= dpos len) trailing-0))))
 		   ((> exp 0)
-		    (setq str (concat str (make-string exp ?0) point)))
+		    (setq str (concat str (make-string exp ?0)
+                                      point trailing-0)))
 		   (t   ; (< dpos 0)
 		    (setq str (concat "0" point
 				      (make-string (- dpos) ?0) str))))
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index c5aa5a31eb..06010dd417 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -191,6 +191,33 @@ calc-format-radix
     (let ((calc-number-radix 36))
       (should (equal (math-format-number 12345678901) "36#5,O6A,QT1")))))
 
+(ert-deftest calc-display-digit-after-point ()
+  "Test display of trailing 0 after decimal point (bug#47302)."
+  (let ((calc-display-digit-after-point nil))
+    ;; Integral floats have no digits after the decimal point (default).
+    (should (equal (math-format-number '(float 0 0)) "0."))
+    (should (equal (math-format-number '(float 5 0)) "5."))
+    (should (equal (math-format-number '(float 3 1)) "30."))
+    (should (equal (math-format-number '(float 23 0)) "23."))
+    (should (equal (math-format-number '(float 123 0)) "123."))
+    (should (equal (math-format-number '(float 1 -1)) "0.1"))
+    (should (equal (math-format-number '(float 54 -1)) "5.4"))
+    (should (equal (math-format-number '(float 1 -4)) "1e-4"))
+    (should (equal (math-format-number '(float 1 14)) "1e14"))
+    (should (equal (math-format-number 12) "12")))
+  (let ((calc-display-digit-after-point t))
+    ;; Integral floats have at least one digit after the decimal point.
+    (should (equal (math-format-number '(float 0 0)) "0.0"))
+    (should (equal (math-format-number '(float 5 0)) "5.0"))
+    (should (equal (math-format-number '(float 3 1)) "30.0"))
+    (should (equal (math-format-number '(float 23 0)) "23.0"))
+    (should (equal (math-format-number '(float 123 0)) "123.0"))
+    (should (equal (math-format-number '(float 1 -1)) "0.1"))
+    (should (equal (math-format-number '(float 54 -1)) "5.4"))
+    (should (equal (math-format-number '(float 1 -4)) "1e-4"))
+    (should (equal (math-format-number '(float 1 14)) "1e14"))
+    (should (equal (math-format-number 12) "12"))))
+
 (ert-deftest calc-calendar ()
   "Test calendar conversions (bug#36822)."
   (should (equal (calcFunc-julian (math-parse-date "2019-07-27")) 2458692))

  reply	other threads:[~2021-04-25 15:53 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-21 21:54 bug#47302: 27.1; calc math-format-number formatting for floats without decimals is unusual Jelle Licht
2021-04-21 15:16 ` Stefan Kangas
2021-04-22 13:44   ` Mattias Engdegård
2021-04-22 15:03     ` Jelle Licht
2021-04-22 16:35       ` Dave Gillespie
2021-04-25 15:53         ` Mattias Engdegård [this message]
2021-04-26 14:58           ` Dave Gillespie
2021-04-27 16:15             ` Mattias Engdegård

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0E7C5A4F-105A-4E1E-A103-BFB9C263F2BA@acm.org \
    --to=mattiase@acm.org \
    --cc=47302@debbugs.gnu.org \
    --cc=Daveg@synaptics.com \
    --cc=jlicht@fsfe.org \
    --cc=stefan@marxist.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).