Performance question

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Dann Corbit
Posts: 12538
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Performance question

Post by Dann Corbit »

Don wrote:
bob wrote:
michiguel wrote:
metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
The second one is incorrect and it is not guaranteed to give you what you expect. (a==b) could give you any number as long as is not zero! Even if it does, it hurts readability.

Stay away from it!

Miguel
Last time I looked, ansi standards said 0 or 1 for that. The test for true will take any non-zero value for true, but a == b is supposed to return 0 or one only, so far as I know. Other languages are different (Fortran used to use -1 for true on many machines, as one example).
Are you sure about that? I'm pretty sure it is implementation defined unless that has changed.
Bob is right:

The current, amended C standard says:
ISO/IEC 9899:TC3 Committee Draft — Septermber 7, 2007 WG14/N1256
6.5.9 Equality operators
Syntax
1 equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
Constraints
2 One of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void; or
— one operand is a pointer and the other is a null pointer constant.
Semantics
3 The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.93) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.
4 If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Values of complex types are equal if and only if both their real parts are equal and also their imaginary parts are equal. Any two values of arithmetic types from different type domains are equal if and only if the results of their conversions to the (complex) result type determined by the usual arithmetic conversions are equal.

Footnote 93) Because of the precedences, a<b == c<d is 1 whenever a<b and c<d have the same truth-value.

In C++, the result is boolean rather than integral.
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Performance question

Post by Gerd Isenberg »

metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
Depends on how hard the branch is predictable on pipelined processors like x86, and how many other branches and branch targets you have inside your program, where each target takes an entry in a x86 branch target buffer, which might pollute like caches do.

The conditional jump is unbeatable in code size and register usage, but if the number of miss-predictions exceeds some threshold (one miss-predicted branch cost 12 ore more cycles), a pgo compiler may replace it by a conditional move, which on the other hand needs one extra register.

Code: Select all

  cmp  eax, ebx
  jne  skipInc  ; jnz
  add  ecx, 1
skipInc&#58;
versus cmovXX

Code: Select all

  cmp   eax, ebx
  lea   edx, &#91;ecx+1&#93; ; does not change flags
  cmovz ecx, edx  ; conditionally moves edx to ecx if zero flag is set &#40;equal comparison&#41;

On really random pattern, known in advance, it might be worth to add the comparision {0|1} result, which is for me easy to read as well, f.i. in cases like that, which is correct C or C++:

Code: Select all

int nConditionsTrue = &#40;a == b&#41; + &#40;c > b&#41; + &#40;d < c&#41; + &#40;e == f&#41;; // 0..4
if ( nConditionsTrue == 2 ) .... 
But x86 setXX on byte register (needs to clear the 32-bit register in advance) and flag dependency, it is slower than correct predicted branch. Often in greater or less conditions with respect to value ranges, one may rely on the sign flag of a subtraction, to use shift arithmetic right for a conditional {0, -1} mask without flag dependencies.

Code: Select all

  xor  edx, edx ; zero edx
  cmp  eax, ebx
  setz dl
  add  ecx, edx
It also depends on which other instructions and conditions are around. For max instructions per cycle, branchless code is necessary, see f. i. Vulnerable on distant Checks.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Performance question

Post by Don »

Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.

My question now is whether I can use this idiom and expect my code to be portable with respect to any compiler that is in common usage. (I would like to.)

I wanted to use this a few years ago and the compiler I used returned 2 instead of 1 which we thought was strange. It was on Solaris and I think it was GCC but it might have been the Sun compiler - I don't remember for sure.

I don't think this would actually improve the code, but it would make it look nicer and be more readable.

Dann Corbit wrote:
Don wrote:
bob wrote:
michiguel wrote:
metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
The second one is incorrect and it is not guaranteed to give you what you expect. (a==b) could give you any number as long as is not zero! Even if it does, it hurts readability.

Stay away from it!

Miguel
Last time I looked, ansi standards said 0 or 1 for that. The test for true will take any non-zero value for true, but a == b is supposed to return 0 or one only, so far as I know. Other languages are different (Fortran used to use -1 for true on many machines, as one example).
Are you sure about that? I'm pretty sure it is implementation defined unless that has changed.
Bob is right:

