Prolog:测试位是否设置

时间:2016-07-07 03:29:50

标签: prolog benchmarking microbenchmark sicstus-prolog

我使用任意精度整数来表示大小范围内的密集位向量 从十几到几千。

我的代码经常需要检查是否设置了某些位, 所以我做了一些微基准测试,看看某些变化是否明显快于其他变化:

bench_1(0, _, _) :- !.
bench_1(N, V, P) :- V /\ (1 << P) =\= 0, N0 is N-1, bench_1(N0, V, P).

bench_2(0, _, _) :- !.
bench_2(N, V, P) :- (V >> P) /\ 1 =:= 1, N0 is N-1, bench_2(N0, V, P).

bench_3(0, _, _) :- !.
bench_3(N, V, P) :- (V >> P) /\ 1 =\= 0, N0 is N-1, bench_3(N0, V, P).

bench_4(0, _, _) :- !.
bench_4(N, V, P) :- (V >> P) /\ 1  >  0, N0 is N-1, bench_4(N0, V, P).

bench_5(0, _, _) :- !.
bench_5(N, V, P) :- 1 is (V >> P) /\  1, N0 is N-1, bench_5(N0, V, P).

对于SWI和SICStus,上述变体都(几乎)同样快速。

然后我偶然发现了以下interesting part of the SWI-Prolog manual

  

getbit(+IntExprV, +IntExprI)

     

评估01的位值(IntExprIIntExprV)。      两个参数都必须求值为非负整数。      结果相当于(IntExprV >> IntExprI)/\1,但效率更高,因为避免了移位值的具体化。

     

未来版本会优化(IntExprV >> IntExprI)/\1来调用getbit/2,同时提供便携性和性能。

所以我查了getbit/2

bench_6(0, _, _) :- !.
bench_6(N, V, P) :- getbit(V,P) =:= 1, N0 is N-1, bench_6(N0, V, P).

我使用以下代码进行微基准测试:

call_indi_delta(G, What, Delta) :-
   statistics(What, [V0|_]),
   call(G),
   statistics(What, [V1|_]),
   Delta is V1 - V0.

run(Ind, Reps, Expr, Pos) :-
   Position is Pos,
   Value    is Expr,
   member(P_3, [bench_1,bench_2,bench_3,bench_4,bench_5,bench_6]),
   G =.. [P_3,Reps,Value,Position],
   call_indi_delta(G, Ind, T_ms), 
   write(P_3:Reps=T_ms), nl,
   false.

使用run(runtime, 10000000, 1<<1000-1, 200)我观察了这些运行时:

        | SWI    | SWI -O | SICStus | SICStus |
        | 7.3.23 | 7.3.23 |   4.3.2 |   4.3.3 |
--------+-----------------+-------------------|
bench_1 | 4547ms | 3704ms |   900ms |   780ms |
bench_2 | 4562ms | 3619ms |   970ms |   850ms |
bench_3 | 4541ms | 3603ms |   970ms |   870ms |
bench_4 | 4541ms | 3633ms |   940ms |   890ms |
bench_5 | 4502ms | 3632ms |   950ms |   840ms |
--------+-----------------+-------------------|
bench_6 | 1424ms |  797ms |    n.a. |    n.a. |

看来:

是否有更好的表达方式(arith。fun。等)与SICStus获得类似的加速?

提前谢谢!

1 个答案:

答案 0 :(得分:5)

不,我认为配方比您尝试的配方更快。特别是,SICStus中没有getbit/2(在编译算术时甚至没有在内部使用)。

PS。一般来说,我会使用walltime进行基准测试。目前的操作系统不能提供非常可靠的runtime

PPS。我会添加一个使用测试代码序列的虚拟版本的基准测试,只是为了确保测试代码实际上比基准测试工具花费更多。 (我做了,并且通过调用没有做任何事情的dummy/3替换了位测试,使得速度更快。所以基准测试似乎没问题。)