言語別のテク
64 ビットに収まらない整数を、各言語でどう書けるかをまとめました。 128 ビット整数と多倍長整数の「―」は、標準の機能と外部ライブラリに書き方を見つけていないものです。
- 128 ビット整数: 値が 128 ビットに収まるなら一番速い書き方です。入力から 1024 を読み、次の 5 つを出します: 2127−1、1030 を 7 で割った商、1030 を 1000000007 で割った余り、読んだ 1024 そのもの、下の繰り返しの結果。
- 128 ビットの積: 128 ビット整数の型が無い言語で、64 ビットどうしの積の上位を出す関数を使う書き方です。入力の 1018 + 9 を読み、下の繰り返しの結果だけを出します。書き方が載っている言語でだけ試していて、この列の「―」は試していないという意味です。
- 多倍長整数: 値の大きさを気にせず使えます。入力から 1024 を読み、200!、200! を 1024 で割った商、下の繰り返しの結果を出します。
- 64 ビット整数: 128 ビット整数・128 ビットの積・多倍長整数と速さを比べるためのものです。同じ形の繰り返しを、法を 109 + 7 にして 64 ビット整数だけで回します。入力の 109 + 7 を読み、繰り返しの結果だけを出します。測っていない言語もあります(Python・Ruby・JavaScript などは、64 ビットの整数の型を書けません)。
- 多倍長整数(64 ビットに収まる値): 値が 64 ビットに収まると分かっているのに多倍長整数を使ったときの速さです。64 ビット整数と同じ入力・同じ繰り返しを、多倍長整数で回します。Python のように整数が自動で多倍長になる言語では、ふつうの整数で回した時間です。
- 仕組み: 128 ビット整数・128 ビットの積をどう計算しているかと、整数が自動で多倍長になるか(なる言語では値をどう持っているか)を、各言語の節に書きました。判定と同じ環境で、コンパイル結果や実行時の様子を見て確かめたことだけを書いていて、確かめていない言語には書いていません。
- 繰り返し: 64 ビット整数と多倍長整数(64 ビットに収まる値)のほかは、どれも同じ
x = (x * x + 1) % (10^18 + 9)を 100 万回です。途中の値は 128 ビットに収まります。この 2 つはx = (x * x + 1) % (10^9 + 7)を 100 万回で、途中の値は 64 ビットに収まります。 - 時間: 繰り返し 100 万回の時間です。プログラムの実行時間から、繰り返しを 0 回にした同じプログラムの実行時間を引いているので、処理系の起動と繰り返し以外の処理は入りません。繰り返しを動かしたときに初めて起きる JIT のコンパイルなどは入ります。どちらも 3 回のうち一番速い値で、言語のまとまりの中で差があるときは範囲で書きます。判定サーバーとは別の環境で2026-11-06に測った値なので、書き方どうしの目安にしてください。
- C++ との比: 多倍長整数の 2 つの列には、同じ列の C++23 の boost::multiprecision::cpp_int の時間の何倍かも書きます。
動かしたプログラムは、表の言語名から移る各言語の節の「コード」で読めます。
| 言語 | 64 ビット整数(比べる用) | 多倍長整数(64 ビットに収まる値) | 128 ビット整数 | 128 ビットの積 | 多倍長整数 |
|---|---|---|---|---|---|
| C++ |
long long
言語の機能 11〜12 ms |
boost::multiprecision::cpp_int
外部ライブラリ 24〜33 ms C++ の 1.0〜1.3 倍 動かない: C++11、C++11(gcc12)、C++11(old_compat) |
__int128
言語の機能 24〜42 ms boost::multiprecision::int128_t
外部ライブラリ 24〜25 ms 動かない: C++11、C++11(gcc12)、C++11(old_compat) |
― |
boost::multiprecision::cpp_int
外部ライブラリ 55〜62 ms C++ の 1.0〜1.1 倍 動かない: C++11、C++11(gcc12)、C++11(old_compat) |
| cLay |
long long
言語の機能 11 ms |
boost::multiprecision::cpp_int
外部ライブラリ 22 ms C++ の 0.9 倍 |
__int128
言語の機能 25 ms |
― |
boost::multiprecision::cpp_int
外部ライブラリ 56 ms C++ の 1.0 倍 |
| C |
long long
言語の機能 12 ms |
__int128
言語の機能 25〜26 ms |
― | ― | |
| Java |
long
言語の機能 15 ms |
java.math.BigInteger
標準ライブラリ 223 ms C++ の 8.9 倍 |
― |
Math.multiplyHigh
標準ライブラリ 80 ms |
java.math.BigInteger
標準ライブラリ 495 ms C++ の 8.8 倍 |
| C# |
long
言語の機能 12〜13 ms |
System.Numerics.BigInteger
標準ライブラリ 80〜139 ms C++ の 3.2〜5.6 倍 |
System.Int128
標準ライブラリ 38 ms 動かない: C#(csc) |
― |
System.Numerics.BigInteger
標準ライブラリ 252〜391 ms C++ の 4.5〜7.0 倍 |
| F# |
int64
言語の機能 15 ms |
bigint
言語の機能 92 ms C++ の 3.7 倍 |
System.Int128
標準ライブラリ 70 ms |
― |
bigint
言語の機能 255 ms C++ の 4.6 倍 |
| Perl |
数値(64 ビット整数)
言語の機能 47 ms |
Math::BigInt
標準ライブラリ 43950 ms C++ の 1758 倍 |
― | ― |
Math::BigInt
標準ライブラリ 51925 ms C++ の 927 倍 |
| Raku |
int(ネイティブ)
言語の機能 31 ms |
Int(自動で多倍長)
言語の機能 701 ms C++ の 28 倍 |
― | ― |
Int(自動で多倍長)
言語の機能 866 ms C++ の 15 倍 |
| PHP |
int
言語の機能 18 ms |
BCMath
外部ライブラリ 470 ms C++ の 19 倍 GMP
外部ライブラリ 207 ms C++ の 8.3 倍 |
― | ― |
BCMath
外部ライブラリ 653 ms C++ の 12 倍 GMP
外部ライブラリ 209 ms C++ の 3.7 倍 |
| Python |
int(自動で多倍長)
言語の機能 5〜253 ms C++ の 0.2〜10 倍 |
― | ― |
int(自動で多倍長)
言語の機能 85〜410 ms C++ の 1.5〜7.3 倍 |
|
| Ruby |
Integer(自動で多倍長)
言語の機能 52 ms C++ の 2.1 倍 |
― | ― |
Integer(自動で多倍長)
言語の機能 336 ms C++ の 6.0 倍 |
|
| D |
long
言語の機能 11 ms |
std.bigint.BigInt
標準ライブラリ 456 ms C++ の 18 倍 |
std.int128.Int128
標準ライブラリ 48 ms |
― |
std.bigint.BigInt
標準ライブラリ 726 ms C++ の 13 倍 |
| Go |
int64
言語の機能 12 ms |
math/big.Int
標準ライブラリ 54 ms C++ の 2.2 倍 |
― |
math/bits (Mul64, Add64, Rem64)
標準ライブラリ 30 ms |
math/big.Int
標準ライブラリ 107 ms C++ の 1.9 倍 |
| Haskell |
Int
言語の機能 14 ms |
Integer
言語の機能 28 ms C++ の 1.1 倍 |
― | ― |
Integer
言語の機能 49 ms C++ の 0.9 倍 |
| Scala |
Long
言語の機能 15 ms |
BigInt
標準ライブラリ 62 ms C++ の 2.5 倍 |
― |
Math.multiplyHigh
標準ライブラリ 79 ms |
BigInt
標準ライブラリ 615 ms C++ の 11 倍 |
| Nim |
int64
言語の機能 12 ms |
__int128 (importc)
言語の機能 26 ms |
― | ― | |
| Rust |
i64
言語の機能 12 ms |
num::BigInt
外部ライブラリ 19 ms C++ の 0.8 倍 |
i128
言語の機能 28 ms |
― |
num::BigInt
外部ライブラリ 81 ms C++ の 1.4 倍 |
| Kotlin |
Long
言語の機能 23 ms |
java.math.BigInteger
標準ライブラリ 246 ms C++ の 9.8 倍 |
― |
Math.multiplyHigh
標準ライブラリ 81 ms |
java.math.BigInteger
標準ライブラリ 462 ms C++ の 8.2 倍 |
| Scheme |
整数(自動で多倍長)
言語の機能 58 ms C++ の 2.3 倍 |
― | ― |
整数(自動で多倍長)
言語の機能 768 ms C++ の 14 倍 |
|
| Crystal |
Int64
言語の機能 12 ms |
BigInt (require "big")
標準ライブラリ 302 ms C++ の 12 倍 |
Int128
言語の機能 38 ms |
― |
BigInt (require "big")
標準ライブラリ 299 ms C++ の 5.3 倍 |
| Swift |
Int
言語の機能 12 ms |
Int128
標準ライブラリ 25 ms |
― | ― | |
| OCaml |
int(63 ビット)
言語の機能 13 ms |
Z (Zarith)
外部ライブラリ 17 ms C++ の 0.7 倍 |
― | ― |
Z (Zarith)
外部ライブラリ 90 ms C++ の 1.6 倍 |
| Clojure |
long
言語の機能 81 ms |
bigint
言語の機能 51 ms C++ の 2.0 倍 |
― | ― |
bigint
言語の機能 735 ms C++ の 13 倍 |
| Elixir |
整数(自動で多倍長)
言語の機能 37 ms C++ の 1.5 倍 |
― | ― |
整数(自動で多倍長)
言語の機能 127 ms C++ の 2.3 倍 |
|
| Lua | ― | ― | ― | ||
| Julia |
Int64
言語の機能 0 ms |
BigInt
標準ライブラリ 404 ms C++ の 16 倍 |
Int128
言語の機能 11 ms |
― |
BigInt
標準ライブラリ 420 ms C++ の 7.5 倍 |
| Fortran |
integer(8)
言語の機能 11 ms |
integer(16)
言語の機能 26 ms |
― | ― | |
| JavaScript |
BigInt
言語の機能 22〜66 ms C++ の 0.9〜2.6 倍 |
― | ― |
BigInt
言語の機能 92〜115 ms C++ の 1.6〜2.1 倍 |
|
| TypeScript |
bigint
言語の機能 24〜59 ms C++ の 1.0〜2.4 倍 |
― | ― |
bigint
言語の機能 89〜115 ms C++ の 1.6〜2.1 倍 |
|
| Common Lisp |
整数(自動で多倍長)
言語の機能 15 ms C++ の 0.6 倍 |
― | ― |
整数(自動で多倍長)
言語の機能 83 ms C++ の 1.5 倍 |
|
| Standard ML |
Int64.int
標準ライブラリ 12 ms |
IntInf
標準ライブラリ 20 ms C++ の 0.8 倍 |
― | ― |
IntInf
標準ライブラリ 70 ms C++ の 1.2 倍 |
| Bash |
$(( ))(算術式)
言語の機能 2655 ms |
bc コマンド
外部ライブラリ 1075 ms C++ の 43 倍 |
― | ― |
bc コマンド
外部ライブラリ 2263 ms C++ の 40 倍 |
| Fix |
I64
言語の機能 12 ms |
Minilib.Math.BigInt
外部ライブラリ 98 ms C++ の 3.9 倍 |
I128
言語の機能 25 ms |
― |
Minilib.Math.BigInt
外部ライブラリ 426 ms C++ の 7.6 倍 |
C++
C++23(gcc16)、C++23(gnu拡張gcc16)、C++23、C++23(gnu拡張)、C++17、C++17(gnu拡張)、C++17(gcc12)、C++17(clang)、C++14、C++11、C++11(gcc12)、C++11(old_compat)
GMP のヘッダは入っていますが、コンパイルコマンドにリンクの指定が無いので、mpz_class はリンクエラーになります。
64 ビット整数(比べる用)
long long 言語の機能
11〜12 ms
コード
#include <iostream>
using namespace std;
int main() {
long long m, x = 2;
cin >> m;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << x << "\n";
}
多倍長整数(64 ビットに収まる値)
boost::multiprecision::cpp_int 外部ライブラリ
24〜33 ms(C++ の 1.0〜1.3 倍)
動かない: C++11、C++11(gcc12)、C++11(old_compat)
コード
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
using boost::multiprecision::cpp_int;
using namespace std;
int main() {
cpp_int m, x = 2;
cin >> m;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << x << "\n";
}
128 ビット整数
__int128 言語の機能
24〜42 ms
コード
#include <iostream>
#include <string>
using namespace std;
__extension__ typedef __int128 i128;
string str(i128 v) {
if (v == 0) return "0";
string s;
while (v > 0) {
s.insert(s.begin(), char('0' + int(v % 10)));
v /= 10;
}
return s;
}
int main() {
string s;
cin >> s;
i128 n = 0, a = 1;
for (char c : s) n = n * 10 + (c - '0');
for (int i = 0; i < 126; i++) a = a * 2 + 1;
i128 b = n * 1000000;
cout << str(a) << "\n" << str(b / 7) << "\n" << str(b % 1000000007) << "\n" << str(n) << "\n";
i128 m = n / 1000000 + 9, x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << str(x) << "\n";
}
boost::multiprecision::int128_t 外部ライブラリ
24〜25 ms
動かない: C++11、C++11(gcc12)、C++11(old_compat)
コード
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
using boost::multiprecision::int128_t;
using namespace std;
int main() {
int128_t n, a = 1;
cin >> n;
for (int i = 0; i < 126; i++) a = a * 2 + 1;
int128_t b = n * 1000000;
cout << a << "\n" << b / 7 << "\n" << b % 1000000007 << "\n" << n << "\n";
int128_t m = n / 1000000 + 9, x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << x << "\n";
}
仕組み: __int128 の掛け算は、64 ビットどうしの積を 128 ビットで出す x86-64 の mul 命令などになります。128 ビットを 128 ビットで割る命令は無いので、割り算と余りはライブラリの関数(__modti3 など)を呼びます(g++ 15・clang++ で確認)。
多倍長整数
boost::multiprecision::cpp_int 外部ライブラリ
55〜62 ms(C++ の 1.0〜1.1 倍)
動かない: C++11、C++11(gcc12)、C++11(old_compat)
コード
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
using boost::multiprecision::cpp_int;
using namespace std;
int main() {
cpp_int n, f = 1;
cin >> n;
for (int i = 1; i <= 200; i++) f *= i;
cpp_int m = n / 1000000 + 9;
cpp_int x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << f << "\n" << f / n << "\n" << x << "\n";
}
cLay
64 ビット整数(比べる用)
long long 言語の機能
11 ms
コード
{
long long m;
cin >> m;
long long x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << x << "\n";
}
多倍長整数(64 ビットに収まる値)
boost::multiprecision::cpp_int 外部ライブラリ
22 ms(C++ の 0.9 倍)
コード
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
using boost::multiprecision::cpp_int;
using namespace std;
int main() {
cpp_int m, x = 2;
cin >> m;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << x << "\n";
}
128 ビット整数
__int128 言語の機能
25 ms
コード
string str(__int128 v) {
if (v == 0) return "0";
string s;
while (v > 0) {
s.insert(s.begin(), char('0' + int(v % 10)));
v /= 10;
}
return s;
}
{
string s;
cin >> s;
__int128 n = 0;
__int128 a = 1;
for (char c : s) n = n * 10 + (c - '0');
for (int i = 0; i < 126; i++) a = a * 2 + 1;
__int128 b = n * 1000000;
cout << str(a) << "\n" << str(b / 7) << "\n" << str(b % 1000000007) << "\n" << str(n) << "\n";
__int128 m = n / 1000000 + 9;
__int128 x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << str(x) << "\n";
}
仕組み: C++ に変換して g++ 15 でコンパイルするので、__int128 は C++ と同じです。掛け算は mul 命令などになり、割り算と余りはライブラリの関数(__modti3 など)を呼びます。
多倍長整数
boost::multiprecision::cpp_int 外部ライブラリ
56 ms(C++ の 1.0 倍)
コード
#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>
using boost::multiprecision::cpp_int;
using namespace std;
int main() {
cpp_int n, f = 1;
cin >> n;
for (int i = 1; i <= 200; i++) f *= i;
cpp_int m = n / 1000000 + 9;
cpp_int x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
cout << f << "\n" << f / n << "\n" << x << "\n";
}
C
C、C(gnu17)、C11(gcc12 gnu拡張)、C90、C90(gcc12)
64 ビット整数(比べる用)
long long 言語の機能
12 ms
コード
#include <stdio.h>
int main(void) {
long long m, x = 2;
int i;
if (scanf("%lld", &m) != 1) return 1;
for (i = 0; i < 1000000; i++) x = (x * x + 1) % m;
printf("%lld\n", x);
return 0;
}
128 ビット整数
__int128 言語の機能
25〜26 ms
コード
#include <stdio.h>
__extension__ typedef __int128 i128;
static void put(i128 v) {
char buf[64];
int n = 0;
if (v == 0) buf[n++] = '0';
while (v > 0) {
buf[n++] = (char)('0' + (int)(v % 10));
v /= 10;
}
while (n > 0) putchar(buf[--n]);
putchar('\n');
}
int main(void) {
char s[64];
int i;
i128 n = 0, a = 1, b, m, x = 2;
if (scanf("%63s", s) != 1) return 1;
for (i = 0; s[i]; i++) n = n * 10 + (s[i] - '0');
for (i = 0; i < 126; i++) a = a * 2 + 1;
b = n * 1000000;
put(a);
put(b / 7);
put(b % 1000000007);
put(n);
m = n / 1000000 + 9;
for (i = 0; i < 1000000; i++) x = (x * x + 1) % m;
put(x);
return 0;
}
仕組み: __int128 の掛け算は、64 ビットどうしの積を 128 ビットで出す x86-64 の mul 命令などになります。128 ビットを 128 ビットで割る命令は無いので、割り算と余りはライブラリの関数(__modti3 など)を呼びます(gcc 15 で確認)。
多倍長整数
Java
64 ビット整数(比べる用)
long 言語の機能
15 ms
コード
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
long m = new Scanner(System.in).nextLong();
long x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
System.out.println(x);
}
}
多倍長整数(64 ビットに収まる値)
java.math.BigInteger 標準ライブラリ
223 ms(C++ の 8.9 倍)
コード
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BigInteger m = new Scanner(System.in).nextBigInteger();
BigInteger x = BigInteger.TWO;
for (int i = 0; i < 1000000; i++) x = x.multiply(x).add(BigInteger.ONE).mod(m);
System.out.println(x);
}
}
128 ビット整数
128 ビットの積
Math.multiplyHigh 標準ライブラリ
80 ms
コード
import java.util.Scanner;
public class Main {
// (hi, lo) を m で割った余り。hi < m のときに使える。128 / 64 の割り算が無いので 1 ビットずつ引く
static long rem(long hi, long lo, long m) {
for (int i = 0; i < 64; i++) {
hi = (hi << 1) | (lo >>> 63);
lo <<= 1;
if (Long.compareUnsigned(hi, m) >= 0) hi -= m;
}
return hi;
}
public static void main(String[] args) {
long m = new Scanner(System.in).nextLong();
long x = 2;
for (int i = 0; i < 1000000; i++) {
// x * x + 1 を 64 ビット 2 つ(hi, lo)で持つ
long hi = Math.multiplyHigh(x, x);
long lo = x * x + 1;
if (lo == 0) hi++;
x = rem(hi, lo, m);
}
System.out.println(x);
}
}
仕組み: Math.multiplyHigh は、JIT が組み込みの処理(intrinsic)に置き換えます。余りは、このプログラムでは 1 ビットずつ引いて出しています。
多倍長整数
java.math.BigInteger 標準ライブラリ
495 ms(C++ の 8.8 倍)
コード
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BigInteger n = new Scanner(System.in).nextBigInteger(), f = BigInteger.ONE;
for (int i = 1; i <= 200; i++) f = f.multiply(BigInteger.valueOf(i));
BigInteger m = n.divide(BigInteger.valueOf(1000000)).add(BigInteger.valueOf(9));
BigInteger x = BigInteger.TWO;
for (int i = 0; i < 1000000; i++) x = x.multiply(x).add(BigInteger.ONE).mod(m);
System.out.println(f);
System.out.println(f.divide(n));
System.out.println(x);
}
}
C#
C#、C#(csc)
64 ビット整数(比べる用)
long 言語の機能
12〜13 ms
コード
using System;
class Program {
static void Main() {
long m = long.Parse(Console.ReadLine().Trim()), x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
Console.WriteLine(x);
}
}
多倍長整数(64 ビットに収まる値)
System.Numerics.BigInteger 標準ライブラリ
80〜139 ms(C++ の 3.2〜5.6 倍)
コード
using System;
using System.Numerics;
class Program {
static void Main() {
BigInteger m = BigInteger.Parse(Console.ReadLine().Trim()), x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
Console.WriteLine(x);
}
}
128 ビット整数
System.Int128 標準ライブラリ
38 ms
動かない: C#(csc)
コード
using System;
class Program {
static void Main() {
Int128 n = Int128.Parse(Console.ReadLine().Trim()), a = 1;
for (int i = 0; i < 126; i++) a = a * 2 + 1;
Int128 b = n * 1000000;
Console.WriteLine(a);
Console.WriteLine(b / 7);
Console.WriteLine(b % 1000000007);
Console.WriteLine(n);
Int128 m = n / 1000000 + 9, x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
Console.WriteLine(x);
}
}
仕組み: System.Int128 は、64 ビットの整数 2 つ(_lower・_upper)を並べた構造体です。csharp_dotnet(.NET 10)では、掛け算は 64 ビットの掛け算を組み合わせて計算し、余りは割り算(Int128.op_Division)を呼んで出します(JIT の出力で確認)。csharp(Mono)では System.Int128 をコンパイルできません。
多倍長整数
System.Numerics.BigInteger 標準ライブラリ
252〜391 ms(C++ の 4.5〜7.0 倍)
コード
using System;
using System.Numerics;
class Program {
static void Main() {
BigInteger n = BigInteger.Parse(Console.ReadLine().Trim()), f = 1;
for (int i = 1; i <= 200; i++) f *= i;
BigInteger m = n / 1000000 + 9, x = 2;
for (int i = 0; i < 1000000; i++) x = (x * x + 1) % m;
Console.WriteLine(f);
Console.WriteLine(f / n);
Console.WriteLine(x);
}
}
F#
64 ビット整数(比べる用)
int64 言語の機能
15 ms
コード
open System
let m = Int64.Parse(Console.ReadLine().Trim())
let mutable x = 2L
for _ in 1 .. 1000000 do
x <- (x * x + 1L) % m
printfn "%d" x
多倍長整数(64 ビットに収まる値)
bigint 言語の機能
92 ms(C++ の 3.7 倍)
コード
open System
let m = bigint.Parse(Console.ReadLine().Trim())
let mutable x = 2I
for _ in 1 .. 1000000 do
x <- (x * x + 1I) % m
printfn "%s" (x.ToString())
128 ビット整数
System.Int128 標準ライブラリ
70 ms
コード
open System
let n = Int128.Parse(Console.ReadLine().Trim())
let mutable a = Int128.One
for _ in 1 .. 126 do
a <- a * Int128.op_Implicit 2 + Int128.One
let b = n * Int128.op_Implicit 1000000
printfn "%s" (a.ToString())
printfn "%s" ((b / Int128.op_Implicit 7).ToString())
printfn "%s" ((b % Int128.op_Implicit 1000000007).ToString())
printfn "%s" (n.ToString())
let m = n / Int128.op_Implicit 1000000 + Int128.op_Implicit 9
let mutable x = Int128.op_Implicit 2
for _ in 1 .. 1000000 do
x <- (x * x + Int128.One) % m
printfn "%s" (x.ToString())
仕組み: C# と同じ .NET の System.Int128(64 ビットの整数 2 つを並べた構造体)です。F# での JIT の出力は確かめていません。
多倍長整数
bigint 言語の機能
255 ms(C++ の 4.6 倍)
コード
open System
let n = bigint.Parse(Console.ReadLine().Trim())
let f = List.fold (fun acc i -> acc * bigint (i: int)) 1I [ 1 .. 200 ]
let m = n / 1000000I + 9I
let mutable x = 2I
for _ in 1 .. 1000000 do
x <- (x * x + 1I) % m
printfn "%s" (f.ToString())
printfn "%s" ((f / n).ToString())
printfn "%s" (x.ToString())
Perl
64 ビット整数(比べる用)
数値(64 ビット整数) 言語の機能
47 ms
コード
use strict;
my $m = <STDIN> + 0;
my $x = 2;
for (1 .. 1000000) { $x = ($x * $x + 1) % $m; }
print "$x\n";
多倍長整数(64 ビットに収まる値)
Math::BigInt 標準ライブラリ
43950 ms(C++ の 1758 倍)
コード
use strict;
use Math::BigInt;
my $m = Math::BigInt->new(scalar <STDIN> =~ s/\s//gr);
my $x = Math::BigInt->new(2);
for (1 .. 1000000) {
$x->bmul($x)->badd(1)->bmod($m);
}
print $x->bstr, "\n";
128 ビット整数
多倍長整数
Math::BigInt 標準ライブラリ
51925 ms(C++ の 927 倍)
コード
use strict;
use Math::BigInt;
my $n = Math::BigInt->new(scalar <STDIN> =~ s/\s//gr);
my $f = Math::BigInt->new(1);
$f->bmul($_) for 1 .. 200;
my $m = $n->copy->bdiv(1000000)->badd(9);
my $x = Math::BigInt->new(2);
for (1 .. 1000000) {
$x->bmul($x)->badd(1)->bmod($m);
}
print $f->bstr, "\n", $f->copy->bdiv($n)->bstr, "\n", $x->bstr, "\n";
仕組み: 数値は 64 ビットの整数で持ち、符号付きの範囲を超えると符号無し 64 ビット、それも超えると浮動小数点数になります。自動で多倍長にはならないので、多倍長は Math::BigInt を使います。整数どうしの掛け算は、imul・mul 命令とあふれのフラグ(jo)で確かめ、あふれたら浮動小数点数の計算に移ります。
Raku
64 ビット整数(比べる用)
int(ネイティブ) 言語の機能
31 ms
コード
my int $m = get().trim.Int;
my int $x = 2;
for ^1000000 { $x = ($x * $x + 1) % $m; }
say $x;
多倍長整数(64 ビットに収まる値)
Int(自動で多倍長) 言語の機能
701 ms(C++ の 28 倍)
コード
my $m = get().trim.Int;
my $x = 2;
for ^1000000 { $x = ($x * $x + 1) % $m; }
say $x;
128 ビット整数
多倍長整数
Int(自動で多倍長) 言語の機能
866 ms(C++ の 15 倍)
コード
my $n = get().trim.Int;
my $f = [*] 1 .. 200;
my $m = $n div 1000000 + 9;
my $x = 2;
for ^1000000 { $x = ($x * $x + 1) % $m; }
say $f;
say $f div $n;
say $x;
仕組み: Int は大きさに上限が無く、自動で多倍長になります。型を int(ネイティブ)にすると 64 ビットで、あふれると負の値に回ります。MoarVM は、32 ビット(符号付き)に収まる小さい値を 32 ビットのまま持ち、2 つとも小さい値なら 64 ビットの掛け算(imul)で計算します。大きい値があれば、多倍長整数のライブラリ libtommath の掛け算(mp_mul)を呼びます。
PHP
64 ビット整数(比べる用)
int 言語の機能
18 ms
コード
<?php $m = (int)trim(fgets(STDIN)); $x = 2; for ($i = 0; $i < 1000000; $i++) $x = ($x * $x + 1) % $m; echo $x, "\n";
多倍長整数(64 ビットに収まる値)
BCMath 外部ライブラリ
470 ms(C++ の 19 倍)
コード
<?php $m = trim(fgets(STDIN)); $x = '2'; for ($i = 0; $i < 1000000; $i++) $x = bcmod(bcadd(bcmul($x, $x), '1'), $m); echo $x, "\n";
GMP 外部ライブラリ
207 ms(C++ の 8.3 倍)
コード
<?php $m = gmp_init(trim(fgets(STDIN))); $x = gmp_init(2); for ($i = 0; $i < 1000000; $i++) $x = gmp_mod(gmp_add(gmp_mul($x, $x), 1), $m); echo gmp_strval($x), "\n";
128 ビット整数
多倍長整数
BCMath 外部ライブラリ
653 ms(C++ の 12 倍)
コード
<?php $n = trim(fgets(STDIN)); $f = '1'; for ($i = 1; $i <= 200; $i++) $f = bcmul($f, (string)$i); $m = bcadd(bcdiv($n, '1000000', 0), '9'); $x = '2'; for ($i = 0; $i < 1000000; $i++) $x = bcmod(bcadd(bcmul($x, $x), '1'), $m); echo $f, "\n", bcdiv($f, $n, 0), "\n", $x, "\n";
GMP 外部ライブラリ
209 ms(C++ の 3.7 倍)
コード
<?php $n = gmp_init(trim(fgets(STDIN))); $f = gmp_init(1); for ($i = 1; $i <= 200; $i++) $f = gmp_mul($f, $i); $m = gmp_add(gmp_div_q($n, 1000000), 9); $x = gmp_init(2); for ($i = 0; $i < 1000000; $i++) $x = gmp_mod(gmp_add(gmp_mul($x, $x), 1), $m); echo gmp_strval($f), "\n", gmp_strval(gmp_div_q($f, $n)), "\n", gmp_strval($x), "\n";
仕組み: int は 64 ビットで、あふれると float(浮動小数点数)になります。自動で多倍長にはならないので、BCMath か GMP を使います。
Python
Python3、PyPy3、PyPy2
多倍長整数(64 ビットに収まる値)
int(自動で多倍長) 言語の機能
5〜253 ms(C++ の 0.2〜10 倍)
コード
import sys
m = int(sys.stdin.readline())
x = 2
for _ in range(1000000):
x = (x * x + 1) % m
print(x)
128 ビット整数
多倍長整数
int(自動で多倍長) 言語の機能
85〜410 ms(C++ の 1.5〜7.3 倍)
コード
import sys
n = int(sys.stdin.readline())
f = 1
for i in range(1, 201):
f *= i
m = n // 1000000 + 9
x = 2
for _ in range(1000000):
x = (x * x + 1) % m
print(f)
print(f // n)
print(x)
仕組み: Python 3 の int は大きさに上限の無い 1 つの型です。CPython は値を 30 ビットずつの桁に分けて持ちます。PyPy は値が 64 ビットに収まる間は機械の整数(W_IntObject)で計算し、収まらなくなると多倍長(W_LongObject)に切り替えます。PyPy 2 では、切り替わると型も int から long に変わります。PyPy の JIT は、掛け算・足し算のたびにあふれを確かめる処理(int_mul_ovf・guard_no_overflow)を入れ、あふれたときだけ多倍長の処理に移ります。CPython の掛け算は、2 つとも 1 桁(30 ビット以下)なら 64 ビットの掛け算 1 回で計算します(積は 60 ビットに収まるので、あふれの確認は要りません)。
Ruby
多倍長整数(64 ビットに収まる値)
Integer(自動で多倍長) 言語の機能
52 ms(C++ の 2.1 倍)
コード
m = gets.to_i
x = 2
1000000.times { x = (x * x + 1) % m }
puts x
128 ビット整数
多倍長整数
Integer(自動で多倍長) 言語の機能
336 ms(C++ の 6.0 倍)
コード
n = gets.to_i
f = (1..200).inject(:*)
m = n / 1000000 + 9
x = 2
1000000.times { x = (x * x + 1) % m }
puts f, f / n, x
仕組み: Integer は 1 つの型です。2^62 - 1 までの値はオブジェクトを作らずにそのまま持ち、それより大きい値は多倍長のオブジェクトを作ります。掛け算では、2 つの値の印(最下位のビット)で小さい整数(2^62 - 1 まで)かを確かめ、imul 命令で 128 ビットの積を出して、小さい整数の範囲に収まるかを比べます。収まるときだけ、そのまま小さい整数として返します。
D
64 ビット整数(比べる用)
long 言語の機能
11 ms
コード
import std.stdio, std.string, std.conv;
void main() {
long m = readln.strip.to!long, x = 2;
foreach (i; 0 .. 1000000) x = (x * x + 1) % m;
writeln(x);
}
多倍長整数(64 ビットに収まる値)
std.bigint.BigInt 標準ライブラリ
456 ms(C++ の 18 倍)
コード
import std.bigint, std.stdio, std.string;
void main() {
BigInt m = BigInt(readln.strip), x = 2;
foreach (i; 0 .. 1000000) x = (x * x + 1) % m;
writeln(x);
}
128 ビット整数
std.int128.Int128 標準ライブラリ
48 ms
コード
import std.int128, std.stdio, std.string, std.conv;
string str(Int128 v) {
if (v == Int128(0L)) return "0";
string s;
while (v > Int128(0L)) {
s = to!string((v % Int128(10L)).data.lo) ~ s;
v = v / Int128(10L);
}
return s;
}
void main() {
Int128 n = Int128(0L), a = Int128(1L);
foreach (c; readln.strip) n = n * Int128(10L) + Int128(cast(long)(c - '0'));
foreach (i; 0 .. 126) a = a * Int128(2L) + Int128(1L);
Int128 b = n * Int128(1000000L);
writeln(str(a));
writeln(str(b / Int128(7L)));
writeln(str(b % Int128(1000000007L)));
writeln(str(n));
Int128 m = n / Int128(1000000L) + Int128(9L), x = Int128(2L);
foreach (i; 0 .. 1000000) x = (x * x + Int128(1L)) % m;
writeln(str(x));
}
仕組み: std.int128.Int128 は、druntime の core.int128 が 64 ビットの整数を組み合わせて計算します。掛け算は 64 ビットの掛け算を何回か組み合わせ、割り算と余りは core.int128.divmod を呼びます。
多倍長整数
std.bigint.BigInt 標準ライブラリ
726 ms(C++ の 13 倍)
コード
import std.bigint, std.stdio, std.string;
void main() {
BigInt n = BigInt(readln.strip), f = 1;
foreach (i; 1 .. 201) f *= i;
BigInt m = n / 1000000 + 9, x = 2;
foreach (i; 0 .. 1000000) x = (x * x + 1) % m;
writeln(f);
writeln(f / n);
writeln(x);
}
Go
64 ビット整数(比べる用)
int64 言語の機能
12 ms
コード
package main
import "fmt"
func main() {
var m int64
fmt.Scan(&m)
x := int64(2)
for i := 0; i < 1000000; i++ {
x = (x*x + 1) % m
}
fmt.Println(x)
}
多倍長整数(64 ビットに収まる値)
math/big.Int 標準ライブラリ
54 ms(C++ の 2.2 倍)
コード
package main
import (
"fmt"
"math/big"
)
func main() {
var s string
fmt.Scan(&s)
m, _ := new(big.Int).SetString(s, 10)
x, one, t := big.NewInt(2), big.NewInt(1), new(big.Int)
for i := 0; i < 1000000; i++ {
t.Mul(x, x)
t.Add(t, one)
x.Mod(t, m)
}
fmt.Println(x)
}
128 ビット整数
128 ビットの積
math/bits (Mul64, Add64, Rem64) 標準ライブラリ
30 ms
コード
package main
import (
"fmt"
"math/bits"
)
func main() {
var m uint64
fmt.Scan(&m)
x := uint64(2)
for i := 0; i < 1000000; i++ {
// x * x + 1 を 64 ビット 2 つ(hi, lo)で持ち、m で割った余りを出す
hi, lo := bits.Mul64(x, x)
lo, carry := bits.Add64(lo, 1, 0)
x = bits.Rem64(hi+carry, lo, m)
}
fmt.Println(x)
}
仕組み: bits.Mul64 は x86-64 の mul 命令(MULQ)に、bits.Rem64 は 128 ビットを 64 ビットで割る div 命令(DIVQ)になります。どちらもライブラリの関数を呼びません。
多倍長整数
math/big.Int 標準ライブラリ
107 ms(C++ の 1.9 倍)
コード
package main
import (
"fmt"
"math/big"
)
func main() {
var s string
fmt.Scan(&s)
n, _ := new(big.Int).SetString(s, 10)
f := big.NewInt(1)
for i := int64(1); i <= 200; i++ {
f.Mul(f, big.NewInt(i))
}
m := new(big.Int).Quo(n, big.NewInt(1000000))
m.Add(m, big.NewInt(9))
x, one, t := big.NewInt(2), big.NewInt(1), new(big.Int)
for i := 0; i < 1000000; i++ {
t.Mul(x, x)
t.Add(t, one)
x.Mod(t, m)
}
fmt.Println(f)
fmt.Println(new(big.Int).Quo(f, n))
fmt.Println(x)
}
Haskell
64 ビット整数(比べる用)
Int 言語の機能
14 ms
コード
import Data.List (foldl') main :: IO () main = do m <- readLn :: IO Int let x = foldl' (\v _ -> (v * v + 1) `mod` m) 2 [1 .. 1000000 :: Int] print x
多倍長整数(64 ビットに収まる値)
Integer 言語の機能
28 ms(C++ の 1.1 倍)
コード
import Data.List (foldl') main :: IO () main = do m <- readLn :: IO Integer let x = foldl' (\v _ -> (v * v + 1) `mod` m) 2 [1 .. 1000000 :: Int] print x
128 ビット整数
多倍長整数
Integer 言語の機能
49 ms(C++ の 0.9 倍)
コード
import Data.List (foldl')
main :: IO ()
main = do
n <- readLn :: IO Integer
let f = product [1 .. 200] :: Integer
m = n `div` 1000000 + 9
x = foldl' (\v _ -> (v * v + 1) `mod` m) 2 [1 .. 1000000 :: Int]
print f
print (f `div` n)
print x
仕組み: Int は 64 ビットです。Integer は、値が Int(64 ビット)に収まる間は Int と同じ形(IS)で持ち、収まらなくなると多倍長(IP・IN)に切り替わります。Integer の掛け算は、2 つとも IS のとき imul 命令で積を出し、あふれのフラグを見て、収まれば IS のまま返します。
Scala
64 ビット整数(比べる用)
Long 言語の機能
15 ms
コード
object Main {
def main(args: Array[String]): Unit = {
val m = scala.io.StdIn.readLine().trim.toLong
var x = 2L
var i = 0
while (i < 1000000) {
x = (x * x + 1) % m
i += 1
}
println(x)
}
}
多倍長整数(64 ビットに収まる値)
BigInt 標準ライブラリ
62 ms(C++ の 2.5 倍)
コード
object Main {
def main(args: Array[String]): Unit = {
val m = BigInt(scala.io.StdIn.readLine().trim)
var x = BigInt(2)
for (_ <- 0 until 1000000) x = (x * x + 1) % m
println(x)
}
}
128 ビット整数
128 ビットの積
Math.multiplyHigh 標準ライブラリ
79 ms
コード
object Main {
// (hi, lo) を m で割った余り。hi < m のときに使える。128 / 64 の割り算が無いので 1 ビットずつ引く
def rem(hi0: Long, lo0: Long, m: Long): Long = {
var hi = hi0
var lo = lo0
var i = 0
while (i < 64) {
hi = (hi << 1) | (lo >>> 63)
lo <<= 1
if (java.lang.Long.compareUnsigned(hi, m) >= 0) hi -= m
i += 1
}
hi
}
def main(args: Array[String]): Unit = {
val m = scala.io.StdIn.readLine().trim.toLong
var x = 2L
var i = 0
while (i < 1000000) {
// x * x + 1 を 64 ビット 2 つ(hi, lo)で持つ
var hi = java.lang.Math.multiplyHigh(x, x)
val lo = x * x + 1
if (lo == 0L) hi += 1
x = rem(hi, lo, m)
i += 1
}
println(x)
}
}
仕組み: Java と同じ JVM で動くので、Math.multiplyHigh は Java と同じく JIT の組み込みの処理(intrinsic)になります。余りは、このプログラムでは 1 ビットずつ引いて出しています。
多倍長整数
BigInt 標準ライブラリ
615 ms(C++ の 11 倍)
コード
object Main {
def main(args: Array[String]): Unit = {
val n = BigInt(scala.io.StdIn.readLine().trim)
val f = (1 to 200).foldLeft(BigInt(1))(_ * _)
val m = n / 1000000 + 9
var x = BigInt(2)
for (_ <- 0 until 1000000) x = (x * x + 1) % m
println(f)
println(f / n)
println(x)
}
}
Nim
64 ビット整数(比べる用)
int64 言語の機能
12 ms
コード
import std/strutils proc main() = let m = stdin.readLine().strip().parseBiggestInt().int64 var x = 2'i64 for _ in 1 .. 1000000: x = (x * x + 1) mod m echo x main()
128 ビット整数
__int128 (importc) 言語の機能
26 ms
コード
import std/strutils
# 判定の Nim は C++ に変換してコンパイルするので、__int128 をそのまま使う
type I128 {.importc: "__int128", nodecl.} = object
proc toI128(v: int64): I128 {.importc: "(__int128)", nodecl.}
proc lowDigit(v: I128): cint {.importc: "(int)", nodecl.}
proc `+`(a, b: I128): I128 {.importcpp: "(# + #)", nodecl.}
proc `*`(a, b: I128): I128 {.importcpp: "(# * #)", nodecl.}
proc `/`(a, b: I128): I128 {.importcpp: "(# / #)", nodecl.}
proc `%`(a, b: I128): I128 {.importcpp: "(# % #)", nodecl.}
proc `>`(a, b: I128): bool {.importcpp: "(# > #)", nodecl.}
proc str(value: I128): string =
var v = value
if not (v > toI128(0)): return "0"
while v > toI128(0):
result = $lowDigit(v % toI128(10)) & result
v = v / toI128(10)
proc main() =
let s = stdin.readLine().strip()
var n = toI128(0)
for c in s: n = n * toI128(10) + toI128(int64(ord(c) - ord('0')))
var a = toI128(1)
for _ in 1 .. 126: a = a * toI128(2) + toI128(1)
let b = n * toI128(1000000)
echo str(a)
echo str(b / toI128(7))
echo str(b % toI128(1000000007))
echo str(n)
let m = n / toI128(1000000) + toI128(9)
var x = toI128(2)
for _ in 1 .. 1000000: x = (x * x + toI128(1)) % m
echo str(x)
main()
仕組み: C++ に変換して __int128 をそのまま使います。割り算と余りはライブラリの関数(__modti3 など)を呼びます。
多倍長整数
Rust
64 ビット整数(比べる用)
i64 言語の機能
12 ms
コード
use std::io::*;
fn main() {
let mut s = String::new();
stdin().read_to_string(&mut s).unwrap();
let m: i64 = s.trim().parse().unwrap();
let mut x: i64 = 2;
for _ in 0..1000000 {
x = (x * x + 1) % m;
}
println!("{}", x);
}
多倍長整数(64 ビットに収まる値)
num::BigInt 外部ライブラリ
19 ms(C++ の 0.8 倍)
コード
use num::BigInt;
use std::io::*;
fn main() {
let mut s = String::new();
stdin().read_to_string(&mut s).unwrap();
let m: BigInt = s.trim().parse().unwrap();
let mut x = BigInt::from(2);
for _ in 0..1000000 {
x = (&x * &x + 1) % &m;
}
println!("{}", x);
}
128 ビット整数
i128 言語の機能
28 ms
コード
use std::io::*;
fn main() {
let mut s = String::new();
stdin().read_to_string(&mut s).unwrap();
let n: i128 = s.trim().parse().unwrap();
let mut a: i128 = 1;
for _ in 0..126 {
a = a * 2 + 1;
}
let b = n * 1000000;
let m = n / 1000000 + 9;
let mut x: i128 = 2;
for _ in 0..1000000 {
x = (x * x + 1) % m;
}
println!("{}\n{}\n{}\n{}\n{}", a, b / 7, b % 1000000007, n, x);
}
仕組み: i128 の掛け算は、64 ビットどうしの積を 128 ビットで出す mul 命令などになります。割り算と余りは、プログラムに入るライブラリの関数(__modti3 など)を呼びます。
多倍長整数
num::BigInt 外部ライブラリ
81 ms(C++ の 1.4 倍)
コード
use num::BigInt;
use std::io::*;
fn main() {
let mut s = String::new();
stdin().read_to_string(&mut s).unwrap();
let n: BigInt = s.trim().parse().unwrap();
let mut f = BigInt::from(1);
for i in 1..=200 {
f *= i;
}
let m = &n / 1000000 + 9;
let mut x = BigInt::from(2);
for _ in 0..1000000 {
x = (&x * &x + 1) % &m;
}
println!("{}\n{}\n{}", f, &f / &n, x);
}
Kotlin
64 ビット整数(比べる用)
Long 言語の機能
23 ms
コード
fun main() {
val m = readLine()!!.trim().toLong()
var x = 2L
repeat(1000000) {
x = (x * x + 1) % m
}
println(x)
}
多倍長整数(64 ビットに収まる値)
java.math.BigInteger 標準ライブラリ
246 ms(C++ の 9.8 倍)
コード
import java.math.BigInteger
fun main() {
val m = BigInteger(readLine()!!.trim())
var x = 2.toBigInteger()
repeat(1000000) { x = (x * x + BigInteger.ONE).mod(m) }
println(x)
}
128 ビット整数
128 ビットの積
Math.multiplyHigh 標準ライブラリ
81 ms
コード
// (hi, lo) を m で割った余り。hi < m のときに使える。128 / 64 の割り算が無いので 1 ビットずつ引く
fun rem(hi0: Long, lo0: Long, m: Long): Long {
var hi = hi0
var lo = lo0
repeat(64) {
hi = (hi shl 1) or (lo ushr 63)
lo = lo shl 1
if (java.lang.Long.compareUnsigned(hi, m) >= 0) hi -= m
}
return hi
}
fun main() {
val m = readLine()!!.trim().toLong()
var x = 2L
repeat(1000000) {
// x * x + 1 を 64 ビット 2 つ(hi, lo)で持つ
var hi = Math.multiplyHigh(x, x)
val lo = x * x + 1
if (lo == 0L) hi++
x = rem(hi, lo, m)
}
println(x)
}
仕組み: Java と同じ JVM で動くので、Math.multiplyHigh は Java と同じく JIT の組み込みの処理(intrinsic)になります。余りは、このプログラムでは 1 ビットずつ引いて出しています。
多倍長整数
java.math.BigInteger 標準ライブラリ
462 ms(C++ の 8.2 倍)
コード
import java.math.BigInteger
fun main() {
val n = BigInteger(readLine()!!.trim())
var f = BigInteger.ONE
for (i in 1..200) f *= i.toBigInteger()
val m = n / 1000000.toBigInteger() + 9.toBigInteger()
var x = 2.toBigInteger()
repeat(1000000) { x = (x * x + BigInteger.ONE).mod(m) }
println(f)
println(f / n)
println(x)
}
Scheme
多倍長整数(64 ビットに収まる値)
整数(自動で多倍長) 言語の機能
58 ms(C++ の 2.3 倍)
コード
(define m (read)) (define (loop i x) (if (= i 1000000) x (loop (+ i 1) (modulo (+ (* x x) 1) m)))) (print (loop 0 2))
128 ビット整数
多倍長整数
整数(自動で多倍長) 言語の機能
768 ms(C++ の 14 倍)
コード
(define n (read)) (define (fact i acc) (if (> i 200) acc (fact (+ i 1) (* acc i)))) (define f (fact 1 1)) (define m (+ (quotient n 1000000) 9)) (define (loop i x) (if (= i 1000000) x (loop (+ i 1) (modulo (+ (* x x) 1) m)))) (print f) (print (quotient f n)) (print (loop 0 2))
仕組み: 整数は 2^61 - 1 まで fixnum(そのまま持つ整数)で、それを超えると自動で多倍長(bignum)になります(Gauche)。掛け算は、値の印(下位 2 ビット)で fixnum(2^61 - 1 まで)かを確かめ、imul 命令とあふれのフラグ(jno)で収まるかを確かめます。収まらなければ bignum を作ります。
Crystal
64 ビット整数(比べる用)
Int64 言語の機能
12 ms
コード
m = STDIN.gets.not_nil!.strip.to_i64
x = 2_i64
1000000.times { x = (x * x + 1) % m }
puts x
多倍長整数(64 ビットに収まる値)
BigInt (require "big") 標準ライブラリ
302 ms(C++ の 12 倍)
コード
require "big"
m = STDIN.gets.not_nil!.strip.to_big_i
x = BigInt.new(2)
1000000.times { x = (x * x + 1) % m }
puts x
128 ビット整数
Int128 言語の機能
38 ms
コード
n = STDIN.gets.not_nil!.strip.to_i128
a = 1_i128
126.times { a = a * 2 + 1 }
b = n * 1000000
m = n // 1000000 + 9
x = 2_i128
1000000.times { x = (x * x + 1) % m }
puts a, b // 7, b % 1000000007, n, x
仕組み: Int128 の掛け算は mul 命令などで、あふれていないかを確かめながら計算します。余りは、Crystal の標準ライブラリにある __modti3 を呼びます。
多倍長整数
BigInt (require "big") 標準ライブラリ
299 ms(C++ の 5.3 倍)
コード
require "big"
n = STDIN.gets.not_nil!.strip.to_big_i
f = BigInt.new(1)
(1..200).each { |i| f *= i }
m = n // 1000000 + 9
x = BigInt.new(2)
1000000.times { x = (x * x + 1) % m }
puts f, f // n, x
Swift
64 ビット整数(比べる用)
Int 言語の機能
12 ms
コード
func repeatSquare(_ m: Int) -> Int {
var x = 2
for _ in 0..<1000000 { x = (x * x + 1) % m }
return x
}
print(repeatSquare(Int(readLine()!)!))
128 ビット整数
Int128 標準ライブラリ
25 ms
コード
let n = Int128(readLine()!)!
var a: Int128 = 1
for _ in 0..<126 { a = a * 2 + 1 }
let b = n * 1000000
print(a)
print(b / 7)
print(b % 1000000007)
print(n)
func repeatSquare(_ m: Int128) -> Int128 {
var x: Int128 = 2
for _ in 0..<1000000 { x = (x * x + 1) % m }
return x
}
print(repeatSquare(n / 1000000 + 9))
仕組み: Int128 の掛け算は、64 ビットどうしの積を 128 ビットで出す mul 命令などになります。余りはライブラリの関数(__modti3)を呼びます。
多倍長整数
OCaml
64 ビット整数(比べる用)
int(63 ビット) 言語の機能
13 ms
コード
let () =
let m = int_of_string (String.trim (input_line stdin)) in
let x = ref 2 in
for _ = 1 to 1000000 do
x := (!x * !x + 1) mod m
done;
print_endline (string_of_int !x)
多倍長整数(64 ビットに収まる値)
Z (Zarith) 外部ライブラリ
17 ms(C++ の 0.7 倍)
コード
let () =
let m = Z.of_string (String.trim (input_line stdin)) in
let x = ref (Z.of_int 2) in
for _ = 1 to 1000000 do
x := Z.erem (Z.add (Z.mul !x !x) Z.one) m
done;
print_endline (Z.to_string !x)
128 ビット整数
多倍長整数
Z (Zarith) 外部ライブラリ
90 ms(C++ の 1.6 倍)
コード
let () =
let n = Z.of_string (String.trim (input_line stdin)) in
let f = ref Z.one in
for i = 1 to 200 do f := Z.mul !f (Z.of_int i) done;
let m = Z.add (Z.div n (Z.of_int 1000000)) (Z.of_int 9) in
let x = ref (Z.of_int 2) in
for _ = 1 to 1000000 do
x := Z.erem (Z.add (Z.mul !x !x) Z.one) m
done;
print_endline (Z.to_string !f);
print_endline (Z.to_string (Z.div !f n));
print_endline (Z.to_string !x)
仕組み: int は 63 ビット(最大 2^62 - 1)で、自動で多倍長にはなりません。Zarith の Z は、値が int(2^62 - 1 まで)に収まる間は int のまま持ち、収まらなくなると多倍長に切り替わります。Z.mul は、2 つとも int のとき imul 命令とあふれのフラグ(jo)で積が収まるかを確かめ、収まれば int のまま計算します。収まらなければ C の関数を呼びます。
Clojure
Clojure(Beta)
64 ビット整数(比べる用)
long 言語の機能
81 ms
コード
(let [m (Long/parseLong (clojure.string/trim (read-line)))
x (loop [i 0 v 2]
(if (= i 1000000) v (recur (inc i) (mod (+ (* v v) 1) m))))]
(println x))
多倍長整数(64 ビットに収まる値)
bigint 言語の機能
51 ms(C++ の 2.0 倍)
コード
(let [m (bigint (clojure.string/trim (read-line)))
x (loop [i 0 v 2N]
(if (= i 1000000) v (recur (inc i) (mod (+' (*' v v) 1N) m))))]
(println (str x)))
128 ビット整数
多倍長整数
bigint 言語の機能
735 ms(C++ の 13 倍)
コード
(let [n (bigint (clojure.string/trim (read-line)))
f (reduce *' 1N (range 1 201))
m (+' (quot n 1000000N) 9N)
x (loop [i 0 v 2N]
(if (= i 1000000) v (recur (inc i) (mod (+' (*' v v) 1N) m))))]
(println (str f))
(println (str (quot f n)))
(println (str x)))
仕組み: 整数は long(64 ビット)で、* はあふれると例外(long overflow)になります。*' や +' を使うと、あふれたときに自動で多倍長(BigInt)になります。BigInt は、値が long(64 ビット)に収まる間は long で持ちます。* は Math.multiplyExact を呼ぶので、あふれると例外になります。*' は、掛けた結果を割り戻して元の値に戻るかで、あふれを確かめます。
Elixir
多倍長整数(64 ビットに収まる値)
整数(自動で多倍長) 言語の機能
37 ms(C++ の 1.5 倍)
コード
defmodule Main do
def main do
m = IO.gets("") |> String.trim() |> String.to_integer()
x = Enum.reduce(1..1000000//1, 2, fn _, v -> rem(v * v + 1, m) end)
IO.puts(x)
end
end
128 ビット整数
多倍長整数
整数(自動で多倍長) 言語の機能
127 ms(C++ の 2.3 倍)
コード
defmodule Main do
def main do
n = IO.gets("") |> String.trim() |> String.to_integer()
f = Enum.reduce(1..200, 1, fn i, acc -> acc * i end)
m = div(n, 1000000) + 9
x = Enum.reduce(1..1000000//1, 2, fn _, v -> rem(v * v + 1, m) end)
IO.puts(f)
IO.puts(div(f, n))
IO.puts(x)
end
end
仕組み: 整数は 1 つの型です。2^59 - 1 までの値はそのまま持ち、それより大きい値は多倍長としてヒープに置きます(Erlang/OTP 29)。掛け算は、2 つの値の印で小さい整数(2^59 - 1 まで)かを確かめてから imul 命令で計算し、あふれのフラグ(jo)が立てば別の処理に移ります(BEAM の JIT の出力で確認)。
Lua
128 ビット整数
多倍長整数
Julia
64 ビット整数(比べる用)
Int64 言語の機能
0 ms
コード
function repeat_square(m::Int64)
x = Int64(2)
for _ in 1:1000000
x = mod(x * x + 1, m)
end
return x
end
println(repeat_square(parse(Int64, strip(readline()))))
多倍長整数(64 ビットに収まる値)
BigInt 標準ライブラリ
404 ms(C++ の 16 倍)
コード
function repeat_square(m::BigInt)
x = big(2)
for _ in 1:1000000
x = mod(x * x + 1, m)
end
return x
end
println(repeat_square(parse(BigInt, strip(readline()))))
128 ビット整数
Int128 言語の機能
11 ms
コード
n = parse(Int128, strip(readline()))
a = Int128(1)
for _ in 1:126
global a = a * 2 + 1
end
b = n * 1000000
println(a)
println(div(b, 7))
println(rem(b, 1000000007))
println(n)
function repeat_square(m::Int128)
x = Int128(2)
for _ in 1:1000000
x = mod(x * x + 1, m)
end
return x
end
println(repeat_square(div(n, 1000000) + 9))
仕組み: Int128 の掛け算は mulx 命令などになります。mod はライブラリの関数(__divti3)を呼んで計算します。
多倍長整数
BigInt 標準ライブラリ
420 ms(C++ の 7.5 倍)
コード
function main()
n = parse(BigInt, strip(readline()))
f = factorial(big(200))
m = div(n, 1000000) + 9
x = big(2)
for _ in 1:1000000
x = mod(x * x + 1, m)
end
println(f)
println(div(f, n))
println(x)
end
main()
Fortran
64 ビット整数(比べる用)
integer(8) 言語の機能
11 ms
コード
program main
implicit none
integer, parameter :: q = 8
integer(q) :: m, x
integer :: i
read (*, *) m
x = 2
do i = 1, 1000000
x = mod(x*x + 1_q, m)
end do
print '(I0)', x
end program
128 ビット整数
integer(16) 言語の機能
26 ms
コード
program main
implicit none
integer, parameter :: q = 16
integer(q) :: n, a, b, m, x
integer :: i
read (*, *) n
a = 1
do i = 1, 126
a = a*2 + 1
end do
b = n*1000000_q
print '(I0)', a
print '(I0)', b/7_q
print '(I0)', mod(b, 1000000007_q)
print '(I0)', n
m = n/1000000_q + 9_q
x = 2
do i = 1, 1000000
x = mod(x*x + 1_q, m)
end do
print '(I0)', x
end program
仕組み: integer(16) の掛け算は、64 ビットどうしの積を 128 ビットで出す mul 命令などになります。mod はライブラリの関数(__modti3)を呼びます。
多倍長整数
JavaScript
JavaScript(Node)、JavaScript(Bun)
多倍長整数(64 ビットに収まる値)
BigInt 言語の機能
22〜66 ms(C++ の 0.9〜2.6 倍)
コード
const m = BigInt(require('fs').readFileSync(0, 'utf8').trim());
let x = 2n;
for (let i = 0; i < 1000000; i++) x = (x * x + 1n) % m;
console.log(x.toString());
128 ビット整数
多倍長整数
BigInt 言語の機能
92〜115 ms(C++ の 1.6〜2.1 倍)
コード
const n = BigInt(require('fs').readFileSync(0, 'utf8').trim());
let f = 1n;
for (let i = 1n; i <= 200n; i++) f *= i;
const m = n / 1000000n + 9n;
let x = 2n;
for (let i = 0; i < 1000000; i++) x = (x * x + 1n) % m;
console.log(f.toString());
console.log((f / n).toString());
console.log(x.toString());
仕組み: Number は浮動小数点数なので、整数を正しく持てるのは 2^53 - 1 までです(999999999 * 999999999 も正しく出ません)。そのため 64 ビット整数の列はありません。BigInt は別の型で、Number から自動で切り替わることはありません。
TypeScript
TypeScript(Node)、TypeScript(Bun)
多倍長整数(64 ビットに収まる値)
bigint 言語の機能
24〜59 ms(C++ の 1.0〜2.4 倍)
コード
declare const require: any;
const m: bigint = BigInt(require('fs').readFileSync(0, 'utf8').trim());
let x: bigint = 2n;
for (let i = 0; i < 1000000; i++) x = (x * x + 1n) % m;
console.log(x.toString());
128 ビット整数
多倍長整数
bigint 言語の機能
89〜115 ms(C++ の 1.6〜2.1 倍)
コード
declare const require: any;
const n: bigint = BigInt(require('fs').readFileSync(0, 'utf8').trim());
let f: bigint = 1n;
for (let i = 1n; i <= 200n; i++) f *= i;
const m: bigint = n / 1000000n + 9n;
let x: bigint = 2n;
for (let i = 0; i < 1000000; i++) x = (x * x + 1n) % m;
console.log(f.toString());
console.log((f / n).toString());
console.log(x.toString());
仕組み: 数値の型は JavaScript と同じです。number は浮動小数点数で、整数を正しく持てるのは 2^53 - 1 までなので、64 ビット整数の列はありません。bigint は別の型で、number から自動で切り替わることはありません。
Common Lisp
多倍長整数(64 ビットに収まる値)
整数(自動で多倍長) 言語の機能
15 ms(C++ の 0.6 倍)
コード
(let ((m (read))
(x 2))
(dotimes (i 1000000) (setf x (mod (+ (* x x) 1) m)))
(format t "~d~%" x))
128 ビット整数
多倍長整数
整数(自動で多倍長) 言語の機能
83 ms(C++ の 1.5 倍)
コード
(let* ((n (read))
(f (let ((r 1)) (loop for i from 1 to 200 do (setf r (* r i))) r))
(m (+ (floor n 1000000) 9))
(x 2))
(dotimes (i 1000000) (setf x (mod (+ (* x x) 1) m)))
(format t "~d~%~d~%~d~%" f (floor f n) x))
仕組み: 整数は 2^62 - 1 まで fixnum(そのまま持つ整数)で、それを超えると自動で多倍長(bignum)になります(SBCL)。掛け算(GENERIC-*)は、2 つの値の印(最下位のビット)で fixnum(2^62 - 1 まで)かを確かめ、imul 命令とあふれのフラグ(jo)で積が収まるかを確かめます。
Standard ML
64 ビット整数(比べる用)
Int64.int 標準ライブラリ
12 ms
コード
val SOME line = TextIO.inputLine TextIO.stdIn val SOME m = Int64.fromString line fun loop (i, x : Int64.int) = if i = 1000000 then x else loop (i + 1, (x * x + 1) mod m) val _ = print (Int64.toString (loop (0, 2)) ^ "\n")
多倍長整数(64 ビットに収まる値)
IntInf 標準ライブラリ
20 ms(C++ の 0.8 倍)
コード
val SOME line = TextIO.inputLine TextIO.stdIn val SOME m = IntInf.fromString line fun loop (i, x : IntInf.int) = if i = 1000000 then x else loop (i + 1, (x * x + 1) mod m) val _ = print (IntInf.toString (loop (0, 2)) ^ "\n")
128 ビット整数
多倍長整数
IntInf 標準ライブラリ
70 ms(C++ の 1.2 倍)
コード
val SOME line = TextIO.inputLine TextIO.stdIn val SOME n = IntInf.fromString line fun fact (i, acc : IntInf.int) = if i > 200 then acc else fact (i + 1, acc * IntInf.fromInt i) val f = fact (1, 1) val m = n div 1000000 + 9 fun loop (i, x : IntInf.int) = if i = 1000000 then x else loop (i + 1, (x * x + 1) mod m) val _ = print (IntInf.toString f ^ "\n") val _ = print (IntInf.toString (f div n) ^ "\n") val _ = print (IntInf.toString (loop (0, 2)) ^ "\n")
仕組み: Int は 32 ビットなので、64 ビットの計算には Int64 を使います。IntInf は 2^62 - 1 までの値をそのまま持ち、それより大きい値は多倍長で持ちます(MLton)。IntInf の掛け算は、値の印(最下位のビット)で小さい値(2^62 - 1 まで)かを確かめ、imul 命令とあふれのフラグ(jo)で積が収まるかを確かめます。印を付け直すときにも、あふれを確かめます。
Bash
64 ビット整数(比べる用)
$(( ))(算術式) 言語の機能
2655 ms
コード
read -r m x=2 for ((i = 0; i < 1000000; i++)); do x=$(( (x * x + 1) % m )); done echo "$x"
多倍長整数(64 ビットに収まる値)
bc コマンド 外部ライブラリ
1075 ms(C++ の 43 倍)
コード
read -r m BC_LINE_LENGTH=0 bc <<END m = $m x = 2 for (i = 0; i < 1000000; i++) x = (x * x + 1) % m x END
128 ビット整数
多倍長整数
bc コマンド 外部ライブラリ
2263 ms(C++ の 40 倍)
コード
read -r n # bc は既定で 70 桁ごとに行を折るので、折らないようにする BC_LINE_LENGTH=0 bc <<END f = 1 for (i = 1; i <= 200; i++) f *= i m = $n / 1000000 + 9 x = 2 for (i = 0; i < 1000000; i++) x = (x * x + 1) % m f f / $n x END
仕組み: $(( )) の計算は 64 ビットで、あふれると負の値に回ります。多倍長は bc コマンドで計算します。
Fix
64 ビット整数(比べる用)
I64 言語の機能
12 ms
コード
module Main;
import CPLib.IO;
main : IO () = (
let s = *read_s;
let m : I64 = s.from_string.as_ok;
let x = range(0, 1000000).fold(2, |_, v| (v * v + 1) % m);
x.to_string.println;;
pure()
);
多倍長整数(64 ビットに収まる値)
Minilib.Math.BigInt 外部ライブラリ
98 ms(C++ の 3.9 倍)
コード
module Main;
import CPLib.IO;
import Minilib.Math.BigInt;
big : String -> BigInt;
big = |s| from_string(s).as_ok;
main : IO () = (
let m = big(*read_s);
let one = big("1");
let x = range(0, 1000000).fold(big("2"), |_, v| (v * v + one) % m);
x.to_string.println;;
pure()
);
128 ビット整数
I128 言語の機能
25 ms
コード
module Main;
import CPLib.IO;
main : IO () = (
let s = *read_s;
let n : I128 = s.from_string.as_ok;
let a = range(0, 126).fold(1_I128, |_, v| v * 2_I128 + 1_I128);
let b = n * 1000000_I128;
let m = n / 1000000_I128 + 9_I128;
let x = range(0, 1000000).fold(2_I128, |_, v| (v * v + 1_I128) % m);
a.to_string.println;;
(b / 7_I128).to_string.println;;
(b % 1000000007_I128).to_string.println;;
n.to_string.println;;
x.to_string.println;;
pure()
);
仕組み: I128 の余りは、ライブラリの関数(__modti3)を呼んで計算します。
多倍長整数
Minilib.Math.BigInt 外部ライブラリ
426 ms(C++ の 7.6 倍)
コード
module Main;
import CPLib.IO;
import Minilib.Math.BigInt;
big : String -> BigInt;
big = |s| from_string(s).as_ok;
main : IO () = (
let n = big(*read_s);
let f = range(1, 201).fold(big("1"), |i, acc| acc * big(i.to_string));
let m = n / big("1000000") + big("9");
let x = range(0, 1000000).fold(big("2"), |_, v| (v * v + big("1")) % m);
f.to_string.println;;
(f / n).to_string.println;;
x.to_string.println;;
pure()
);
多倍長整数のライブラリがあるか不明な言語
- Kuin
- Vim script
- Assembler
- Brainfuck
- Whitespace
- Text