The current, amended C standard says:
ISO/IEC 9899:TC3 Committee Draft — Septermber 7, 2007 WG14/N1256
6.5.9 Equality operators
Syntax
1 equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
Constraints
2 One of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void; or
— one operand is a pointer and the other is a null pointer constant.
Semantics
3 The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.93) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.
4 If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Values of complex types are equal if and only if both their real parts are equal and also their imaginary parts are equal. Any two values of arithmetic types from different type domains are equal if and only if the results of their conversions to the (complex) result type determined by the usual arithmetic conversions are equal.

Footnote 93) Because of the precedences, a<b == c<d is 1 whenever a<b and c<d have the same truth-value.

In C++, the result is boolean rather than integral.
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Performance question

Post by Gerd Isenberg »

Don wrote:Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.

My question now is whether I can use this idiom and expect my code to be portable with respect to any compiler that is in common usage. (I would like to.)

I wanted to use this a few years ago and the compiler I used returned 2 instead of 1 which we thought was strange. It was on Solaris and I think it was GCC but it might have been the Sun compiler - I don't remember for sure.
if ( relexpression == true ) is also quite common for some reasons ;-)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Performance question

Post by bob »

Don wrote:Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.

My question now is whether I can use this idiom and expect my code to be portable with respect to any compiler that is in common usage. (I would like to.)

I wanted to use this a few years ago and the compiler I used returned 2 instead of 1 which we thought was strange. It was on Solaris and I think it was GCC but it might have been the Sun compiler - I don't remember for sure.

I don't think this would actually improve the code, but it would make it look nicer and be more readable.
I have only seen the cases of 0/1 or 0/-1. On the Cray, you could test for zero or negative, and they chose 0 and -1 for the two possible values in their Fortran. I have been using the 0/1 convention for years and it has worked on every unix/C box I have tested, including suns. Not sure why you would have seen a +2, which makes no sense at all to me, although stranger things have been done in years past.


Dann Corbit wrote:
Don wrote:
bob wrote:
michiguel wrote:
metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
The second one is incorrect and it is not guaranteed to give you what you expect. (a==b) could give you any number as long as is not zero! Even if it does, it hurts readability.

Stay away from it!

Miguel
Last time I looked, ansi standards said 0 or 1 for that. The test for true will take any non-zero value for true, but a == b is supposed to return 0 or one only, so far as I know. Other languages are different (Fortran used to use -1 for true on many machines, as one example).
Are you sure about that? I'm pretty sure it is implementation defined unless that has changed.
Bob is right:

The current, amended C standard says:
ISO/IEC 9899:TC3 Committee Draft — Septermber 7, 2007 WG14/N1256
6.5.9 Equality operators
Syntax
1 equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
Constraints
2 One of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void; or
— one operand is a pointer and the other is a null pointer constant.
Semantics
3 The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.93) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true.
4 If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Values of complex types are equal if and only if both their real parts are equal and also their imaginary parts are equal. Any two values of arithmetic types from different type domains are equal if and only if the results of their conversions to the (complex) result type determined by the usual arithmetic conversions are equal.

Footnote 93) Because of the precedences, a<b == c<d is 1 whenever a<b and c<d have the same truth-value.

In C++, the result is boolean rather than integral.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Performance question

Post by bob »

Don wrote:
bob wrote:
michiguel wrote:
metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
The second one is incorrect and it is not guaranteed to give you what you expect. (a==b) could give you any number as long as is not zero! Even if it does, it hurts readability.

Stay away from it!

Miguel
Last time I looked, ansi standards said 0 or 1 for that. The test for true will take any non-zero value for true, but a == b is supposed to return 0 or one only, so far as I know. Other languages are different (Fortran used to use -1 for true on many machines, as one example).
I specifically remember searching for this a few years ago because I wanted to be able to safely make that assumption, but I had to reject it. Now I'm trying to figure out if I'm remembering this correctly.

I looked on wikipedia under boolean data types and they have a section for several common languages.

In the section on the C language it says this:
To this day, Boolean values are commonly represented by integers in C programs. The comparison operators (' > ', '==', etc.) are defined to return a signed integer (int) result, either zero (for false) or nonzero (for true).
and later is says this about C:
However, since the C language standards allow the result of a comparison to be any non-zero value, the statement if(t==1){...} is not equivalent to if(t){...} or to if(t!=0){...}.
So I think you are mistaken or the wikipedia entry needs to be corrected.

Someone just mangled the explanation. The test "If (c)" says that if c is zero (0) the condition c is considered to be false, if c is non-zero, it is considered to be true. But for assignments like a = (b == c); a will either be zero or 1, only.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Performance question

