emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Bug in org-table--set-calc-mode?
@ 2020-10-19 15:38 Daniele Nicolodi
  2020-10-20 13:30 ` [PATCH] org-table: Add mode flag to enable Calc units simplification mode Daniele Nicolodi
  0 siblings, 1 reply; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-19 15:38 UTC (permalink / raw)
  To: Org Mode List

Hello,

I am hacking org-table-eval-formula (see thread about monetary values in
org-tables) which uses this inline function:

(defsubst org-table--set-calc-mode (var &optional value)
  (if (stringp var)
      (setq var (assoc var '(("D" calc-angle-mode deg)
			     ("R" calc-angle-mode rad)
			     ("F" calc-prefer-frac t)
			     ("S" calc-symbolic-mode t)))
	    value (nth 2 var) var (nth 1 var)))
  (if (memq var org-tbl-calc-modes)
      (setcar (cdr (memq var org-tbl-calc-modes)) value)
    (cons var (cons value org-tbl-calc-modes)))
  org-tbl-calc-modes)

which I am not able to understand or which is not correct.

The first (if ...) does some value substitutions, however, IIUC the
second (if ...) sets a new value for an entry in the org-tbl-calc-modes
plist if the entry is already present and builds a new plist with the
entry prepended if the entry is not there. However, the original plist
is returned and not the one with the new entry prepended.

It does not seem to be the intended behavior.

Shouldn't this be simply:

(defsubst org-table--set-calc-mode (var &optional value)
  (if (stringp var)
      (setq var (assoc var '(("D" calc-angle-mode deg)
			     ("R" calc-angle-mode rad)
			     ("F" calc-prefer-frac t)
			     ("S" calc-symbolic-mode t)))
	    value (nth 2 var) var (nth 1 var)))
  (plist-put org-tbl-calc-modes var value))

or, better, the code refactored to do not use this function?

Cheers,
Dan


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-19 15:38 Bug in org-table--set-calc-mode? Daniele Nicolodi
@ 2020-10-20 13:30 ` Daniele Nicolodi
  2020-10-20 13:44   ` Eric S Fraga
  2020-10-21 15:57   ` Daniele Nicolodi
  0 siblings, 2 replies; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-20 13:30 UTC (permalink / raw)
  To: emacs-orgmode

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

Hello,

attached there are a few patches reworking the code, fixing the bug, and
introducing a new mode flag to enable Calc's units simplification mode
as discussed in a recent thread on the mailing list.  I haven't updated
the documentation.  I can do it once we agree that this feature is a
good idea.

Cheers,
Dan


On 19/10/2020 17:38, Daniele Nicolodi wrote:
> Hello,
> 
> I am hacking org-table-eval-formula (see thread about monetary values in
> org-tables) which uses this inline function:
> 
> (defsubst org-table--set-calc-mode (var &optional value)
>   (if (stringp var)
>       (setq var (assoc var '(("D" calc-angle-mode deg)
> 			     ("R" calc-angle-mode rad)
> 			     ("F" calc-prefer-frac t)
> 			     ("S" calc-symbolic-mode t)))
> 	    value (nth 2 var) var (nth 1 var)))
>   (if (memq var org-tbl-calc-modes)
>       (setcar (cdr (memq var org-tbl-calc-modes)) value)
>     (cons var (cons value org-tbl-calc-modes)))
>   org-tbl-calc-modes)
> 
> which I am not able to understand or which is not correct.
> 
> The first (if ...) does some value substitutions, however, IIUC the
> second (if ...) sets a new value for an entry in the org-tbl-calc-modes
> plist if the entry is already present and builds a new plist with the
> entry prepended if the entry is not there. However, the original plist
> is returned and not the one with the new entry prepended.
> 
> It does not seem to be the intended behavior.
> 
> Shouldn't this be simply:
> 
> (defsubst org-table--set-calc-mode (var &optional value)
>   (if (stringp var)
>       (setq var (assoc var '(("D" calc-angle-mode deg)
> 			     ("R" calc-angle-mode rad)
> 			     ("F" calc-prefer-frac t)
> 			     ("S" calc-symbolic-mode t)))
> 	    value (nth 2 var) var (nth 1 var)))
>   (plist-put org-tbl-calc-modes var value))
> 
> or, better, the code refactored to do not use this function?
> 
> Cheers,
> Dan
> 


