eq

Infix operator for string comparison inside expr. Returns true if its arguments are string-equal.

Its opposite part is ne which returns true if its arguments are not string-equal.

Differs from == in such that its arguments cannot be treated as numerical values, so 1 == 1.0 returns true, but 1 eq 1.0 returns false.

Example:

% expr {"a" eq "b"}
0
% expr {"a" ne "b"}
1

Also comparing text with eq is faster than ==.

AMG: Efficiency is a secondary concern. Correctness comes first. Your program will misbehave, sometimes in non-obvious ways, if you use == when you need eq or vice versa. When you're comparing strings, use eq. When you're comparing numbers, use ==. Numbers can be equivalent yet have different string representations; strings can be different yet have the same numerical representation. "\t1.e0" == "0x001\n". Luckily, in this case the correct thing is also the fast thing.


BC: Which is more efficient - string compare or eq?

AMG: time to the rescue!

proc 1 {a b} {expr {$a eq $b}}
proc 2 {a b} {::tcl::mathop::eq $a $b}
proc 3 {a b} {string compare $a $b}
proc 4 {a b} {string equal $a $b}
set a "\t1.e0"
set b "0x001\n"
time {1 $a $b} 1000000 ;# 1.633135 microseconds per iteration
time {2 $a $b} 1000000 ;# 1.619685 microseconds per iteration
time {3 $a $b} 1000000 ;# 1.618814 microseconds per iteration
time {4 $a $b} 1000000 ;# 1.612457 microseconds per iteration

It's a wash; the difference is nanoseconds. The actual eq operator (2) takes about the same amount of time as string compare (3). Embedding eq into an expr adds some overhead, which you pay for anyway if you're using if, while, for, or other math and logic.

string compare is closer to ne in behavior; both return 0 when the strings are equal. string equal is the closest command to eq. string compare and string equal both have options that eq and ne do not.


DAB: The timings on this page don't take the "if" condition into account. "if" is automatically calling "expr", so "if{string equal}" is calling one extra command.

Code:

proc 1 {a b} {if {$a eq $b} {return 1}}
proc 2 {a b} {if {[string equal $a $b]} {return 1}}
set a "\t1.e0"
set b "0x001\n"
puts [time {1 $a $b} 1000000] ;# 1.101801 microseconds per iteration
puts [time {2 $a $b} 1000000] ;# 1.230454 microseconds per iteration

Using this pattern, "eq" is about 10% faster.


ko - 2012-09-21 11:33:39

A simple compare between eq with == and ne with != Difference is about 20% in speed

set i 0

set start_time [clock clicks -milliseconds]
for { set i 1 } { $i <= 1000000 } { incr i } {

        set var "waarde_$i"

        if {$var eq "waarde_nr_"} {
                puts stdout ""
        }
}

set current_time [clock clicks -milliseconds]
set diff_time1 [expr "$current_time - $start_time"]

puts stdout "Eq command takes $diff_time1 ms"


# #############################################
set i 0

set start_time [clock clicks -milliseconds]
for { set i 1 } { $i <= 1000000 } { incr i } {

        set var "waarde_$i"

        if {$var == "waarde_nr_"} {
                puts stdout ""
        }
}

set current_time [clock clicks -milliseconds]
set diff_time2 [expr "$current_time - $start_time"]

puts stdout "== command takes $diff_time2 ms"
puts stdout "[expr (($diff_time2 - $diff_time1)/($diff_time2 * 1.0)) * 100] %"

# #############################################

set start_time [clock clicks -milliseconds]
for { set i 1 } { $i <= 1000000 } { incr i } {

        set var "waarde_$i"

        if {$var ne "waarde_nr_"} {
                
        }
}

set current_time [clock clicks -milliseconds]
set diff_time3 [expr "$current_time - $start_time"]
puts stdout "Ne command takes $diff_time3 ms"


# #############################################
set i 0

set start_time [clock clicks -milliseconds]
for { set i 1 } { $i <= 1000000 } { incr i } {

        set var "waarde_$i"

        if {$var != "waarde_nr_"} {
                
        }
}

set current_time [clock clicks -milliseconds]
set diff_time4 [expr "$current_time - $start_time"]

puts stdout "!= command takes $diff_time4 ms"
puts stdout "[expr (($diff_time4 - $diff_time3)/($diff_time4 * 1.0)) * 100] %"

Output is:

Eq command takes 1037 ms
== command takes 1301 ms
20.2920830131 %
Ne command takes 1011 ms
!= command takes 1291 ms
21.6886134779 %

DAH - 2013-09-16 15:01:49

I was recently wondering about a similar performance question. In my case, I was wondering if TCL 8.5 construct 'in' would perform any different from multiple 'eq' statements. I tried the following and when performance is a concern it seems like it can make a substantial difference:

> set arg read_file2
read_file2
> time {expr {($arg eq "read_file1") || ($arg eq "read_file2")}} 1000
0.283 microseconds per iteration
> time {expr {($arg eq "read_file1") || ($arg eq "read_file2") || ($arg eq "read_file3")}} 1000
0.298 microseconds per iteration
> time {expr {$arg in [list read_file1 read_file2]}} 1000
0.508 microseconds per iteration
> time {expr {$arg in [list read_file1 read_file2 read_file3]}} 1000
0.559 microseconds per iteration
> time {expr {$arg in "read_file1 read_file2"}} 1000                
0.19 microseconds per iteration
> time {expr {$arg in "read_file1 read_file2 read_file3"}} 1000
0.204 microseconds per iteration

The subtle thing is that the use of 'list' seems to kill the performance. I would also expect that as the list grows substantially, the likelihood of the earlier compares to succeed could have an impact on the performance as well bias the choice in one direction or the other. This simple test seem to indicate using 'in' and skipping the 'list' will lead to more concise code and better performance but I presume there will be other reasons not to do that depending on your exact needs