Initializing portions of arrays

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

matthewlai
Posts: 793
Joined: Sun Aug 03, 2014 4:48 am
Location: London, UK

Re: Initializing portions of arrays

Post by matthewlai »

mar wrote:
wgarvin wrote:And then there's a few special cases like "const int X = 5" where the language says the actual X variable can be elided and all uses of it replaced with the value 5. But for "const float Y = 5.0f", I think its allowed to replace uses with 5.0f but it can't elide the variable Y. Or something. I guess the moral of the story is: const is a weird animal ! :lol:
A bit of OT (sorry):

Yes a similar thing happened to me as well (sigh).
I'm not sure if it was a float, but I had a static const name=value declared in a class.
Then somewhere in the code (later) I used Max( x, y ), where say x was that constant.
Max is just a simple template that takes arguments by const reference (just like std::max).
And the compiler (I think it was gcc) complained at link phase (I think) because it probably wanted to pass const by reference (debug build IIRC).
When I changed Max to accept args by value, it worked, but of course that's not what I want for generic types :)
Problem is I can't "fix" this by instantiating it as a variable like type Class::name = value (or maybe without the assignment).
While gcc/clang are happy with this, msc gave me a redefinition error so obviously this not standardized.
So somehow I still haven't found a fully portable and clean way to declare pure constants (except for enum when working with ints).
And I certainly don't want to use preprocessor macros :)
Maybe this has been addressed in modern C++11 and onwards?
I believe the portable way to fix that is to declare (not define) the constant in the header, and define it in cpp file.

.h

Code: Select all

class A
{
public:
    const static float MY_CONSTANT;
}
.cpp

Code: Select all

const float A::MY_CONSTANT = 5.0f; // note that "static" shouldn't be on the definition
Disclosure: I work for DeepMind on the AlphaZero project, but everything I say here is personal opinion and does not reflect the views of DeepMind / Alphabet.
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Initializing portions of arrays

Post by mar »

matthewlai wrote:I believe the portable way to fix that is to declare (not define) the constant in the header, and define it in cpp file.

.h

Code: Select all

class A
{
public:
    const static float MY_CONSTANT;
}
.cpp

Code: Select all

const float A::MY_CONSTANT = 5.0f; // note that "static" shouldn't be on the definition
Yes of course, this is portable. But I suffer a performance hit this way (unless I set the compiler to optimize across modules using IPO/LTCG/no idea how they call this in gcc/clang).
matthewlai
Posts: 793
Joined: Sun Aug 03, 2014 4:48 am
Location: London, UK

Re: Initializing portions of arrays

Post by matthewlai »

mar wrote:
matthewlai wrote:I believe the portable way to fix that is to declare (not define) the constant in the header, and define it in cpp file.

.h

Code: Select all

class A
{
public:
    const static float MY_CONSTANT;
}
.cpp

Code: Select all

const float A::MY_CONSTANT = 5.0f; // note that "static" shouldn't be on the definition
Yes of course, this is portable. But I suffer a performance hit this way (unless I set the compiler to optimize across modules using IPO/LTCG/no idea how they call this in gcc/clang).
Yes, and link time optimization is mature enough these days that it should always be enabled for performance-critical code.

I would always write standard portable code and let the compiler optimize it, especially when I know the compiler is fully capable of optimizing it. Same reason why I don't unroll loops or inline functions by hand, etc.
Disclosure: I work for DeepMind on the AlphaZero project, but everything I say here is personal opinion and does not reflect the views of DeepMind / Alphabet.
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Initializing portions of arrays

Post by mar »

matthewlai wrote:Yes, and link time optimization is mature enough these days that it should always be enabled for performance-critical code.

