我昨天花了一些时间为this challenge published on Reddit编写解决方案,并且能够在没有作弊的情况下完成它,但我还有几个问题。 Reference material here
这是我的代码。
(ns baking-pi.core
(:import java.math.MathContext))
(defn modpow [n e m]
(.modPow (biginteger n) (biginteger e) (biginteger m)))
(defn div [top bot]
(with-precision 34 :rounding HALF_EVEN
(/ (bigdec top) (bigdec bot))))
(defn pow [n e]
(.pow (bigdec n) (bigdec e) MathContext/DECIMAL128))
(defn round
([n] (.round (bigdec n) MathContext/DECIMAL128))
([n & args] (->> [n args] (flatten) (map round))))
(defn left [n d]
(letfn [(calc [k] (let [bot (+' (*' 8 k) d)
top (modpow 16 (-' n k) bot)]
(div top bot)))]
(->> (inc' n)
(range 0)
(map calc)
(reduce +'))))
(defn right [n d]
(letfn [(calc [[sum'' sum' k]]
(let [sum' (if (nil? sum') 0M sum')
top (pow 16 (-' n k))
bot (+' (*' k 8) d)
delta (div top bot)]
[sum' (+' sum' delta) (inc' k)]))
(pred [[sum'' sum' k]]
(cond (or (nil? sum'') (nil? sum')) true
(apply == (round sum'' sum')) false
:else true))]
(->> [nil nil (inc' n)]
(iterate calc)
(drop-while pred)
(first)
(second))))
(defn bbp [n]
(letfn [(part [m d] (*' m (+' (left n d) (right n d))))]
(let [sum (-' (part 4 1) (part 2 4) (part 1 5) (part 1 6))]
(-> sum
(-' (long sum))
(*' 16)
(mod 16)
(Long/toHexString)))))
我有两个问题。
wiki发表以下声明。由于我的计算精确到十进制后的34位数,我如何利用它来生成每个bbp调用的更多十六进制数字?
理论上,接下来的几位数字可达到计算的准确性 使用也准确
我的算法依赖于BigInteger的modPow进行模幂运算(基于以下引用),以及其他地方的BigDecimals。它也很慢。请记住,我不想在每个问题#1中失去有意义的准确性,加速这个程序并使其成为有效的clojurescript以及clojure的最佳方法是什么?
要快速有效地计算16 n - k mod(8k + 1),请使用 模幂运算算法。
编辑:从3个问题改为2个。管理自己回答第一个问题。
答案 0 :(得分:2)
如果您希望每个bpp调用计算更多位
然后你必须将方程从1/(16^k)
基数改为大基数。你可以通过总结2
次迭代(k
和k+1
)来做到这一点,所以你有类似的东西
(...)/16^k + (...)/16^(k+1)
(...)/256^k
但在这种情况下,您需要更精确的int
操作。使用不太精确的迭代通常会更快
如果您查看基本等式,那么您会发现根本不需要bigint
进行计算
这就是使用此迭代的原因,但输出数当然是bigint
。因此,您无需在bigint
上计算模块化算术。
我不知道您使用的那个是多么优化......但这是我的:
如果您只想要速度而不是无限精度,那么请使用其他PSLQ方程式
我对PSLQ的理解是找到实数和整数迭代之间关系的算法。
这是我最喜欢的800 digits of Pi algorithm,如果链接出现故障,我会从中提取代码:
//The following 160 character C program, written by Dik T. Winter at CWI, computes pi to 800 decimal digits.
int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);}