[-- Attachment #2: 0001-org-table-Fix-table-formula-mode-string-handling.patch --]
[-- Type: text/plain, Size: 2160 bytes --]

From c7434974897d932fe3acd182f06a98a61719e208 Mon Sep 17 00:00:00 2001
From: Daniele Nicolodi <daniele@grinta.net>
Date: Tue, 20 Oct 2020 11:03:14 +0200
Subject: [PATCH 1/3] org-table: Fix table formula mode string handling

* lisp/org-table.el (org-table-eval-formula): Move mode lookup table
from org-table--set-calc-mode to here.

* lisp/org-table.el (org-table--set-calc-mode): Use plist-put instead
of the buggy open coded version.
---
 lisp/org-table.el | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 112b1e171..0790dc3ca 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -721,17 +721,8 @@ Field is restored even in case of abnormal exit."
 	 (org-table-goto-column ,column)
 	 (set-marker ,line nil)))))
 
-(defsubst org-table--set-calc-mode (var &optional value)
-  (if (stringp var)
-      (setq var (assoc var '(("D" calc-angle-mode deg)
-			     ("R" calc-angle-mode rad)
-			     ("F" calc-prefer-frac t)
-			     ("S" calc-symbolic-mode t)))
-	    value (nth 2 var) var (nth 1 var)))
-  (if (memq var org-tbl-calc-modes)
-      (setcar (cdr (memq var org-tbl-calc-modes)) value)
-    (cons var (cons value org-tbl-calc-modes)))
-  org-tbl-calc-modes)
+(defsubst org-table--set-calc-mode (var value)
+  (plist-put org-tbl-calc-modes var value))
 
 \f
 ;;; Predicates
@@ -2476,9 +2467,14 @@ location of point."
 		(setq keep-empty t
 		      fmt (replace-match "" t t fmt)))
 	    (while (string-match "[DRFS]" fmt)
-	      (setq org-tbl-calc-modes
-		    (org-table--set-calc-mode (match-string 0 fmt)))
-	      (setq fmt (replace-match "" t t fmt)))
+	      (let* ((c (string-to-char (match-string 0 fmt)))
+		     (mode (cdr (assoc c '((?D calc-angle-mode deg)
+					   (?R calc-angle-mode rad)
+					   (?F calc-prefer-frac t)
+					   (?S calc-symbolic-mode t))))))
+		(setq org-tbl-calc-modes (org-table--set-calc-mode
+					  (car mode) (cadr mode))
+		      fmt (replace-match "" t t fmt))))
 	    (unless (string-match "\\S-" fmt)
 	      (setq fmt nil))))
       (when (and (not suppress-const) org-table-formula-use-constants)
-- 
2.28.0


[-- Attachment #3: 0003-org-table-Add-mode-flag-to-enable-Calc-units-simplif.patch --]
[-- Type: text/plain, Size: 1301 bytes --]

From aad8eb548e7a7a7fde1908a9f9c66f980da10b56 Mon Sep 17 00:00:00 2001
From: Daniele Nicolodi <daniele@grinta.net>
Date: Tue, 20 Oct 2020 15:22:02 +0200
Subject: [PATCH 3/3] org-table: Add mode flag to enable Calc units
 simplification mode

* org-table.el (org-table-eval-formula): Add the `u` mode flag to
enable Calc's units simplification mode.
---
 lisp/org-table.el | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 4baad2600..6b92656bd 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -2447,11 +2447,12 @@ location of point."
 		  (?e (org-table--set-calc-mode 'calc-float-format (list 'eng n)))))
 	      ;; Remove matched flags from the mode string.
 	      (setq fmt (replace-match "" t t fmt)))