I would always write standard portable code and let the compiler optimize it, especially when I know the compiler is fully capable of optimizing it. Same reason why I don't unroll loops or inline functions by hand, etc.
Yes, actually I never had success with loop unrolling on modern CPUs anyway (branch predictors probably do the trick).
However you can't do LTO for shared/dynamic libraries (which I don't use anyway).
I think that in the case of a float this is not a big deal as FP constant (unless 0 or 1) has to be fetched indirectly anyway (EDIT: unless it's part of a constant expression),
so I'll probably do it the portable way (at least for floats).
matthewlai
Posts: 793
Joined: Sun Aug 03, 2014 4:48 am
Location: London, UK

Re: Initializing portions of arrays

Post by matthewlai »

mar wrote:
matthewlai wrote:Yes, and link time optimization is mature enough these days that it should always be enabled for performance-critical code.

I would always write standard portable code and let the compiler optimize it, especially when I know the compiler is fully capable of optimizing it. Same reason why I don't unroll loops or inline functions by hand, etc.
Yes, actually I never had success with loop unrolling on modern CPUs anyway (branch predictors probably do the trick).
However you can't do LTO for shared/dynamic libraries (which I don't use anyway).
I think that in the case of a float this is not a big deal as FP constant (unless 0 or 1) has to be fetched indirectly anyway (EDIT: unless it's part of a constant expression),
so I'll probably do it the portable way (at least for floats).
The value of loop unrolling in modern CPUs is probably mostly only when combined with auto-vectorization - when unrolling loops allows the use of SIMD instructions. In other cases, the loop control instructions are probably more or less free anyways from multi-issue scheduling.

Or for extremely short loops (like incrementing all elements in an array by 1).
Disclosure: I work for DeepMind on the AlphaZero project, but everything I say here is personal opinion and does not reflect the views of DeepMind / Alphabet.
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Initializing portions of arrays

Post by mcostalba »

mar wrote: I think that in the case of a float this is not a big deal as FP constant (unless 0 or 1) has to be fetched indirectly anyway (EDIT: unless it's part of a constant expression),
so I'll probably do it the portable way (at least for floats).
Almost there, but you'll need C++11

Code: Select all

 #include <iostream>
 
using namespace std;
 
template<typename T> T Max&#40;T&& f, T&& s&#41;
&#123; return s > f ? s &#58; f; &#125;
 
 
class A
&#123;
public&#58;
 
constexpr static float MY_CONSTANT = 5.0f;
&#125;;
 
 
int main&#40;)
&#123;
cout << Max&#40;A&#58;&#58;MY_CONSTANT, A&#58;&#58;MY_CONSTANT&#41; << endl;
 
return 0;
&#125;
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Initializing portions of arrays

Post by mcostalba »

mcostalba wrote: Almost there
Ok, done

Code: Select all

#include <iostream>
 
using namespace std;
 
template<typename T, typename U> T Max&#40;T&& f, U&& s&#41;
&#123; return s > f ? T&#40;s&#41; &#58; T&#40;f&#41;; &#125;
 
 
class A
&#123;
public&#58;
 
constexpr static float MY_CONSTANT = 5.0f;
&#125;;
 
 
int main&#40;)
&#123;
cout << Max&#40;A&#58;&#58;MY_CONSTANT, 1.0f&#41; << endl;
 
return 0;
&#125;
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Initializing portions of arrays

Post by mar »

mcostalba wrote: Ok, done

Code: Select all

#include <iostream>
 
using namespace std;
 
template<typename T, typename U> T Max&#40;T&& f, U&& s&#41;
&#123; return s > f ? T&#40;s&#41; &#58; T&#40;f&#41;; &#125;
 
 
class A
&#123;
public&#58;
 
constexpr static float MY_CONSTANT = 5.0f;
&#125;;
 
 
int main&#40;)
&#123;
cout << Max&#40;A&#58;&#58;MY_CONSTANT, 1.0f&#41; << endl;
 
return 0;
&#125;
So I have to use constexpr, thanks. However I'm still reluctant to switch to C++11 (I remember msc had problems with constexpr until version 12), but that's a different story,
I most likely will (sooner or later).
I just tried to use plain static const float MY_CONSTANT=xx and msc doesn't even allow this (complaining it needs to be integral type),
so probably the constant I was referring to was not a float (but it doesn't matter).
I like the idea of passing compatible types as arguments (especially useful for containers).
But I think in this case it might be dangerous because Max( 1, 3.75 ) will return 3, which is not what one would expect so I slightly prefer to get an error instead.
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Initializing portions of arrays

Post by mar »

matthewlai wrote:The value of loop unrolling in modern CPUs is probably mostly only when combined with auto-vectorization - when unrolling loops allows the use of SIMD instructions.
This reminds me of a (funny?) story, I tried to iterate over a simple vector of ints and doing a sum or something like that.
The compiler (msc v11) vectorized the loop and it ran pretty fast.
Then I tried to use range-based for loop of C++11: for( type x:arr ) { ... } and to my surprise the compiler failed to vectorize in this case,
because range-based loop uses iterators (=pointers for vector) and somehow it failed to optimize this case.
The same of course applies to iterating the standard way using iterators.
I wonder if the most recent version of their compiler still has problems with this.
matthewlai
Posts: 793
Joined: Sun Aug 03, 2014 4:48 am
Location: London, UK

Re: Initializing portions of arrays

Post by matthewlai »

mar wrote:
mcostalba wrote: Ok, done

Code: Select all

#include <iostream>
 
using namespace std;
 
template<typename T, typename U> T Max&#40;T&& f, U&& s&#41;
&#123; return s > f ? T&#40;s&#41; &#58; T&#40;f&#41;; &#125;
 
 
class A
&#123;
public&#58;
 
constexpr static float MY_CONSTANT = 5.0f;
&#125;;
 
 
int main&#40;)
&#123;
cout << Max&#40;A&#58;&#58;MY_CONSTANT, 1.0f&#41; << endl;
 
return 0;
&#125;
So I have to use constexpr, thanks. However I'm still reluctant to switch to C++11 (I remember msc had problems with constexpr until version 12), but that's a different story,
I most likely will (sooner or later).
I just tried to use plain static const float MY_CONSTANT=xx and msc doesn't even allow this (complaining it needs to be integral type),
so probably the constant I was referring to was not a float (but it doesn't matter).
I like the idea of passing compatible types as arguments (especially useful for containers).
But I think in this case it might be dangerous because Max( 1, 3.75 ) will return 3, which is not what one would expect so I slightly prefer to get an error instead.
It's one of the idiocracies of C++. Only integral type static constants can be initialized in class. It's not compiler-specific.

You can make the type of both parameters the same template argument. That way when you have something like Max(1, 3.75), it will tell you the template parameter cannot be inferred, and you have to specify it explicitly, either Max<double>(1, 3.75) or Max<int>(1, 3.75), depending on what behaviour you want.

That is in fact how std::max is defined. So it's very hard to get unintentional truncation.
Last edited by matthewlai on Sat Feb 21, 2015 5:22 pm, edited 1 time in total.
Disclosure: I work for DeepMind on the AlphaZero project, but everything I say here is personal opinion and does not reflect the views of DeepMind / Alphabet.