【问题标题】:How to convert to dollars and cents -- rounding, and with comma separators如何转换为美元和美分——四舍五入,并使用逗号分隔符
【发布时间】:2013-11-24 10:38:46
【问题描述】:

以下代码摘录会将一列数字相加,并产生几个小数点长的结果。谁能举例说明如何将结果转换为美元和美分,四舍五入到小数点后第二位——即,1.555 应该将向上四舍五入为1.56;并且1.554 应该将向下 舍入到1.55。另外,我想在小数点左侧每三位插入逗号分隔符——例如,1124412.555 应转换为1,124,412.56

(let ((sum 0))
  (while (re-search-forward "[0-9]*\\.?[0-9]+" nil t)
    (setq sum (+ sum (string-to-number (match-string 0)))))
  (insert "\n\nTotal Hours:  " (format "%s" sum ))
  (insert "\n\nTotal Fee for Services Rendered:  " (format "%s" (* 250 sum)))
  (insert "\n\nOne-third of total fee:  " (format "%s" (/ (* 250 sum) 3))))

2.0
0.2
0.1
4.75
4.0
6.5
0.1

Total Hours:  17.650000000000002

Total Fee for Services Rendered:  4412.500000000001

One-third of total fee:  1470.8333333333337

根据@Drew 和@abo-abo 提供的答案,以下是修订后的草案,现在看来可以正常工作:

08884.75585
78774.1235
6.545

Total Hours:  87,665.42

Total Fee:  $21,916,356.09

One-Third:  $7,305,452.03

(let ((sum 0))
  (while (re-search-forward "[0-9]*\\.?[0-9]+" nil t)
    (setq sum (+ sum (string-to-number (match-string 0)))))
    (setq total-hours (group-number (number-conversion (format "%s" sum ))))
    (setq services-rendered (group-number (number-conversion (format "%s" (* 250 sum)))))
    (setq one-third (group-number (number-conversion (format "%s" (/ (* 250 sum) 3)))))
  (insert "\n\nTotal Hours:  " total-hours)
  (insert "\n\nTotal Fee:  $" services-rendered)
  (insert "\n\nOne-Third:  $"  one-third) )

;; @abo-abo
(defun number-conversion (str)
  (let ((x (read str)))
    (format "%0.2f" (* 0.01 (round (* 100 x)))) ))

;; http://www.emacswiki.org/emacs/ElispCookbook#toc23
(defun group-number (num &optional size char)
    "Format NUM as string grouped to SIZE with CHAR."
    ;; Based on code for `math-group-float' in calc-ext.el
    (let* ((size (or size 3))
           (char (or char ","))
           (str (if (stringp num)
                    num
                  (number-to-string num)))
           (pt (or (string-match "[^0-9a-zA-Z]" str) (length str))))
      (while (> pt size)
        (setq str (concat (substring str 0 (- pt size))
                          char
                          (substring str (- pt size)))
              pt (- pt size)))
      str))

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    我相信 abo-abo 的 (* 0.01 (round (* 100 x))) 在极端情况下可能会导致意外(因为 0.01 不能在内部浮点表示中精确表示)。一个更简单的舍入解决方案是:

    (format "%0.2f" x)
    

    【讨论】:

    • 是的,如果数字必须准确(这里可能是也可能不是,但通常是当数字代表金钱时),那么你应该'不要使用浮点数。
    • 非常感谢 - 我已经更新了问题中的工作草案以反映您提供的代码。
    • 我尝试将@abo-abo 的功能与您的代码相结合的尝试无法正常工作。评估 (number-conversion "4.37") 产生 4.38 的结果——正确的结果应该是 4.37。如果它是 4.375、4.376、4.377、4.378 或 4.379,它应该只向上取整到 4.38。关于如何更正该功能的任何想法?我正在使用(defun number-conversion (str) (let ((x (read str))) (format "%0.2f" (+ x 0.005)) ))
    • 哦,确实。 (format "%0.2f" x) 是正确的解决方案,因为 %0.2f 已经舍入(而不是截断)。
    • (stefan "1.555") 似乎没有使用(defun stefan (str) (let ((x (read str))) (format "%0.2f" x) ))进行四舍五入
    【解决方案2】:

    使用(format "%.2f" YOUR-NUMBER)。例如:

    (insert "\n\nOne-third of total fee:  " (format "%.2f" (/ (* 250 sum) 3))))
    

    f 表示使用小数点表示法。 .2 表示显示两位小数。请参阅format 的文档字符串或Elisp 手册,节点Formatting Strings

    据我所知,在 Emacs Lisp 中没有预定义的格式说明符可以为您提供逗号分隔的数字分组。在 Common Lisp 中,format 更强大(一种语言本身)。

    如果您真的需要逗号分隔,那么您需要编写解析文本的代码(例如从format 返回的字符串)并在需要的地方插入逗号。也许其他人会在这里为您做这件事,但鉴于您目前掌握的信息,您可能可以自己做。没有任何预定义可以神奇地帮助解决此问题。

    this 可能对逗号有帮助。

    【讨论】:

    • 任务完成——非常感谢。我已经用一个似乎可以解决所有问题的工作草案更新了这个问题——它使用了你对EmacsWiki: Elisp Cookbook 中的group-number 的建议,以及@abo-abo 提供的num->dollars 函数(我将其重命名为@987654333 @)。
    【解决方案3】:

    代码如下:

    (defun num->dollars (str)
      (let ((x (read str)))
        (replace-regexp-in-string
         "\\."
         ","
         (format "%0.2f"
                 (* 0.01 (round (* 100 x)))))))
    
    (mapcar
     #'num->dollars
     '("4412.500000000001" "1470.8333333333337" "1.555" "1.554"))
    
     ; => ("4412,50" "1470,83" "1,56" "1,55") 
    

    【讨论】:

    • 我认为他想要的逗号是用于分组的。例如,1,234.56 而不是 1234.56,而不是 1234,56。 IOW,不使用逗号作为小数点,而是用于分组:千、百万、...
    • 看起来答案是 abo-abo(他解决了舍入问题)和 @Drew(他通过在 EmacsWiki 中引用 group-number 解决了逗号问题:Elisp Cookbook )。我将整合功能并报告回来。非常感谢你们。
    • 不知何故,我没有注意到您也在询问四舍五入。我以为你有数字,只是询问格式化数字。
    【解决方案4】:

    一般来说,在处理货币值(或其他需要精度的小数部分)时,值得考虑内置 calc 库。

    calc 使用十进制表示浮点数(而不是二进制),因此在处理十进制值时不受传统浮点舍入问题的影响。

    它还可以处理用于显示的数字分组。

    C-hig (calc) RET

    【讨论】:

    • 感谢您对calc 的引用——非常感谢。
    • calc 的功能非常丰富,虽然也很复杂,但calc-eval 的形式有一个非常简单方便的界面(但请注意请注意,您在此函数中使用中缀表示法,而不是前缀)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多