On 05/09/2012 13:33, James Kuyper wrote:

> (..) Initializers for an object of static storage

> duration must be constant expressions. In C++, a const variable

> initialized with a constant expression can itself be used as a constant

> expression, but in C it is not allowed. You'd have to re-write this as a

> single constant expression, and you'll have to be careful to avoid

> running into line length limitations if you do so. I haven't checked to

> be sure, but you might have settle for fewer iterations.
I think that I found a conforming workaround: use enums instead

of constants. There is the limitation that enums can only be

trusted to hold 15 bits, but I can workaround that too using

the following ZS and ZG macros.

// select temporary type uw

#include <limits.h>

#ifdef ULLONG_MAX

typedef unsigned long long uw;

#else

typedef unsigned long uw;

#endif

// Utility macro to set symbol s to value v (60-bit capacity)

#define ZS(s,v) enum{e0##s=(v)&32767,e1##s=(v)>>15&32767,\

e2##s=(v)>>15>>15&32767,e3##s=(v)>>15>>15>>15&3276 7}

// Utility macro to get value of symbol s (60-bit capacity)

#define ZG(s) (((((uw)e3##s<<15|e2##s)<<15|e1##s))<<15|e0##s)

// Set of macros to compute floor(sqrt(x)) for x>0.

// Find a raw approximation of sqrt(x)

#define SQRT0(x) ((uw)8<<(3*((x)<512?0

x)>>15<1?1

x)>>15<64?2:\

(x)>>15>>9<8?3

x)>>15>>15<8?4

x)>>15>>15>>9<1?5: \

(x)>>15>>15>>15<1?6

x)>>15>>15>>15<64?7

x)>>15>> 15>>15>>9<8?8:9)))

// One Newton-Raphson refinement step

#define SQRT1(x,a) (((x)/(a)+(a))/2)

// Four Newton-Raphson refinement steps

#define SQRT4(x,a) (SQRT1(x,SQRT1(x,SQRT1(x,SQRT1(x,a)))))

// Final tweak to get exact value

#define SQRTF(x,a) (SQRT1(x,a)-(SQRT1(x,a)>(a)?1:0))

#define EXPECTED 400000000

// Now we want:

// struct foo * bar[EXPECTED+ceil(12*sqrt(EXPECTED)];

// that is

// struct foo * bar[EXPECTED+1+floor(sqrt(12*12*EXPECTED-1)];

#define KVALUE (12*12*(uw)(EXPECTED)-1)

ZS(kExTmp0, SQRT0(KVALUE)); // first approximation

ZS(kExTmp1, SQRT4(KVALUE,ZG(kExTmp0))); // improve..

ZS(kExTmp2, SQRT4(KVALUE,ZG(kExTmp1))); // improve..

ZS(kExTmp3, SQRT4(KVALUE,ZG(kExTmp2))); // improve..

#define KROOT SQRTF(KVALUE,ZG(kExTmp3)) // finalize

struct foo * bar[EXPECTED+1+KROOT];

This works and (as far as I can tell) is conformant, but many

will understandably frown on it as hairy. Especially if we push

it further and implement floating-point-as-enum.

Questions: In C11, what liberties do we have?

In particular,

- can we define the size of a static array (non-VLA)

using a static const long ?

- can we use a static const long freely in an

expression that defines another static const long ?

- can we use floating point arithmetic in expressions defining

a static const long ?

- can we use exp() and log() in such expressions ?

Francois Grieu