如何在Clojure中切换科学计数法?

4

我正在尝试使用Clojure解决PythonChallenge问题:

(java.lang.Math/pow 2 38)

I got

2.74877906944E11

然而,我需要关闭这个科学计数法。我查阅了Clojure文档,仍然不知道该怎么做。是否有一种通用的方法在Clojure中切换科学计数法的开/关状态?
谢谢。
2个回答

9
您可以使用 format 函数来控制输出结果的格式。
user> (format "%.0f" (Math/pow 2 38))
"274877906944"

此外,如果没有丢失所需数据的风险,您可以将其转换为精确类型:
user> 274877906944.0
2.74877906944E11
user> (long 274877906944.0)
274877906944

针对更大的输入,可使用BigInts。

user> (bigint 27487790694400000000.0)
27487790694400000000N

它有效了,谢谢!如果我想将一个大数字转换为科学计数法,该怎么办? - Nick
它使用Java Formatter的格式 http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html - 因此可以使用%E(带有可选的前缀以进行精度控制)。 - noisesmith
非常感谢!"%e"确实有效。如果数字不是浮点类型,我必须先执行(float the-number)。这也很合理。 - Nick

0

警告

使用java.lang.Math/pow计算整数的幂,往往会失去精度。

例如:

(bigint (java.lang.Math/pow 3 38))
; 1350851717672992000N

(int-pow 3 38)
; 1350851717672992089

它使用二进制的2次幂,因为如果你在二进制中查看它们,就会发现只有一个1位和所有其他0位。因此,十六进制指数仅保持上升,而孤立的1位则漂浮在有效数字中。没有丢失精度。
顺便说一下,上面的int-pow只是重复乘法:
(defn int-pow [b ^long ex]
  (loop [acc 1, ex ex]
    (case ex
      0 acc
      (recur (* acc b) (dec ex)))))

这更像是一条评论而不是解决方案,但又不适合作为评论。


谢谢。当我遇到大量计算时,我会回来参考这里。 - Nick
谢谢缩略图。我正在阅读《Clojure编程》(OReilly),这是一本很棒的书。我是一个没有计算机科学背景的新手,所以对我来说有点难。幸运的是,Clojure社区的人非常乐于助人和友善,这也给了我很多鼓励。 - Nick
很久以前,我再次找到了这篇文章。我认为这个 int-pow 可能更容易阅读:(defn int-pow [base exp] (if (zero? exp) 1N (* base (int-pow base (dec exp))))) - Nick
@Nick 是的。这样更容易阅读。但它是递归的,所以速度较慢,并且只能处理小于10K的exp,并且需要正常的JVM参数。 - Thumbnail
是的,你说得对。我刚刚从SICP中读到了这个快速幂算法:`(defn fast-expt [b n] (cond (zero? n) 1N (even? n) (square (fast-expt b (/ n 2))) :else (* b (fast-expt b (dec n)))))(defn- square [n] (* n n))这可以在大约22毫秒内计算出3^20K`。 - Nick
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接