Sta*_*tas 5 c++ algorithm performance ocaml bitarray
另一个合成基准:Eratosthenes筛选
C++
#include <vector>
#include <cmath>
void find_primes(int n, std::vector<int>& out)
{
std::vector<bool> is_prime(n + 1, true);
int last = sqrt(n);
for (int i = 2; i <= last; ++i)
{
if (is_prime[i])
{
for (int j = i * i; j <= n; j += i)
{
is_prime[j] = false;
}
}
}
for (unsigned i = 2; i < is_prime.size(); ++i)
{
if (is_prime[i])
{
out.push_back(i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
OCaml(使用Jane Street的Core和Res库)
open Core.Std
module Bits = Res.Bits
module Vect = Res.Array
let find_primes n =
let is_prime = Bits.make (n + 1) true in
let last = float n |! sqrt |! Float.iround_exn ~dir:`Zero in
for i = 2 to last do
if not (Bits.get is_prime i) then () else begin
let j = ref (i * i) in
while !j <= n; do
Bits.set is_prime !j false;
j := !j + i;
done;
end;
done;
let ar = Vect.empty () in
for i = 2 to n do
if Bits.get is_prime i then Vect.add_one ar i else ()
done;
ar
Run Code Online (Sandbox Code Playgroud)
我很惊讶OCaml版本(本机)比C++慢大约13倍.我换Res.Bits了Core_extended.Bitarray,但它慢了~18倍.为什么这么慢?OCaml不能为位操作提供快速操作吗?有没有其他快速实现的位阵列?
要明确:我来自C++世界,并将OCaml视为编写性能关键代码的可能替代方案.实际上,我对这样的结果有点吓人.
编辑:
分析结果
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
50.81 1.26 1.26 camlRes__pos_1113
9.72 1.50 0.24 camlRes__unsafe_get_1117
6.68 1.66 0.17 camlRes__unsafe_set_1122
6.28 1.82 0.16 camlNopres_impl__set_1054
6.07 1.97 0.15 camlNopres_impl__get_1051
5.47 2.10 0.14 47786824 0.00 0.00 caml_apply3
3.64 2.19 0.09 22106943 0.00 0.00 caml_apply2
2.43 2.25 0.06 817003 0.00 0.00 caml_oldify_one
2.02 2.30 0.05 1 50.00 265.14 camlPrimes__find_primes_64139
1.21 2.33 0.03 camlRes__unsafe_get_1041
...
Run Code Online (Sandbox Code Playgroud)
在使用复杂的数据结构之前,您是否先尝试使用简单的数据结构?
在我的机器上,以下代码仅比 C++ 版本慢 4 倍(请注意,我做了最小的更改以使用数组作为缓存,并使用列表来累积结果;您可以使用数组 get/set 语法糖):
let find_primes n =
let is_prime = Array.make (n + 1) true in
let last = int_of_float (sqrt (float n)) in
for i = 2 to last do
if not (Array.get is_prime i) then () else begin
let j = ref (i * i) in
while !j <= n; do
Array.set is_prime !j false;
j := !j + i;
done;
end;
done;
let ar = ref [] in
for i = 2 to n do
if Array.get is_prime i then ar := i :: !ar else ()
done;
ar
Run Code Online (Sandbox Code Playgroud)
(慢 4 倍:计算 10_000_000 个第一个素数需要 4 秒,而代码中的 g++ -O1 或 -O2 则需要 1 秒)
意识到位向量解决方案的效率可能来自经济的内存布局,我更改了代码以使用字符串而不是数组:
let find_primes n =
let is_prime = String.make (n + 1) '0' in
let last = int_of_float (sqrt (float n)) in
for i = 2 to last do
if not (String.get is_prime i = '0') then () else begin
let j = ref (i * i) in
while !j <= n; do
String.set is_prime !j '1';
j := !j + i;
done;
end;
done;
let ar = ref [] in
for i = 2 to n do
if String.get is_prime i = '0' then ar := i :: !ar else ()
done;
ar
Run Code Online (Sandbox Code Playgroud)
现在只需要 2 秒,这使得它比 C++ 解决方案慢 2 倍。
| 归档时间: |
|
| 查看次数: |
1118 次 |
| 最近记录: |