-	    (while (string-match "\\([tTUNLEDRFS]\\)" fmt)
+	    (while (string-match "\\([tuTUNLEDRFS]\\)" fmt)
 	      (let ((c (string-to-char (match-string 1 fmt))))
 		(cl-case c
 		  (?t (setq duration t numbers t
 		      	    duration-output-format org-table-duration-custom-format))
+		  (?u (org-table--set-calc-mode 'calc-simplify-mode 'units))
 		  (?T (setq duration t numbers t duration-output-format nil))
 		  (?U (setq duration t numbers t duration-output-format 'hh:mm))
 		  (?N (setq numbers t))
-- 
2.28.0


[-- Attachment #4: 0002-org-table-Simplify-mode-string-parsing.patch --]
[-- Type: text/plain, Size: 5850 bytes --]

From fb8b62e5faabca2b6c6514e25bd306f7a5e8696f Mon Sep 17 00:00:00 2001
From: Daniele Nicolodi <daniele@grinta.net>
Date: Tue, 20 Oct 2020 15:13:40 +0200
Subject: [PATCH 2/3] org-table: Simplify mode string parsing

* org-table.el (org-table-eval-formula): Simplify mode string parsing
and reduce scope of local variables.
---
 lisp/org-table.el | 98 +++++++++++++++++++++--------------------------
 1 file changed, 43 insertions(+), 55 deletions(-)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 0790dc3ca..4baad2600 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -722,7 +722,7 @@ Field is restored even in case of abnormal exit."
 	 (set-marker ,line nil)))))
 
 (defsubst org-table--set-calc-mode (var value)
-  (plist-put org-tbl-calc-modes var value))
+  (setq org-tbl-calc-modes (plist-put org-tbl-calc-modes var value)))
 
 \f
 ;;; Predicates
@@ -2427,54 +2427,42 @@ location of point."
 	   (org-tbl-calc-modes (copy-sequence org-calc-default-modes))
 	   (numbers nil)	   ; was a variable, now fixed default
 	   (keep-empty nil)
-	   n form form0 formrpl formrg bw fmt x ev orig c lispp literal
+	   form form0 formrpl formrg bw fmt ev orig lispp literal
 	   duration duration-output-format)
       ;; Parse the format string.  Since we have a lot of modes, this is
       ;; a lot of work.  However, I think calc still uses most of the time.
-      (if (string-match ";" formula)
-	  (let ((tmp (org-split-string formula ";")))
-	    (setq formula (car tmp)
-		  fmt (concat (cdr (assoc "%" org-table-local-parameters))
-			      (nth 1 tmp)))
+      (if (string-match "\\(.*\\);\\(.*\\)" formula)
+	  (progn
+	    (setq fmt (concat (match-string-no-properties 2 formula)
+			      (cdr (assoc "%" org-table-local-parameters)))
+		  formula (match-string-no-properties 1 formula))
 	    (while (string-match "\\([pnfse]\\)\\(-?[0-9]+\\)" fmt)
-	      (setq c (string-to-char (match-string 1 fmt))
-		    n (string-to-number (match-string 2 fmt)))
-	      (if (= c ?p)
-		  (setq org-tbl-calc-modes
-			(org-table--set-calc-mode 'calc-internal-prec n))
-		(setq org-tbl-calc-modes
-		      (org-table--set-calc-mode
-		       'calc-float-format
-		       (list (cdr (assoc c '((?n . float) (?f . fix)
-					     (?s . sci) (?e . eng))))
-			     n))))
+	      (let ((c (string-to-char (match-string 1 fmt)))
+		    (n (string-to-number (match-string 2 fmt))))
+		(cl-case c
+		  (?p (org-table--set-calc-mode 'calc-internal-prec n))
+		  (?n (org-table--set-calc-mode 'calc-float-format (list 'float n)))
+		  (?f (org-table--set-calc-mode 'calc-float-format (list 'fix n)))
+		  (?s (org-table--set-calc-mode 'calc-float-format (list 'sci n)))
+		  (?e (org-table--set-calc-mode 'calc-float-format (list 'eng n)))))
+	      ;; Remove matched flags from the mode string.
+	      (setq fmt (replace-match "" t t fmt)))
+	    (while (string-match "\\([tTUNLEDRFS]\\)" fmt)
+	      (let ((c (string-to-char (match-string 1 fmt))))
+		(cl-case c
+		  (?t (setq duration t numbers t
+		      	    duration-output-format org-table-duration-custom-format))
+		  (?T (setq duration t numbers t duration-output-format nil))
+		  (?U (setq duration t numbers t duration-output-format 'hh:mm))
+		  (?N (setq numbers t))
+		  (?L (setq literal t))
+		  (?E (setq keep-empty t))
+		  (?D (org-table--set-calc-mode 'calc-angle-mode 'deg))
+		  (?R (org-table--set-calc-mode 'calc-angle-mode 'rad))
+		  (?F (org-table--set-calc-mode 'calc-prefer-frac t))
+		  (?S (org-table--set-calc-mode 'calc-symbolic-mode t))))
+	      ;; Remove matched flags from the mode string.
 	      (setq fmt (replace-match "" t t fmt)))
-	    (if (string-match "[tTU]" fmt)
-		(let ((ff (match-string 0 fmt)))
-		  (setq duration t numbers t
-			duration-output-format
-			(cond ((equal ff "T") nil)
-			      ((equal ff "t") org-table-duration-custom-format)
-			      ((equal ff "U") 'hh:mm))
-			fmt (replace-match "" t t fmt))))
-	    (if (string-match "N" fmt)
-		(setq numbers t
-		      fmt (replace-match "" t t fmt)))
-	    (if (string-match "L" fmt)
-		(setq literal t
-		      fmt (replace-match "" t t fmt)))
-	    (if (string-match "E" fmt)
-		(setq keep-empty t
-		      fmt (replace-match "" t t fmt)))
-	    (while (string-match "[DRFS]" fmt)
-	      (let* ((c (string-to-char (match-string 0 fmt)))
-		     (mode (cdr (assoc c '((?D calc-angle-mode deg)
-					   (?R calc-angle-mode rad)
-					   (?F calc-prefer-frac t)
-					   (?S calc-symbolic-mode t))))))
-		(setq org-tbl-calc-modes (org-table--set-calc-mode
-					  (car mode) (cadr mode))
-		      fmt (replace-match "" t t fmt))))
 	    (unless (string-match "\\S-" fmt)
 	      (setq fmt nil))))
       (when (and (not suppress-const) org-table-formula-use-constants)
@@ -2575,17 +2563,17 @@ location of point."
 	(setq form0 form)
 	;; Insert the references to fields in same row
 	(while (string-match "\\$\\(\\([-+]\\)?[0-9]+\\)" form)
-	  (setq n (+ (string-to-number (match-string 1 form))
-		     (if (match-end 2) n0 0))
-		x (nth (1- (if (= n 0) n0 (max n 1))) fields)
-		formrpl (save-match-data
-			  (org-table-make-reference
-			   x keep-empty numbers lispp)))
-	  (when (or (not x)
-		    (save-match-data
-		      (string-match (regexp-quote formula) formrpl)))
-	    (user-error "Invalid field specifier \"%s\""
-			(match-string 0 form)))
+	  (let* ((n (+ (string-to-number (match-string 1 form))
+		       (if (match-end 2) n0 0)))
+		 (x (nth (1- (if (= n 0) n0 (max n 1))) fields)))
+	    (setq formrpl (save-match-data
+			    (org-table-make-reference
+			     x keep-empty numbers lispp)))
+	    (when (or (not x)
+		      (save-match-data
+			(string-match (regexp-quote formula) formrpl)))
+	      (user-error "Invalid field specifier \"%s\""
+			  (match-string 0 form))))
 	  (setq form (replace-match formrpl t t form)))
 
 	(if lispp
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 13:30 ` [PATCH] org-table: Add mode flag to enable Calc units simplification mode Daniele Nicolodi
@ 2020-10-20 13:44   ` Eric S Fraga
  2020-10-20 14:00     ` Daniele Nicolodi
  2020-10-20 14:19     ` Eric S Fraga
  2020-10-21 15:57   ` Daniele Nicolodi
  1 sibling, 2 replies; 11+ messages in thread
From: Eric S Fraga @ 2020-10-20 13:44 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: emacs-orgmode

Just to say that I have done a quick test with this and I really like
it.  Simple calculations with units of mol/s and mol/min work perfectly.

-- 
: Eric S Fraga via Emacs 28.0.50, Org release_9.4-61-ga88806.dirty


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 13:44   ` Eric S Fraga
@ 2020-10-20 14:00     ` Daniele Nicolodi
  2020-10-20 14:22       ` Eric S Fraga
  2020-10-20 14:19     ` Eric S Fraga
  1 sibling, 1 reply; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-20 14:00 UTC (permalink / raw)
  To: emacs-orgmode

On 20/10/2020 15:44, Eric S Fraga wrote:
> Just to say that I have done a quick test with this and I really like
> it.  Simple calculations with units of mol/s and mol/min work perfectly.

Thank you for testing Eric.

To cover the use case of monetary quantities discussed in the other
thread I would like to also add an `m?` (or M?) flag that can combine
the effect of the existing `f?` flag and the new `u` flag. But I don't
know if sparing one character is worth one character in the small flag
characters set.

Cheers,
Dan


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 13:44   ` Eric S Fraga
  2020-10-20 14:00     ` Daniele Nicolodi
@ 2020-10-20 14:19     ` Eric S Fraga
  2020-10-20 14:32       ` Daniele Nicolodi
  1 sibling, 1 reply; 11+ messages in thread
From: Eric S Fraga @ 2020-10-20 14:19 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: emacs-orgmode

Hello again,

Following up on myself.  I'm seeing some strange behaviour although unit
calculations are working nicely.  For instance, this table:

#+begin_src org
  | stream   | a            | b            | c            | total        |   x_a |   x_b |   x_c |
  |          | <l>          | <l>          | <l>          | <l>          |   <r> |   <r> |   <r> |
  |----------+--------------+--------------+--------------+--------------+-------+-------+-------|
  | feed     | 1.05 mol/s   | 1.05 mol/s   |              | 2.10 mol / s | 0.500 | 0.500 |     0 |
  | effluent | 0.74 mol / s | 0.74 mol / s | 0.32 mol / s | 1.80 mol / s | 0.411 | 0.411 | 0.178 |
  ,#+TBLFM: $5=vsum($2..$4);uf2::$6=$2/$5;uf3::$7=$3/$5;uf3::$8=$4/$5;uf3::@4$2=(1-0.3)*@-1;uf2::@4$3=(1-0.3)*@-1;uf2::@4$4=@-1+0.3*@-1$-1;uf2
#+end_src

does not seem to pay attention to the f3 mode in the last column, first
data row.

I've also seen some (difficult to replicate) problem with column widths
where the columns are much wider than the expected.  I'll keep playing
to see if I can isolate the column width behaviour.

-- 
: Eric S Fraga via Emacs 28.0.50, Org release_9.4-61-ga88806.dirty


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 14:00     ` Daniele Nicolodi
@ 2020-10-20 14:22       ` Eric S Fraga
  0 siblings, 0 replies; 11+ messages in thread
From: Eric S Fraga @ 2020-10-20 14:22 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: emacs-orgmode

On Tuesday, 20 Oct 2020 at 16:00, Daniele Nicolodi wrote:
> To cover the use case of monetary quantities discussed in the other
> thread I would like to also add an `m?` (or M?) flag that can combine
> the effect of the existing `f?` flag and the new `u` flag. But I don't
> know if sparing one character is worth one character in the small flag
> characters set.

Well, I personally am perfectly fine with uf3 instead of m3 (say) as the
former has a clear intent.

But, as you'll have seen by my followup message, there is something
strange going on with u and f combined.  But I'm still playing.
-- 
: Eric S Fraga via Emacs 28.0.50, Org release_9.4-61-ga88806.dirty


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 14:19     ` Eric S Fraga
@ 2020-10-20 14:32       ` Daniele Nicolodi
  2020-10-20 14:53         ` Daniele Nicolodi
  2020-10-20 15:35         ` Eric S Fraga
  0 siblings, 2 replies; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-20 14:32 UTC (permalink / raw)
  To: emacs-orgmode

On 20/10/2020 16:19, Eric S Fraga wrote:
> Hello again,
> 
> Following up on myself.  I'm seeing some strange behaviour although unit
> calculations are working nicely.  For instance, this table:
> 
> #+begin_src org
>   | stream   | a            | b            | c            | total        |   x_a |   x_b |   x_c |
>   |          | <l>          | <l>          | <l>          | <l>          |   <r> |   <r> |   <r> |
>   |----------+--------------+--------------+--------------+--------------+-------+-------+-------|
>   | feed     | 1.05 mol/s   | 1.05 mol/s   |              | 2.10 mol / s | 0.500 | 0.500 |     0 |
>   | effluent | 0.74 mol / s | 0.74 mol / s | 0.32 mol / s | 1.80 mol / s | 0.411 | 0.411 | 0.178 |
>   ,#+TBLFM: $5=vsum($2..$4);uf2::$6=$2/$5;uf3::$7=$3/$5;uf3::$8=$4/$5;uf3::@4$2=(1-0.3)*@-1;uf2::@4$3=(1-0.3)*@-1;uf2::@4$4=@-1+0.3*@-1$-1;uf2
> #+end_src
> 
> does not seem to pay attention to the f3 mode in the last column, first
> data row.

It is something related to how Calc computes the result. The f2 mode
specifies the formatting for floating point values, however it seems
that Calc treats the zero (from the missing value in the fourth column)
divided by a float (from the value in the fifth column) as an integer
and not as a float. This may be because the org substitutes a "0" for
the missing value, thus an integer. Still, I am not sure dividing an
integer by a float should result in an integer (I guess zero is special
cased here).

If you change the formula for that field to:

  #+TBLFM: $8=$4*1.0/$5;uf3

to force the $4 field to be evaluated as a float (there are other ways
to get the same effect) you get the expected result (I think).

> I've also seen some (difficult to replicate) problem with column widths
> where the columns are much wider than the expected.  I'll keep playing
> to see if I can isolate the column width behaviour.

I haven't touched any code dealing with columns width (I believe).

Cheers,
Dan


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 14:32       ` Daniele Nicolodi
@ 2020-10-20 14:53         ` Daniele Nicolodi
  2020-10-20 15:35           ` Eric S Fraga
  2020-10-20 15:35         ` Eric S Fraga
  1 sibling, 1 reply; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-20 14:53 UTC (permalink / raw)
  To: emacs-orgmode

On 20/10/2020 16:32, Daniele Nicolodi wrote:
> On 20/10/2020 16:19, Eric S Fraga wrote:
>> Hello again,
>>
>> Following up on myself.  I'm seeing some strange behaviour although unit
>> calculations are working nicely.  For instance, this table:
>>
>> #+begin_src org
>>   | stream   | a            | b            | c            | total        |   x_a |   x_b |   x_c |
>>   |          | <l>          | <l>          | <l>          | <l>          |   <r> |   <r> |   <r> |
>>   |----------+--------------+--------------+--------------+--------------+-------+-------+-------|
>>   | feed     | 1.05 mol/s   | 1.05 mol/s   |              | 2.10 mol / s | 0.500 | 0.500 |     0 |
>>   | effluent | 0.74 mol / s | 0.74 mol / s | 0.32 mol / s | 1.80 mol / s | 0.411 | 0.411 | 0.178 |
>>   ,#+TBLFM: $5=vsum($2..$4);uf2::$6=$2/$5;uf3::$7=$3/$5;uf3::$8=$4/$5;uf3::@4$2=(1-0.3)*@-1;uf2::@4$3=(1-0.3)*@-1;uf2::@4$4=@-1+0.3*@-1$-1;uf2
>> #+end_src
>>
>> does not seem to pay attention to the f3 mode in the last column, first
>> data row.
> 
> It is something related to how Calc computes the result. The f2 mode
> specifies the formatting for floating point values, however it seems
> that Calc treats the zero (from the missing value in the fourth column)
> divided by a float (from the value in the fifth column) as an integer
> and not as a float. This may be because the org substitutes a "0" for
> the missing value, thus an integer. Still, I am not sure dividing an
> integer by a float should result in an integer (I guess zero is special
> cased here).
> 
> If you change the formula for that field to:
> 
>   #+TBLFM: $8=$4*1.0/$5;uf3
> 
> to force the $4 field to be evaluated as a float (there are other ways
> to get the same effect) you get the expected result (I think).

There are other funny Calc behaviors: if an expression results in a
number with an unit where the numerical part is exactly 1, the printed
result looses the numerical part and only the units are printed.

Cheers,
Dan


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 14:32       ` Daniele Nicolodi
  2020-10-20 14:53         ` Daniele Nicolodi
@ 2020-10-20 15:35         ` Eric S Fraga
  1 sibling, 0 replies; 11+ messages in thread
From: Eric S Fraga @ 2020-10-20 15:35 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: emacs-orgmode

On Tuesday, 20 Oct 2020 at 16:32, Daniele Nicolodi wrote:
> This may be because the org substitutes a "0" for the missing value,
> thus an integer. 

This makes sense.  Thank you.

-- 
: Eric S Fraga via Emacs 28.0.50, Org release_9.4-61-ga88806.dirty


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 14:53         ` Daniele Nicolodi
@ 2020-10-20 15:35           ` Eric S Fraga
  0 siblings, 0 replies; 11+ messages in thread
From: Eric S Fraga @ 2020-10-20 15:35 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: emacs-orgmode

On Tuesday, 20 Oct 2020 at 16:53, Daniele Nicolodi wrote:
> There are other funny Calc behaviors: if an expression results in a
> number with an unit where the numerical part is exactly 1, the printed
> result looses the numerical part and only the units are printed.

Yes, this I'm used to (and it is *annoying* sometimes).  But given what
calc brings to the party, I can put up with small things like this!

Thanks again,
eric

-- 
: Eric S Fraga via Emacs 28.0.50, Org release_9.4-61-ga88806.dirty


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] org-table: Add mode flag to enable Calc units simplification mode
  2020-10-20 13:30 ` [PATCH] org-table: Add mode flag to enable Calc units simplification mode Daniele Nicolodi
  2020-10-20 13:44   ` Eric S Fraga
@ 2020-10-21 15:57   ` Daniele Nicolodi
  1 sibling, 0 replies; 11+ messages in thread
From: Daniele Nicolodi @ 2020-10-21 15:57 UTC (permalink / raw)
  To: emacs-orgmode

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

Hello,

after working on this I realized that the org-tbl-calc-modes variables
is used only locally despite being declare globally. Maybe a remnant
from pre-lexical-binding times. Attached is a patch (on top of the
others one in this thread) that simplifies things a little.

Cheers,
Dan


On 20/10/2020 15:30, Daniele Nicolodi wrote:
> Hello,
> 
> attached there are a few patches reworking the code, fixing the bug, and
> introducing a new mode flag to enable Calc's units simplification mode
> as discussed in a recent thread on the mailing list.  I haven't updated
> the documentation.  I can do it once we agree that this feature is a
> good idea.
> 
> Cheers,
> Dan
> 
> 
> On 19/10/2020 17:38, Daniele Nicolodi wrote:
>> Hello,
>>
>> I am hacking org-table-eval-formula (see thread about monetary values in
>> org-tables) which uses this inline function:
>>
>> (defsubst org-table--set-calc-mode (var &optional value)
>>   (if (stringp var)
>>       (setq var (assoc var '(("D" calc-angle-mode deg)
>> 			     ("R" calc-angle-mode rad)
>> 			     ("F" calc-prefer-frac t)
>> 			     ("S" calc-symbolic-mode t)))
>> 	    value (nth 2 var) var (nth 1 var)))
>>   (if (memq var org-tbl-calc-modes)
>>       (setcar (cdr (memq var org-tbl-calc-modes)) value)
>>     (cons var (cons value org-tbl-calc-modes)))
>>   org-tbl-calc-modes)
>>
>> which I am not able to understand or which is not correct.
>>
>> The first (if ...) does some value substitutions, however, IIUC the
>> second (if ...) sets a new value for an entry in the org-tbl-calc-modes
>> plist if the entry is already present and builds a new plist with the
>> entry prepended if the entry is not there. However, the original plist
>> is returned and not the one with the new entry prepended.
>>
>> It does not seem to be the intended behavior.
>>
>> Shouldn't this be simply:
>>
>> (defsubst org-table--set-calc-mode (var &optional value)
>>   (if (stringp var)
>>       (setq var (assoc var '(("D" calc-angle-mode deg)
>> 			     ("R" calc-angle-mode rad)
>> 			     ("F" calc-prefer-frac t)
>> 			     ("S" calc-symbolic-mode t)))
>> 	    value (nth 2 var) var (nth 1 var)))
>>   (plist-put org-tbl-calc-modes var value))
>>
>> or, better, the code refactored to do not use this function?
>>
>> Cheers,
>> Dan
>>
> 


[-- Attachment #2: 0004-org-table-Remove-unused-org-tbl-calc-modes-variable.patch --]
[-- Type: text/plain, Size: 4374 bytes --]

From 2d4521a032ec3e4174c97b2b2e9a08491e9870fb Mon Sep 17 00:00:00 2001
From: Daniele Nicolodi <daniele@grinta.net>
Date: Wed, 21 Oct 2020 17:47:15 +0200
Subject: [PATCH 4/4] org-table: Remove unused org-tbl-calc-modes variable

* org-table.el (org-tbl-calc-modes): Remove the variable declaration
as the varialble is only used as a local variable in `org-table-eval-formula'.

* org-table.el (org-table--set-calc-mode): Drop convenience macro.

* org-table.el (org-table-eval-formula): Rename `org-tbl-calc-modes`
local variable without the org-table prefix and usr the gained screen
real estate to avoid indirection through covenience macro.
---
 lisp/org-table.el | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/lisp/org-table.el b/lisp/org-table.el
index 6b92656bd..1651decd3 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -676,8 +676,6 @@ Will be filled automatically during use.")
     ("_" . "Names for values in row below this one.")
     ("^" . "Names for values in row above this one.")))
 
-(defvar org-tbl-calc-modes nil)
-
 (defvar org-pos nil)
 
 \f
@@ -721,9 +719,6 @@ Field is restored even in case of abnormal exit."
 	 (org-table-goto-column ,column)
 	 (set-marker ,line nil)))))
 
-(defsubst org-table--set-calc-mode (var value)
-  (setq org-tbl-calc-modes (plist-put org-tbl-calc-modes var value)))
-
 \f
 ;;; Predicates
 
@@ -2424,7 +2419,7 @@ location of point."
 			equation
 		      (org-table-get-formula equation (equal arg '(4)))))
 	   (n0 (org-table-current-column))
-	   (org-tbl-calc-modes (copy-sequence org-calc-default-modes))
+	   (calc-modes (copy-sequence org-calc-default-modes))
 	   (numbers nil)	   ; was a variable, now fixed default
 	   (keep-empty nil)
 	   form form0 formrpl formrg bw fmt ev orig lispp literal
@@ -2440,11 +2435,11 @@ location of point."
 	      (let ((c (string-to-char (match-string 1 fmt)))
 		    (n (string-to-number (match-string 2 fmt))))
 		(cl-case c
-		  (?p (org-table--set-calc-mode 'calc-internal-prec n))
-		  (?n (org-table--set-calc-mode 'calc-float-format (list 'float n)))
-		  (?f (org-table--set-calc-mode 'calc-float-format (list 'fix n)))
-		  (?s (org-table--set-calc-mode 'calc-float-format (list 'sci n)))
-		  (?e (org-table--set-calc-mode 'calc-float-format (list 'eng n)))))
+		  (?p (setf (cl-getf calc-modes 'calc-internal-prec) n))
+		  (?n (setf (cl-getf calc-modes 'calc-float-format) (list 'float n)))
+		  (?f (setf (cl-getf calc-modes 'calc-float-format) (list 'fix n)))
+		  (?s (setf (cl-getf calc-modes 'calc-float-format) (list 'sci n)))
+		  (?e (setf (cl-getf calc-modes 'calc-float-format) (list 'eng n)))))
 	      ;; Remove matched flags from the mode string.
 	      (setq fmt (replace-match "" t t fmt)))
 	    (while (string-match "\\([tuTUNLEDRFS]\\)" fmt)
@@ -2452,16 +2447,16 @@ location of point."
 		(cl-case c
 		  (?t (setq duration t numbers t
 		      	    duration-output-format org-table-duration-custom-format))
-		  (?u (org-table--set-calc-mode 'calc-simplify-mode 'units))
+		  (?u (setf (cl-getf calc-modes 'calc-simplify-mode) 'units))
 		  (?T (setq duration t numbers t duration-output-format nil))
 		  (?U (setq duration t numbers t duration-output-format 'hh:mm))
 		  (?N (setq numbers t))
 		  (?L (setq literal t))
 		  (?E (setq keep-empty t))
-		  (?D (org-table--set-calc-mode 'calc-angle-mode 'deg))
-		  (?R (org-table--set-calc-mode 'calc-angle-mode 'rad))
-		  (?F (org-table--set-calc-mode 'calc-prefer-frac t))
-		  (?S (org-table--set-calc-mode 'calc-symbolic-mode t))))
+		  (?D (setf (cl-getf calc-modes 'calc-angle-mode) 'deg))
+		  (?R (setf (cl-getf calc-modes 'calc-angle-mode) 'rad))
+		  (?F (setf (cl-getf calc-modes 'calc-prefer-frac) t))
+		  (?S (setf (cl-getf calc-modes 'calc-symbolic-mode) t))))
 	      ;; Remove matched flags from the mode string.
 	      (setq fmt (replace-match "" t t fmt)))
 	    (unless (string-match "\\S-" fmt)
@@ -2606,7 +2601,7 @@ location of point."
 
 	  (setq ev (if (and duration (string-match "^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" form))
 		       form
-		     (calc-eval (cons form org-tbl-calc-modes)
+		     (calc-eval (cons form calc-modes)
 				(when (and (not keep-empty) numbers) 'num)))
 		ev (if duration (org-table-time-seconds-to-string
 				 (if (string-match "^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" ev)
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-10-21 15:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-19 15:38 Bug in org-table--set-calc-mode? Daniele Nicolodi
2020-10-20 13:30 ` [PATCH] org-table: Add mode flag to enable Calc units simplification mode Daniele Nicolodi
2020-10-20 13:44   ` Eric S Fraga
2020-10-20 14:00     ` Daniele Nicolodi
2020-10-20 14:22       ` Eric S Fraga
2020-10-20 14:19     ` Eric S Fraga
2020-10-20 14:32       ` Daniele Nicolodi
2020-10-20 14:53         ` Daniele Nicolodi
2020-10-20 15:35           ` Eric S Fraga
2020-10-20 15:35         ` Eric S Fraga
2020-10-21 15:57   ` Daniele Nicolodi

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.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).