Post by Don »

bob wrote:
Don wrote:
bob wrote:
michiguel wrote:
metax wrote:Is there any difference in the performance of the following two lines:

1. if (a == b) c++;

or

c += (a == b);


Is any of these faster?
The second one is incorrect and it is not guaranteed to give you what you expect. (a==b) could give you any number as long as is not zero! Even if it does, it hurts readability.

Stay away from it!

Miguel
Last time I looked, ansi standards said 0 or 1 for that. The test for true will take any non-zero value for true, but a == b is supposed to return 0 or one only, so far as I know. Other languages are different (Fortran used to use -1 for true on many machines, as one example).
I specifically remember searching for this a few years ago because I wanted to be able to safely make that assumption, but I had to reject it. Now I'm trying to figure out if I'm remembering this correctly.

I looked on wikipedia under boolean data types and they have a section for several common languages.

In the section on the C language it says this:
To this day, Boolean values are commonly represented by integers in C programs. The comparison operators (' > ', '==', etc.) are defined to return a signed integer (int) result, either zero (for false) or nonzero (for true).
and later is says this about C:
However, since the C language standards allow the result of a comparison to be any non-zero value, the statement if(t==1){...} is not equivalent to if(t){...} or to if(t!=0){...}.
So I think you are mistaken or the wikipedia entry needs to be corrected.

Someone just mangled the explanation. The test "If (c)" says that if c is zero (0) the condition c is considered to be false, if c is non-zero, it is considered to be true. But for assignments like a = (b == c); a will either be zero or 1, only.
I only know that I have avoided this assumption for years based on a previous experience at MIT.

But now that I think about it, it could have been the compiler for the DEC alpha quads we used at MIT and that Cilkchess ran on.

There is no question that it returned 2 for a true comparison because we all had the same reaction you just did, that it seemed like a very bizarre value to return - it even seems like you would have to go to extra trouble to make it return that value. I could see -1 but not 2. But that is what it returned.
User avatar
Zach Wegner
Posts: 1922
Joined: Thu Mar 09, 2006 12:51 am
Location: Earth

Re: Performance question

Post by Zach Wegner »

Don wrote:Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.
The standard has always said that == is 0/1 AFAIK. In pre-K&R C, there weren't any short-circuiting logical operators, only the bitwise, so the tests _had_ to be 0 or 1.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Performance question

Post by Don »

Zach Wegner wrote:
Don wrote:Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.
The standard has always said that == is 0/1 AFAIK. In pre-K&R C, there weren't any short-circuiting logical operators, only the bitwise, so the tests _had_ to be 0 or 1.
I've been digging around and have not found anything that refutes this other than the wikipedia article which states: "However, since the C language standards allow the result of a comparison to be any non-zero value ..."

I don't know how that can be interpreted any other way, but I could certainly accept that they just got it wrong - maybe it was written by someone who did not check their facts.

On the other hand, I also have my own experience which has caused me to avoid using comparisons this way for years. So maybe both my memory and that article are at fault.

Anyway, I don't really care - I'll start using this if the occasion arises.
Jan Brouwer
Posts: 201
Joined: Thu Mar 22, 2007 7:12 pm
Location: Netherlands

Re: Performance question

Post by Jan Brouwer »

Don wrote:
Zach Wegner wrote:
Don wrote:Dann,

It appears that Bob has it right and the wikipedia is wrong then. I think the standard has changed with regard to this exact issue.
The standard has always said that == is 0/1 AFAIK. In pre-K&R C, there weren't any short-circuiting logical operators, only the bitwise, so the tests _had_ to be 0 or 1.
I've been digging around and have not found anything that refutes this other than the wikipedia article which states: "However, since the C language standards allow the result of a comparison to be any non-zero value ..."

I don't know how that can be interpreted any other way, but I could certainly accept that they just got it wrong - maybe it was written by someone who did not check their facts.

On the other hand, I also have my own experience which has caused me to avoid using comparisons this way for years. So maybe both my memory and that article are at fault.

Anyway, I don't really care - I'll start using this if the occasion arises.
In C operators such as >, ==, !, etc only return 0 or 1.
So you can rewrite eg "int a = (b != 0) ? 1 : 0;" as "int a = (b != 0)" (or "int a = !!b;").
The C if statement implicitly compares the expression between brackets against 0, "if (a)" is equivalent to "if (a != 0)",
so I think the quote above is not correct.