質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

1517閲覧

JavaScriptで巨大な数が素数であるか判定したい

ActiveTK

総合スコア50

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2023/04/08 02:31

編集2023/04/08 02:34

実現したいこと

JavaScriptで巨大な数(メルセンヌ数)が素数であるか判定したいです。
巨大な数とは、具体的には 2^100000000 (10進法表記で約3000万桁) 程度です。

前提

JavaScript V8 11.1.24.7

JavaScript

1let prime, n; 2for (n = 100000000n; ; n++) { 3 4 // 一度目のループ 5 // 2^n - 1 を計算する 6 if (!prime) prime = (2n ** n) - 1n; 7 // 2回目以降のループ 8 // 2^n - 1 を計算するとリソースを食うので、 9 // 一つ前の計算で求めた結果に1を足して2を掛けて1を引く 10 else prime = (prime + 1n) * 2n - 1n; 11 12 // 素数判定 13 if (IsPrime(n, prime)) 14 console.log("2^" + primejs.n + "-1 は素数です。"); 15}

JavaScript

1function IsPrime(n, num) { 2 // 高速化のため、素数番目以外のメルセンヌ数は除外 3 // 省略 4 5 // リュカ–レーマーのテスト 6 let s = 4n, M = (1n << num) - 1n; 7 for (let n = 2; n < num; n++) 8 s = (s ** 2n - 2n) % M; 9 10 if (s != 0n) return false; 11 12 // 素数の場合の処理 13 return true; 14} 15

発生している問題・エラーメッセージ

Uncaught RangeError: Maximum BigInt size exceeded 発生場所: `let s = 4n, M = (1n << num) - 1n;`

試したこと

リュカ–レーマーのテストを用いずに、単純に2からsqrt(num)までmodを行うと数がオーバーしません。

javascript

1function sqrt(value) { 2 let sqrt = value / 3n; 3 if (value <= 0n) return 0n; 4 for (let i = 0; i < 6; i++) 5 sqrt = (sqrt + value / sqrt) / 2n; 6 return sqrt; 7} 8function IsPrime(n, num) { 9 // 3以上かつ数字の平方根より小さい数で割り切れないか試す。numRoot mod n === 0 の時点で終了 10 // BigIntは小数点以下を扱わないため、Math.ceilは不要 11 let numRoot = sqrt(num); 12 for (let i = BigInt(3); i < numRoot; i++) 13 if (num % i === 0n) return false; 14 15 return true; 16}

しかし、それでは最大でsqrt(num)-2回のループ処理が必要となってしまうため、どうしてもリュカ–レーマーのテストをオーバーフローさせずに実行したいです。

そこで、BigIntの上限より大きな数を扱う方法若しくは巨大な数を登場させずに素数判定ができるアルゴリズムがあれば教えて頂きたいです。

宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2023/04/08 03:29

> しかし、それでは最大でsqrt(num)-2回のループ処理が必要となってしまうため、どうしてもリュカ–レーマーのテストをオーバーフローさせずに実行したいです。 つまり、それより速い方法があると思っていますか?
Zuishin

2023/04/08 03:40 編集

上のコメントは「リュカ・レーマーの判定法を用いず判定したい」と読んでしまったためです。 判定法を正しく実装したいということなら、BigInt を使わない方法を探すのが良いでしょう。 単純に、多倍長整数を自分で実装してしまえば解決するかもしれません。 JavaScript ではなく C++ の方がみつけやすいと思います。
ActiveTK

2023/04/08 10:03

コメント有難うございます。 そもそもJavaScriptには実行メモリ制限があるため、C#でBigIntegerを用いて同様の処理を実装したことにより、自己解決(解決なのかは未知数)しました。
Zuishin

2023/04/08 10:06

過去の質問から見て想定していた結果と寸分違わず一致しました。
guest

回答1

0

自己解決

そもそもJavaScriptには実行メモリ制限があるなど巨大な数字の処理に向いていないため、
C#でBigIntegerを用いて同様の処理を実装したことにより、自己解決しました。

C#

1using System.Numerics; 2 3static bool IsPrime(BigInteger n) 4{ 5 if (n < 2) 6 return false; 7 if (n != 2 && n % 2 == 0) 8 { 9 return false; 10 } 11 Random rand = new Random(); 12 for (int i = 0; i < 30; i++) 13 { 14 BigInteger a = new BigInteger(); 15 do 16 { 17 a = BigInteger.Remainder(BigInteger.Abs(new BigInteger(rand.Next())), n); 18 } while (a == 0); 19 BigInteger x = BigInteger.ModPow(a, n - 1, n); 20 if (x != 1) 21 return false; 22 } 23 return true; 24}

投稿2023/04/08 10:07

ActiveTK

総合スコア50

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問