Ultimately, I think @goretkin is right that the implementation is key. Currently, the default is
if this < prev
return false
end
The alternative would be as follows.
if !( this >= prev )
return false
end
The second version seems less efficient since you have to do the >=
comparison and then negate it. However, this is Julia, and we have a fancy compiler.
julia> function f(this, prev)
if this < prev
return false
end
return true
end
f (generic function with 1 method)
julia> function g(this, prev)
if !( this >= prev )
return false
end
return true
end
g (generic function with 1 method)
julia> f(1,2)
false
julia> g(1,2)
false
julia> f(2, 1)
true
julia> g(2,1)
true
julia> @code_llvm debuginfo=:none f(2, 1)
; Function Attrs: uwtable
define i8 @julia_f_816(i64 signext %0, i64 signext %1) #0 {
top:
%.not = icmp sge i64 %0, %1
%spec.select = zext i1 %.not to i8
ret i8 %spec.select
}
julia> @code_llvm debuginfo=:none g(2, 1)
; Function Attrs: uwtable
define i8 @julia_g_818(i64 signext %0, i64 signext %1) #0 {
top:
%.not = icmp sle i64 %1, %0
%spec.select = zext i1 %.not to i8
ret i8 %spec.select
}
Both versions compile to very similar code.
julia> @code_native debuginfo=:none issorted([1, 2, 3])
.text
pushq %rbp
movq %rsp, %rbp
movq 8(%rcx), %r9
movb $1, %al
testq %r9, %r9
je L57
cmpq $1, %r9
je L57
movq (%rcx), %r8
movq (%r8), %rdx
movl $2, %ecx
L32:
movq %rdx, %r10
movq -8(%r8,%rcx,8), %rdx
cmpq %r10, %rdx
jl L55
cmpq %r9, %rcx
jae L57
incq %rcx
jmp L32
L55:
xorl %eax, %eax
L57:
popq %rbp
retq
nopl (%rax,%rax)
julia> import Base: issorted, lt
julia> function issorted(itr, order::Base.Order.Ordering)
y = iterate(itr)
y === nothing && return true
prev, state = y
y = iterate(itr, state)
while y !== nothing
this, state = y
!lt(order, prev, this) && return false
prev = this
y = iterate(itr, state)
end
return true
end
issorted (generic function with 5 methods)
julia> @code_native debuginfo=:none issorted([1, 2, 3], lt = <= )
.text
pushq %rbp
movq %rsp, %rbp
movq 8(%rcx), %r9
movb $1, %al
testq %r9, %r9
je L57
cmpq $1, %r9
je L57
movq (%rcx), %r8
movq (%r8), %rdx
movl $2, %ecx
L32:
movq %rdx, %r10
movq -8(%r8,%rcx,8), %rdx
cmpq %rdx, %r10
jg L55
cmpq %r9, %rcx
jae L57
incq %rcx
jmp L32
L55:
xorl %eax, %eax
L57:
popq %rbp
retq
nopl (%rax,%rax)
Again, it looks like in practice there is not much difference for the given lt
. Where this may make a difference is for an arbitrary lt
that the compiler cannot easily negate.