How to print numbers with n decimal places

(The code examples below may be run from the Nyquist Prompt effect. It is necessary to have a track selection in order to use the Nyquist Prompt, though none of these examples are concerned with audio data).

There is a system variable that allows a user to specify how floating point numbers are to be printed:
float-format

This system variable is set to a string expression of either “%e”, “%f” or “%g” as described in the XLISP manual here:
http://www.audacity-forum.de/download/edgar/nyquist/nyquist-doc/xlisp/xlisp-ref/xlisp-ref-119.htm

The part that is not really covered in the manual is how to set it so that floating point numbers are displayed with a specific number of decimal places.
The way to do this is to set the variable with the “%f” option in the form “%#1._n_f” where n is the number of decimal places.

For example, using this code:

(setq *float-format* "%#1.3f")
(format NIL "~a" 1023.987654321)

will output:

1023.988

(three decimal places)
and

(setq *float-format* "%#1.0f")
(format NIL "~a" 1023.987654321)

will output:

1024.

(0 decimal places).

Some details to notice;

  • The number is rounded (not truncated) to the set number of decimal places.
  • The decimal point is printed even if the number of decimal places is set to zero, indicating that it is a float and not an integer.
  • The value of the number is not changed - only the way that it is displayed is changed.

Here’s an example to illustrate:

(setq A 1.4937)
(setq B 3.4460)

(setq *float-format* "%#1.2f")
(setq a-string (format NIL "~a" A))

(setq *float-format* "%#1.1f")
(setq b-string (format NIL "~a" B))

(setq *float-format* "%#1.0f")
(setq c-string (format NIL "~a" (+ A B)))

(setq *float-format* "%#1.6f")
(strcat a-string " + " b-string " = " c-string "n"
   (format NIL "~a + ~a = ~a" A B  (+ A B)))

which prints:

1.49 + 3.4 = 5.
1.493700 + 3.446000 = 4.939700

This can be very useful when outputting text data, for example with an Analyze plug-in. However it is rather cumbersome if the format needs to be changed very often.
What would be more convenient is if we had a function that we could reuse that would convert a number into a string with a set number of decimal places.

A function to round number to specified decimal places and return as a string.

; print number 'n' rounded to 'p' places
(defun roundn (n p)
   (let* ((x (format NIL "~a" p))(ff (strcat "%#1." x "f")))
      (setq *float-format* ff)
      (format NIL "~a" n)))

Here’s a commented version with a bit of code to test the function:

; function to round number to specified decimal places and return as a string.
(defun roundn (num places)
   (let* ((x (format NIL "~a" places)) ; number of places as a string
            (ff (strcat "%#1." x "f"))) ; build string for *float-format"
      (setq *float-format* ff)
      (format NIL "~a" num)))

;; test function
(setq string "") ; initialisse empty string
(dotimes (n 20)
   (setq string (strcat string "n" (roundn pi n))))

(print string)