2026年7月3日金曜日

Python vs JavaScript計算速度

6.4kb,python3のプログラムでは、計算結果 関数: SIN 入力角度: 69.9456 [degrees] 使用精度: 2000000 桁 結果: 0.93936746313921234097988393589238179159580804874360060315349846493292147343414030864383559302808475733039446789291794840641414768516036511406636601005944222181470908398512160399370035109947838219478622343346779097877788470181801497998994603453883479790740964163986226106424406659735646951455720717881459811687985085224105830815492725352298165766660974901358869097563598642090282608901111965181441420419355553368540005226690202434474105729521230711254319892872139260312706341156658139750438810025744351749315757137530576192931008619144791647782569338446916679864646081922100749924795794540701949414360550437194512596067607000979496977283357617141657810122288215664449156642390525185830039406050902229209860405243262297976918250221222335265851454187337710623311874081936165334466141249963717518783260788649336229034275311361392702097936760549149114538021138880      ーーーーー      全部は、掲載出来ませんが、1分未満で、答えが、出ますが、JavascriptWebアプリ、では、大分、改良を、重ねましたが、50,000桁でも、704秒、時間がかかります、この、差の原因と、Javascriptプログラムへの、応用方法などについて、雑学や業界話を交えながら、解説してください。

これは、とても面白いテーマです。

Python版が200万桁を1分未満なのに、JavaScript版は5万桁で704秒ということは、単純計算すると約4万~6万倍以上の性能差があります。

普通はPythonよりJavaScriptの方が遅くても数倍~数十倍程度なので、この差は「言語」よりもアルゴリズム・実装方法の違いによるものがほとんどです。


一番大きな原因

結論から言うと、

Python版は、高速な多倍長整数ライブラリや効率的なアルゴリズムを使っている可能性が非常に高い

ということです。

例えば

  • Python標準の整数(int)
  • MPIR
  • GMP
  • MPFR
  • gmpy2

などを利用すると、内部ではC言語で何十年も最適化されたコードが動いています。

つまり

Python
   ↓
gmpy2
   ↓
MPFR
   ↓
GMP
   ↓
CPU

実際には「Python」が計算しているのではなく、

C言語製ライブラリ

がほぼ全部やっています。

Pythonはその司令塔です。


JavaScriptでは?

一方、

JavaScript Webアプリは

BigInt

decimal.js
big.js

などで実装しているケースが多いです。

これらは多くが

JavaScriptだけ

で書かれています。

つまり

JavaScript
↓
JavaScript
↓
JavaScript

になります。


JavaScriptは実は速い

意外ですが、

JavaScriptのエンジン

  • V8(Chrome)
  • SpiderMonkey(Firefox)
  • JavaScriptCore(Safari)

は非常に高速です。

実際、

Googleは毎年数百人規模でV8を最適化しています。

なので

普通の整数演算なら

Pythonより速いこともあります。

しかし

多倍長演算になると事情が変わります。


多倍長整数は別世界

例えば

123456789012345678901234567890

くらいなら問題ありません。

しかし

2,000,000桁

になると、

一回の加算ですら

2,000,000回近い計算

になります。

掛け算はもっと大変です。


掛け算もアルゴリズムが違う

学校で習う

1234
×5678

の掛け算は

O(n²)

です。

しかしGMPは

桁数に応じて

  • Karatsuba
  • Toom-Cook
  • FFT multiplication
  • Schönhage–Strassen
  • NTT系

などを切り替えます。

例えば

100万桁になると

FFT乗算になります。

これは

O(n log n)

です。

この差は天文学的です。


SIN計算はさらに複雑

SINは

普通

sin(x)

=
x
-
x^3/3!
+
x^5/5!
...

では計算しません。

この方法は非常に遅いです。

高速ライブラリは

例えば

  • 引数縮小
  • Binary Splitting
  • AGM
  • 高速除算
  • 高速平方根
  • 高速乗算

などを組み合わせます。

つまり

SINの中身は

数十種類以上のアルゴリズムで構成されています。


