2

Is there a way to get elisp to automatically treat all numeric variables as floating points without having to repeatedly use the float function?

For example to a division function that outputs the "true" quotient is

(defun divide ( x y )
  (/ (float x) y))

But I'd rather not have so many float functions floating around (even if, given the name, that's a part of the function's essence ;) ).

Drew
  • 75,699
  • 9
  • 109
  • 225
Quinn Culver
  • 157
  • 6
  • 1
    You might want to clarify why you have "*many* float functions": I don't see this problem occurring often within "typical" Elisp code and I can't think of a general way to satisfy your request (except in ways which break lots of existing code), so your specific circumstances are probably necessary to be able to come up with a good answer. – Stefan Oct 23 '19 at 19:22
  • I guess it must be typical practice to just make sure the numbers passed at the beginning of a complicated procedure are floats? So in my example I'd remove the `float` function but just be sure to pass, say, 2.0 instead of 2 as an argument to the function `divide`. – Quinn Culver Oct 23 '19 at 20:13
  • 1
    It's only "typical practice", except when you intend to use floating point computations (i.e. rarely). In Elisp, integers and floats are two distinct types that behave differently in various circumstances, and we write the code with this premise in mind (like in many (most?) other programming languages and unlike in JS). – Stefan Oct 23 '19 at 20:29
  • Thanks @Stefan. I'm gonna delete this question unless you think I shouldn't. – Quinn Culver Oct 23 '19 at 20:42
  • 1
    To elaborate slightly, floating point numbers are not a super-set of integers. FP is imprecise by definition; there are numbers (including integers) in the FP range which cannot be represented. As Stefan says, the two things can behave differently, so if you don't require FP then using it is probably a mistake. – phils Oct 23 '19 at 20:50
  • Questions like this can be helpful to other people who have the same question and go searching; so I'd be inclined to close it rather than delete it. Or maybe Stefan could post his comments as an answer. – phils Oct 23 '19 at 20:52
  • Sounds like this might be an [XY problem](https://meta.stackexchange.com/q/66377/231821). Maybe say what you're really trying to do (which has resulted in your solution involving many uses of `float`). (IOW, pretty much what @Stefan asked.) – Drew Oct 23 '19 at 21:28

2 Answers2

3

The following Elisp code demonstrates how you can define your own wrapper macro with-float/ that treats all explicit occurences of / in its body as division of floats.

Division operators that are used in functions called within the body of with-float/ are the original operators.

(defmacro with-float/ (&rest body)
  "Evaluate BODY with / for float arguments."
  (declare (debug body))
  `(cl-macrolet ((/ (x &rest args)
           `(,(symbol-function #'/) (float ,x) ,@args)))
     ,@body))

(defun using-the-old-/ (x y)
  (/ x y))

(defun using-float/ (x y)
  (with-float/
   (/ x y)))

(append
 (list (using-float/ 1 2))
 (with-float/
  (list
   (/ 1 2)
   (using-the-old-/ 1 2))))

The last form (i.e., the append) returns (0.5 0.5 0).

Tobias
  • 32,569
  • 1
  • 34
  • 75
3

For numeric calculation there is a parallel universe within Elisp: Calc.

The division operator / within defmath works with the floating numbers of Calc.

Nevertheless, the interface of Calc with the Elisp world is a bit complicated. You need to convert floating point numbers to strings. These strings are then converted by Calc to their Calc-internal representation.

This is not a problem if you stay in the defmath "environment" for your complicated maths calculations.

(defmath mydiv (x y)
  "Divide x by y within `defmath'."
  (/ x y))

(calc-eval "mydiv(1,2)")

The calc-eval form returns 0.5.

You can convert a float number X to Calc format by (math-read-number (number-to-string X)) and a Calc float Y to an Emacs float by (read (math-format-value Y)).

Tobias
  • 32,569
  • 1
  • 34
  • 75