crafty-22.0

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

gladius
Posts: 568
Joined: Tue Dec 12, 2006 10:10 am
Full name: Gary Linscott

Re: crafty-22.0

Post by gladius »

As an example of not using inline functions, in my eval, I was using a structure similar to this:

Code: Select all

inline int NegateIfBlack(Color color, int value) {
 return color == WHITE ? value : -value;
}

template<Color color>
inline int eval&#40;) &#123;
 result += NegateIfBlack&#40;color, ...);
 result += NegateIfBlack&#40;color, ...);
&#125;
Turns out the silly optimizer decided that NegateIfBlack was not inlineable, even though the argument is a constant deduced by the template specifier. Did a profile, and NegateIfBlack was 2% of my execution time!

I ended up turning it into:

Code: Select all

template<Color color>
inline int NegateIfBlack&#40;int value&#41; &#123;
 return color == WHITE ? value &#58; -value;
&#125;
and got my nice 2% speedup (which is not huge, but enough 2% speed-ups, and you have a pretty fast program :)). Of course, it's not a great example, as I was still able to use an inline and get the speed I wanted, but if the compiler isn't good enough, macros may win the day.
Tord Romstad
Posts: 1808
Joined: Wed Mar 08, 2006 9:19 pm
Location: Oslo, Norway

Re: crafty-22.0

Post by Tord Romstad »

gladius wrote:Of course, it's not a great example, as I was still able to use an inline and get the speed I wanted, but if the compiler isn't good enough, macros may win the day.
Perhaps, but in cases like this, I would consider it to be a weakness of the compiler, and not a weakness of my program. I guess that those who deliver their programs without source code would have a different perspective on this, though.

Morover, I am almost always willing to sacrifice a tiny amount of speed to make bugs slightly less likely. This is actually the main reason why my program is stronger than most amateur chess programs: Slow and bug-free generally beats fast and buggy.

Tord
Uri Blass
Posts: 10282
Joined: Thu Mar 09, 2006 12:37 am
Location: Tel-Aviv Israel

Re: crafty-22.0

Post by Uri Blass »

Tord Romstad wrote:
gladius wrote:Of course, it's not a great example, as I was still able to use an inline and get the speed I wanted, but if the compiler isn't good enough, macros may win the day.
Perhaps, but in cases like this, I would consider it to be a weakness of the compiler, and not a weakness of my program. I guess that those who deliver their programs without source code would have a different perspective on this, though.

Morover, I am almost always willing to sacrifice a tiny amount of speed to make bugs slightly less likely. This is actually the main reason why my program is stronger than most amateur chess programs: Slow and bug-free generally beats fast and buggy.

Tord
I am not sure if most amateur programs are fast.
I guess that most amateur programs are weaker than glaurung because of combination of the following reasons:
1)being slower
2)inferior search
3)inferior evaluation
4)bugs

Uri
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: crafty-22.0

Post by bob »

Tord Romstad wrote:
bob wrote:
Guetti wrote:
Tord Romstad wrote:
Guetti wrote:I also ditched the color dependent code in move generation with one exception, to generate rochade moves. Is it possible to generate these independant form the color? I have stuff there like if (fromsq(King) == E1) etc.
Yes, it is easy to make things like this color-independent:

Code: Select all

if&#40;fromsq&#40;King&#41; == &#40;E1^&#40;color*070&#41;))
I have found this to be useful so often that I have written a little function for it:

Code: Select all

inline Square relative_square&#40;Color c, Square s&#41; &#123;
  return Square&#40;int&#40;s&#41; ^ &#40;int&#40;c&#41; * 070&#41;);
&#125;
With this function, relative_square(WHITE, SQ_E1) returns SQ_E1, while relative_square(BLACK, SQ_E1) returns E8.

Replace the constant 070 by 0x70 if you use a 128-square board.

Tord
Interesting.

For pawns I simply made an array advance_one[2] = {8, -8} and advance_two[2] = {16, -16} to get fromsq+advance_one[WHITE] = fromsq+8, fromsq+advance_one[BLACK] = fromsq-8.

But your square conversion didn't come to my mind.
I started off with Tord's approach, but I found many cases where that didn't work (your 8, -8 is one example.
Not, that's not an example, because they are two entirely different operations. Flipping a square vertically is obviously not the same as flipping a square delta.
That was my point. By using the 2-element arrays, I can flip squares vertically, or flip directions, or anything else that is side-dependent, and I do it in the same way everywhere which helps readability somewhat...


By the way, doing pawn pushes for both colors without an array is also easy, as explained in one of my other posts. In any case, because the array will be so tiny, it doesn't matter at all which approach you use.
I finally defined an array "map_squares[side][square]" to do this for all squares.

Now I just do map_squares[side][E1] and get E1 for side = wtm, and E8 for side = btm.
My approach of doing square ^ (side * 070) does exactly the same for all squares, as you can easily prove.
I agree and hope I didn't imply otherwise. Just that there are other operations needed besides just vertically flipping a square from the 1st to the 8th ranks and vice-versa...
You can bury that in a Macro to make it less intrusive if you want...
I agree, of course this should be done in a macro or inline function. My own preference would be to use an inline function, in order to avoid the pitfalls of preprocessor macros and to ensure some type safety. I honestly don't understand why people are still using preprocessor macros, but that's probably just because of my general ignorance about C/C++ programming.

Tord
I use them for portability since windoze and unix do things so differently. And once I used them there, it made sense to use them for all the simple things, although one needs to be "parenthesis-savvy" to avoid some really ugly bugs, since the pre-processor has a tendency to do what you wrote, and not what you meant. :)
gladius
Posts: 568
Joined: Tue Dec 12, 2006 10:10 am
Full name: Gary Linscott

Re: crafty-22.0

Post by gladius »

Perhaps, but in cases like this, I would consider it to be a weakness of the compiler, and not a weakness of my program. I guess that those who deliver their programs without source code would have a different perspective on this, though.
I certainly agree it is a weakness in the compiler, but we have to work with our tools. If no compiler out there is going to do the optimization, then copy/paste or macros might be the only way to get the speed boost. Of course, optimizing things that don't show up on the profiler is a good recipe for creating bugs with no benefit.
Morover, I am almost always willing to sacrifice a tiny amount of speed to make bugs slightly less likely. This is actually the main reason why my program is stronger than most amateur chess programs: Slow and bug-free generally beats fast and buggy.
I think you are too modest here :). Glaurung is a fast engine, along with being bug-free. Anything that helps to avoid bugs is a good thing, but in time critical code such as the eval, enough small perf. hits and you can lose a ply or two.
jarkkop
Posts: 198
Joined: Thu Mar 09, 2006 2:44 am
Location: Helsinki, Finland

Re: crafty-22.0

Post by jarkkop »