はじめに
数値計算をやるときの言語選択についてさまざまな選択肢が存在すると思います。
- チームのスキルセット
- 既存のコードベース
- プロジェクトの規模と納期
- エコシステムの充実度
- 保守性・可読性
これらすべてを考慮した上で、最適な言語を選択したいところです。
ここでは、数値計算におけるPython / Julia / C++の棲み分けを解説します。
3言語の立ち位置
| 言語 | 主な用途 | 強み | 弱み |
|---|---|---|---|
| Python | プロトタイピング・データ分析 | エコシステム・学習コスト | 純粋Pythonの速度 |
| Julia | 研究開発・高速プロトタイピング | 速度と開発効率の両立 | エコシステムの未成熟 |
| C++ | プロダクション・HPC | 最高速度・完全制御 | 開発速度・複雑性 |
各言語の特徴と強み
Python
強み
1. 圧倒的なエコシステム
import numpy as np # 数値計算
import scipy as sp # 科学計算
import matplotlib.pyplot as plt # 可視化
import pandas as pd # データ処理
import torch # 機械学習
import sympy # 数式処理
2. 学習コストの低さ
# わかりやすい
data = [1, 2, 3, 4, 5]
result = sum(data) / len(data)
3. NumPy/SciPyの性能
import numpy as np
# これはC/Fortranで実装されている
A = np.random.rand(1000, 1000)
B = np.random.rand(1000, 1000)
C = A @ B # 非常に高速
弱み
1. 純粋Pythonループは遅い
# 遅い
def slow_sum(arr):
total = 0
for x in arr:
total += x
return total
# 速い
def fast_sum(arr):
return np.sum(arr)
2. GILによる並列化の制約
マルチスレッドが実質的に使えない(マルチプロセスは可能)。
3. 型の曖昧さによる最適化の限界
JITコンパイラ(Numba)を使っても、型が明確な言語には及びません。
Pythonを選ぶべき場面
- 機械学習・データサイエンスが主体
- 豊富なライブラリが必要
- チームメンバーの多くがPython経験者
- プロトタイピング速度が最優先
- NumPy/SciPyで十分な速度が出る
Julia
強み
1. 速度と開発効率の両立
# Pythonのように書ける
function sum_array(arr)
total = 0.0
for x in arr
total += x
end
return total
end
# でもC++並みに速い
2. 数値計算のための言語
using LinearAlgebra
# 数学的な記法がそのまま書ける
A = rand(1000, 1000)
B = rand(1000, 1000)
C = A * B # Python同様に書けて、C++並みの速度
3. 優れた並列化サポート
using Distributed
# 簡単に並列化
@distributed for i in 1:1000000
# 処理
end
4. 多重ディスパッチによる柔軟性
# 型によって自動的に最適な実装が選ばれる
function compute(x::Float64)
# Float64用の最適化された実装
end
function compute(x::ComplexF64)
# 複素数用の実装
end
弱み
1. エコシステムの未成熟
Pythonと比べると、ライブラリが少ない・ドキュメントが不足している場面があります。
2. 初回実行が遅い(JITコンパイル)
# 初回は遅い
@time f(x) # 5.2秒 (コンパイル含む)
# 2回目以降は速い
@time f(x) # 0.001秒
3. パッケージの安定性
Python(NumPy/SciPy)ほどの成熟度はまだありません。
Juliaを選ぶべき場面
以下の条件に当てはまるとき
- 新しいアルゴリズムを研究開発
- 速度が重要だが、C++は避けたい
- 数値計算が主体(機械学習は補助的)
- 並列計算が必要
- プロトタイプをそのまま本番で使いたい
C++
強み
1. 最高速度
// 完全に制御可能
void matrix_multiply(const double* A, const double* B, double* C,
int N) {
#pragma omp parallel for
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
double sum = 0.0;
for (int k = 0; k < N; ++k) {
sum += A[i*N + k] * B[k*N + j];
}
C[i*N + j] = sum;
}
}
}
SIMD、キャッシュ最適化、メモリレイアウトまで完全制御。
2. ゼロコスト抽象化
template<typename T>
class Vector {
// テンプレートはコンパイル時に展開される
// 実行時オーバーヘッドゼロ
};
3. ライブラリの成熟
#include <Eigen/Dense> // 線形代数
#include <boost/math> // 数学関数
// HPC向けライブラリが豊富
弱み
1. 開発速度
// Pythonなら1行
// result = np.mean(data)
// C++では...
double mean(const std::vector<double>& data) {
double sum = std::accumulate(data.begin(), data.end(), 0.0);
return sum / data.size();
}
2. コンパイル時間
大規模プロジェクトでは、コンパイルに数分〜数十分かかることも。
3. 複雑性
// メモリ管理
std::unique_ptr<double[]> data(new double[N]);
// 並列化
#pragma omp parallel for schedule(dynamic)
// SIMD
#pragma omp simd
初学者には敷居が高い。
C++を選ぶべき場面
- リアルタイム性が必要(レイテンシ重視)
- HPC(スーパーコンピュータ)で動かす
- 組み込み・エッジデバイス
- 既存のC++コードベースとの統合
- 最後の1%まで最適化が必要
エコシステム比較
ライブラリの充実度
| 分野 | Python | Julia | C++ |
|---|---|---|---|
| 機械学習 | ◎(PyTorch, TensorFlow) | ○(Flux.jl) | △(LibTorch) |
| 数値最適化 | ○(SciPy) | ◎(JuMP.jl) | ○(NLopt) |
| 可視化 | ◎(Matplotlib, Plotly) | ○(Plots.jl) | △(gnuplot) |
| 並列計算 | △(multiprocessing) | ◎(Distributed) | ◎(OpenMP, MPI) |
| データ処理 | ◎(Pandas) | ○(DataFrames.jl) | △(独自実装) |
| 微分方程式 | ○(SciPy) | ◎(DifferentialEquations.jl) | ○(独自実装) |
| 記号計算 | ◎(SymPy) | ○(Symbolics.jl) | △(SymEngine) |
## 言語連携パターン
実務では、複数の言語を組み合わせることも多いです。
Python + C++
使い分け:
- プロトタイプ・UI: Python
- 計算コア: C++
連携方法:
// C++側(pybind11)
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
py::array_t<double> fast_compute(py::array_t<double> input) {
// C++での高速計算
auto buf = input.request();
double *ptr = (double *) buf.ptr;
// 計算処理
return input;
}
PYBIND11_MODULE(fast_module, m) {
m.def("fast_compute", &fast_compute);
}
# Python側
import fast_module
import numpy as np
data = np.random.rand(1000000)
result = fast_module.fast_compute(data) # C++で計算
メリット:
- Pythonの開発速度
- C++の実行速度
- 既存のPythonコードベースを活用
Julia単体
使い分け:
- 全体をJuliaで実装
メリット:
- 言語境界がない
- 開発速度と実行速度の両立
- コードの一貫性
デメリット:
- エコシステムの制約
- チームの学習コスト
ハイブリッド
フェーズ1(研究開発): Julia
↓ アルゴリズム確定
フェーズ2(プロダクション): C++移植
↓
フェーズ3(運用): Python(制御・監視)
まとめ
各言語を選ぶべき決定的な理由
Python を選ぶべきとき
最優先なら
- 豊富なライブラリ(特に機械学習)
- チームの習熟度
- 開発速度
- エコシステムとの統合
Julia を選ぶべきとき
最優先なら
- 速度と開発効率の両立
- 新しいアルゴリズムの研究
- 数値計算が主体
- 並列計算が必要
C++ を選ぶべきとき
最優先なら
- 絶対的な速度
- レイテンシ(応答時間)
- メモリ効率
- 組み込み・エッジ