2016-03-06 81 views
5

長整數m = 38941629971148227236N。我想生成1 <和< m之間的數字e,並檢查e是否滿足以下要求:gcd(e,m)= 1。我的方法是使用(長(RAND M))隨機生成E,我得到了一個警告:如何在clojure中隨機生成一個長整數

IllegalArgumentException Value out of range for long: 
1.7166121075068025E19 clojure.lang.RT.longCast (RT.java:1254) 

我的代碼是:

(defn find-e [m] 
(loop [e (long (rand m))] 
    (if (= 1 (gcd e m)) e 
     (recur (long (rand m)))))) 

我知道結果超出範圍長,但我不知道有什麼辦法可以解決這個問題嗎?

回答

4

問題在於(long (rand m)),因爲您選擇的隨機值通常比長內容要大得多。你想做一個不長的大事。下面是它周圍的一種方法:

(bigint (bigdec (rand 38941629971148227236N))) 

注意,在這種方式中選擇隨機數確實是生產雙將其轉化爲將其轉化爲一個bigit一個bigdec。因此,可能的隨機值域是有限的。使用double作爲基本隨機數意味着不會生成所有可能的bigint。如果你想真正的BIGINT隨機選擇,看看this answer ......但如果你沒有太在意,只要你在正確的範圍內BIGINT這可能會爲你工作:

(defn find-e [m] 
    (loop [e (bigint (bigdec (rand m)))] 
    (if (= 1 (gcd e m)) 
     e 
     (recur (bigint (bigdec (rand m))))))) 
4

(defn random-bigint [limit] 
    (let [bits (.bitLength limit)] 
    (loop [result (BigInteger. bits (ThreadLocalRandom/current))] 
     (if (< result limit) 
     (bigint result) 
     (recur (BigInteger. bits (ThreadLocalRandom/current))))))) 

那麼你的代碼可以重複使用的功能:

(defn find-e [m] 
    (loop [e (random-bigint m)] 
    (if (= 1 (gcd e m)) 
     e 
     (recur (random-bigint m))))) 

這種方法發電機密封可以用知識從the answer on generating random java.math.BigInteger有一個更有效的解決方案構建它e隨機數然後檢查它是否在期望的範圍內有一個缺點,如果你非常不幸,你的循環將需要很多迭代。您可能會將其擴展爲對重試次數有限制,並且在超出次數時發生異常並失敗。

+0

真的很好的答案。對於大限制,重試次數不應該成爲問題。 – muhuk

+1

其實我錯了,它可能是一個問題,因爲每一位都會使搜索空間加倍。而越大的「極限」越大,它變得越糟糕。 – muhuk