Compare/3 faster than arithmetic why?

In SWI-Prolog 8.4.3:

?- time((between(0, 50_000_000, N), N > 49_000_000)).
% 98,000,005 inferences, 2.912 CPU in 2.914 seconds (100% CPU, 33653791 Lips)
N = 49000001 .

?- time((between(0, 50_000_000, N), compare(>, N, 49_000_000))).
% 98,000,003 inferences, 2.411 CPU in 2.413 seconds (100% CPU, 40645761 Lips)
N = 49000001 .

Why is compare/3 significantly faster? Seems unintuitive :grinning:

Have you followed the code al the way down even into the C level code?

I use to use format/2,3 only when needed for outputing values as I thought it was time expensive. Then Jan W. noted in an unrelated reply that it was actually quite fast when used correctly and often used for more then just formatting, think conversion. After looking for examples in my list of trusted repositories I started to see many uses of format/2,3 beyond what I expected.

So don’t take the name of a predicate or description of its use to be limited to just that. Also don’t bring the baggage of ideas from imperative and functional languages along with you when reasoning about Prolog code, go look at the source.

If you want a predicate that is way beyond what it seems to be learn arg/3. :slightly_smiling_face:

As I like to say, get the code working correctly before making it faster.

Did you notice the difference in lips? 33653791 vs 40645761.
I don’t know if or how much that will skew the results but I would understand that more for such questions.

Sorry, but I could not catch the point, in particular why format/2 is related here. But I tested the comparison for curiosity, in which I haven’t seen a significant difference.

?-  time((between(0, 50_000_000, N), N > 49_000_000)).
% 98,000,005 inferences, 3.410 CPU in 3.423 seconds (100% CPU, 28739637 Lips)
N = 49000001 .

?- time((between(0, 50_000_000, N), compare(>, N, 49_000_000))).
% 98,000,003 inferences, 3.351 CPU in 3.362 seconds (100% CPU, 29243816 Lips)
N = 49000001 .

My original comparison (2.4 vs 2.9 seconds), with compare/3 faster, was run on an AMD Ryzen 7 5800H CPU, using x86_64.

On an Intel Core m3-6Y30 running SWI-Prolog 8.5.13 on x86_64, the difference is 6.6 vs 8.3 seconds.

On an Apple M1 Pro running 8.4.3 supplied via brew (presumably native arm64), the diffence is insignificant at 2.4 vs 2.5 seconds.

Perhaps this shows that there is scope for perforrmance improvement on x86_64 by changing method of numerical comparison.

compare/3 examines the terms and sees which is less. It works on all kinds of terms, not just numbers. It doesn’t perform arithmetic, just examines the internal representation. SWI-Prolog -- Manual

>/2 evaluates each terms using built-in arithmetic. It works on all terms that represent arithmetic expression.

I think you should prefer compare or @>

1 Like
?- time((between(0, 50_000_000, N), N @> 49_000_000)).
% 98,000,003 inferences, 2.282 CPU in 2.283 seconds (100% CPU, 42951988 Lips)
N = 49000001 .

That’s a nice performance improvement, by adding the ampersand, when both variables are known to be of type integer :grinning:

E.g. this would be unintended:

?- 5 @> 5.0.
1 Like

For another timing on the list, load a file using swipl -O that holds

p(N) :-
    between(0, 50_000_000, N),
    N > 49_000_000.

and do ?- time(p(N)). That gives me the best time as it used optimized arithmetic done by the VM itself. All the others call a “foreign” predicate. compare/3 is indeed standard order comparison and thus should be compared to @>/2, which -for me- is a little faster than compare/3.

1 Like