Я использую целые числа произвольной точности для представления плотных битовых векторов размером от дюжины до нескольких тысяч.
Мой код часто должен проверять, установлены ли определенные биты (или нет), поэтому я провел несколько микротестов, чтобы увидеть, были ли некоторые варианты значительно быстрее, чем другие:
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 все вышеперечисленные варианты (почти) одинаково быстры.
Затем я наткнулся на следующую интересную часть руководства SWI-Prolog:
getbit(+IntExprV, +IntExprI)
Вычисляет значение бита (
0
или1
)IntExprI
-го битаIntExprV
. Оба аргумента должны быть неотрицательными целыми числами. Результат эквивалентен(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. |
Оказывается, что:
getbit/2
дал SWI-Prolog ускорение на 500%.Параметр командной строки
-O
дал SWI-Prolog значительное ускорение.
Есть ли лучшая формулировка (арифметика, веселье и т. Д.) Для получения аналогичного ускорения с помощью SICStus?
Заранее спасибо!