JavaScriptで一番時間がかかる部分

よくある実装では

for (...)

    足す

for (...)

    掛ける

for (...)

    割る

を何十万回も繰り返しています。

さらに

BigNumber.plus()
BigNumber.times()
BigNumber.div()

のたびに

新しいオブジェクト

を生成します。

これが非常に重いです。


ガベージコレクション

JavaScriptには

GC(Garbage Collection)

があります。

例えば

a.plus(b)

すると

新しいBigNumber

が作られます。

100万回呼ぶと

100万個できます。

GCが始まると

数秒止まることもあります。

PythonでもGCはありますが、

GMP内部では

巨大メモリをかなり効率よく管理しています。


Webブラウザという制約

ブラウザでは

UI

JavaScript

DOM

描画

イベント

全部が同じ環境です。

だから

CPUを100%使い続けると

画面まで止まります。

Pythonは

コンソールなら

CPUをほぼ100%使えます。


CPU命令の違い

GMPは

CPUごとに

例えば

AVX2

AVX512

BMI2

MULX

ADCX

などを利用します。

つまり

IntelならIntel専用

AMDならAMD専用

ARMならARM専用

のコードがあります。

JavaScriptでは

これらを直接使えません。


キャッシュ最適化

GMPは

CPUキャッシュ

L1

L2

L3

まで考えて

データ配置を変えます。

これは職人芸です。

世界中の数学ライブラリ開発者が

20年以上かけて改良しています。


JavaScriptへ応用する方法

ここからが重要です。

① WebAssemblyを使う

一番おすすめです。

JavaScript

↓

WebAssembly

↓

GMP

あるいは

MPFR

をWebAssembly化します。

すると

数十倍〜数百倍高速になることがあります。


② Web Worker

計算を

Worker

へ移します。

UIが固まりません。

体感速度が大きく改善します。


③ Binary Splitting

SINの級数計算なら

Binary Splitting

が有効です。

これはπ計算でもよく使われます。


④ FFT乗算

50,000桁を超えるなら

FFT乗算を使うだけでも

大幅に改善する可能性があります。


⑤ 引数縮小

SINなら

69.9456°

をそのまま計算するのではなく

周期性を利用して

0~π/4

くらいまで縮小してから級数計算すると、

必要な項数が減り、計算量を抑えられます。


⑥ メモリ再利用

毎回

new BigNumber()

せず、

使い回せる領域は再利用します。

GC負荷がかなり減ります。


業界話

実は世界最高速クラスの多倍長ライブラリを書いている人たちは、それほど多くありません。

代表格のGMPは1990年代から改良が続けられており、CPUアーキテクチャごとのアセンブリコードまで含めて膨大な最適化が積み重ねられています。多倍長演算ライブラリは、暗号・数論・数値解析・計算機代数など幅広い分野で使われるため、「一度ライブラリを徹底的に速くし、多くのソフトウェアがそれを利用する」という文化が根付いています。

一方、Web開発では「速度より保守性や移植性」を重視することが多く、JavaScript製の多倍長ライブラリは、ブラウザでどこでも動くことを優先した設計になっている場合が少なくありません。そのため、純粋な演算速度では専用ライブラリとの差が大きくなります。

あなたのケースで特に注目した点

5万桁で704秒」という数字は、ブラウザで純粋なJavaScriptによる高精度三角関数計算としては十分に起こり得る範囲ですが、「200万桁を1分未満」というPython版は、単なるPythonコードでは説明しにくい速度です。内部で高度に最適化された多倍長演算ライブラリやアルゴリズムを利用している可能性が高いでしょう。

もしJavaScript版でも「数十万桁〜数百万桁」を現実的な時間で目指すのであれば、純粋なJavaScriptの改良だけでなく、WebAssembly化したGMP/MPFRの利用、Web Workerによる並列化、Binary SplittingやFFT乗算などのアルゴリズム改善を組み合わせることが、最も大きな性能向上につながる可能性があります。

0 件のコメント: