2016-03-06 20 views
5

長い整数m = 38941629971148227236Nがあります。 1 < e < mの間にeを生成し、この要件を満たす場合にeをチェックします。gcd(e、m)= 1。私のコードがある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)))))) 

私は範囲外の結果を知っている長い間、私の方法は、ランダムに電子を生成する(長い(ランドのM))を使用することで、私は警告を得ましたしかし、私はこの問題を解決する方法はありますか?

答えて

4

問題は(long (rand m))にあります。選択しているランダムな値は、しばしば長いものの中に収まるよりもはるかに大きいためです。あなたはbigintを長くしたくないです。このように乱数を選択すると、本当にbigitに変換されbigdecに変換され、二重に生成していることを

(bigint (bigdec (rand 38941629971148227236N))) 

注:ここでは、その周りに1つの方法です。したがって、可能なランダム値の領域は限定されている。基本乱数として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))))))) 

:より効率的なソリューションを持っているthe answer on generating random java.math.BigIntegerから知識を使用して、それを構築することができ

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

generatへのこのアプローチあなたが非常に不運な場合、あなたのループは多くの反復を取るだろうという欠点を持っています。再試行回数に制限があるように拡張し、超過した場合には例外を発生させることができます。

+0

本当に良い答えです。大きな 'limit'sの場合、再試行回数は問題ではありません。 – muhuk

+1

実際、私は間違っていました。あらゆるビットが検索スペースを倍増させるにつれて問題になる可能性があります。そして、より大きな「限界」が得られると、悪化する。 – muhuk