2016-03-06 45 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