How to compute non-integer (fractional) log2 at compile time in C - c

There are various macro-based solutions out there to compute the integer-valued log2 at compile time, but what if you need a bit more precision than what you get with integers, i.e. a few binary places after the binary point? It doesn't matter whether the value generated is a floating point expression, or a fixed-point scaled integer expression, as long as it evaluates to a compile-time constant value.
What is this useful for, you may ask? The application I had in mind was to compute the number of bits needed to optimally pack a structure whose fields have value sets that don't span a power of 2 range.

I've come up with the following - it's not particularly inventive, but it works, and doesn't slow the compilation totally to a crawl. IOW, it does what I needed it to do - add a couple (here: dozen) binary places' worth of precision after the binary point.
It works by representing the number as a power of 2 and trial-multiplying it by coefficients that happen to have log2 values equal to a binary fraction (2^-n). Multiplying by such coefficients is equivalent to adding together the logarithms, and thus the FRAC_LOG2 macro expands to a sum with elements selected with nested ternary expressions.
#define IROOT2_1 .7071067812 // 2^-(2^-1)
#define IROOT2_2 .8408964153 // 2^-(2^-2)
#define IROOT2_3 .9170040432 // 2^-(2^-3)
#define IROOT2_4 .9576032807 // 2^-(2^-4)
#define IROOT2_5 .9785720621 // 2^-(2^-5)
#define IROOT2_6 .9892280132 // 2^-(2^-6)
#define IROOT2_7 .9945994235 // 2^-(2^-7)
#define IROOT2_8 .9972960561 // 2^-(2^-8)
#define IROOT2_9 .9986471129 // 2^-(2^-9)
#define IROOT2_A .9993233275 // 2^-(2^-10)
#define IROOT2_B .9996616065 // 2^-(2^-11)
#define IROOT2_C .9998307889 // 2^-(2^-12)
#define BIT_SCAN_REV(n) \
(n>>15?15:n>>14?14:n>>13?13:n>>12?12:n>>11?11:n>>10?10:n>>9?9:\
n>>8?8:n>>7?7:n>>6?6:n>>5?5:n>>4?4:n>>3?3:n>>2?2:n>>1?1:0)
#define FRAC_LOG2_1(m,n) (1./4096.)*\
((m<=n*IROOT2_1?2048:0)+FRAC_LOG2_2(m,n*(m<=n*IROOT2_1?IROOT2_1:1)))
#define FRAC_LOG2_2(m,n) ((m<=n*IROOT2_2?1024:0)+FRAC_LOG2_3(m,n*(m<=n*IROOT2_2?IROOT2_2:1)))
#define FRAC_LOG2_3(m,n) ((m<=n*IROOT2_3?512:0)+FRAC_LOG2_4(m,n*(m<=n*IROOT2_3?IROOT2_3:1)))
#define FRAC_LOG2_4(m,n) ((m<=n*IROOT2_4?256:0)+FRAC_LOG2_5(m,n*(m<=n*IROOT2_4?IROOT2_4:1)))
#define FRAC_LOG2_5(m,n) ((m<=n*IROOT2_5?128:0)+FRAC_LOG2_6(m,n*(m<=n*IROOT2_5?IROOT2_5:1)))
#define FRAC_LOG2_6(m,n) ((m<=n*IROOT2_6?64:0)+FRAC_LOG2_7(m,n*(m<=n*IROOT2_6?IROOT2_6:1)))
#define FRAC_LOG2_7(m,n) ((m<=n*IROOT2_7?32:0)+FRAC_LOG2_8(m,n*(m<=n*IROOT2_7?IROOT2_7:1)))
#define FRAC_LOG2_8(m,n) ((m<=n*IROOT2_8?16:0)+FRAC_LOG2_9(m,n*(m<=n*IROOT2_8?IROOT2_8:1)))
#define FRAC_LOG2_9(m,n) ((m<=n*IROOT2_9?8:0)+FRAC_LOG2_A(m,n*(m<=n*IROOT2_9?IROOT2_9:1)))
#define FRAC_LOG2_A(m,n) ((m<=n*IROOT2_A?4:0)+FRAC_LOG2_B(m,n*(m<=n*IROOT2_A?IROOT2_A:1)))
#define FRAC_LOG2_B(m,n) ((m<=n*IROOT2_B?2:0)+FRAC_LOG2_C(m,n*(m<=n*IROOT2_B?IROOT2_B:1)))
#define FRAC_LOG2_C(m,n) (m<=n*IROOT2_C?1:0)
#define FRAC_LOG2(n) (BIT_SCAN_REV(n) + FRAC_LOG2_1(1<<BIT_SCAN_REV(n), n))
It's not exactly cheap, of course - for a 2-digit number, it expands to about 700kb of code that the compiler has to dig through, but it has precision of over 5 fractional decimal digits.
A work around is to store the integral result of BIT_SCAN_REV in an enum, so that it's just a couple letters instead of about 170:
enum {
input = 36,
bsr = BIT_SCAN_REV(input),
bsr_ = 1<<bsr_,
};
static const float output = bsr + FRAC_LOG2_1(bsr_, input);
Another way of doing this at a much lower memory cost, without recursive macros, would require an include file to be used any time a value is to be computed.

Related

Asking a predefined value as a float(or string) on an `#if` macro

I want to condition in an #if on the float(or string) value of a predefined variable.
As I saw if the value of the predefined variable is a whole number the #if is working good. But, if it is a float or a string, the if is not working as expected.
For example:
#define _VER_ = 103
#if _VER_ == 103
//Do somthing
#endif
The above code is working as expected, the #if becomes active/not active according to the _VER_ value. But, if the _VER_ value will be set to 1.0.3 or to "1.0.3" the #if is not working as expected.
For example:
#define _VER_ = 1.0.3
#if _VER_ == 1.0.3
//Do somthing
#endif
Or this:
#define _VER_ = "1.0.3"
#if _VER_ == "1.0.3"
//Do somthing
#endif
Both code example are not working as expected, the #if stays inactive regardless with the _VER_ value.
How to make this working properly?
The pre-processor is not able to do string comparisons at all, and floating point values in #if directives are not supported by the standard either. But even if they were comparing floating point is always critical due to rounding issues (keep in mind that you cannot even represent many of such simple numbers like 0.1 exactly as they are periodic in binary), see e.g. here or here, thus you cannot compare floating points safely either (most likely that's why they are not supported...).
What you could do, though, is having three distinct integral values:
#define MAJOR 1
#define MINOR 0
#define REVISION 3
Now you can do comparisons on these single values individually like:
#if MAJOR > 1 || MAJOR == 1 && MINOR > 0
// anything after 1.0.x
What you could do as well is combining these values into a single integer value by shifting them appropriately, e. g.
#define VERSION MAKE_VERSION(MAJOR, MINOR, REVISION)
#define MAKE_VERSION(X, Y, Z) MAKE_VERSION_(X, Y, Z)
// intermediate step necessary to resolve the version parts correctly
#define MAKE_VERSION_(X, Y, Z) (X ## lu << 16 | Y ## lu << 8 | Z ## lu)
Adding lu suffixes: long is guaranteed large enough by the standard such that shifting by 16 bit will fit into the type (which is not guaranteed for int!). You might experiment with other offsets to make the result fit into int and then leaving out the suffix (e. g. shifting by 8 or 12 instead of 16) or to allow more sub-versions (e. g. by shifting by 20 instead of 16).
Multiplying by 10000 and 100 would do the trick as well and result in more human readable version numbers (in decimal notation at least).
Finally you could create a version string by another macro:
#define VERSION_STRING MAKE_VERSION(MAJOR, MINOR, REVISION)
#define MAKE_VERSION(X, Y, Z) MAKE_VERSION_(X, Y, Z)
// intermediate step needed for correct stringification
#define MAKE_VERSION_(X, Y, Z) #X "." #Y "." #Z
Side note:
#define _VER_ = 103
Is plain wrong for two reasons:
The pre-processor does nothing else than pure text processing, it is not aware of any C code. The assignment sign (=) will be included in text replacement anywhere you use it (so #if _VER_ == 103 will be expanded to #if = 103 == 103).
Identifiers starting with an underscore followed by a capital character are reserved, using them results in undefined behaviour (note: identifiers with two subsequent underscores – anywhere – as well).
You can split the version up in the way that makes most sense anyway, namely:
#define VERS_MAJOR 1
#define VERS_MINOR 0
#define VERS_PATCH 3
And then do pre-processor comparisons such as:
#if (VERS_MAJOR == 1) && (VERS_MINOR == 0)
...
If you need to get 1.0.3 as output then convert it to a string literal:
#define STR(x) #x
#define STR_VERSION(a,b,c) STR(a) "." STR(b) "." STR(c)
#define VERSION STR_VERSION(VERS_MAJOR,VERS_MINOR,VERS_PATCH)
...
puts(VERSION); // prints 1.0.3

C defines proper usage

A problem with C defines:
#define RANGE1_ms 64
#define FS 16000.0f
#define BS 64
#define COUNTER1_LIMIT ( ( RANGE1_ms/1000.0f)* FS/BS )
This gives 16.0 for COUNTER1_LIMIT.
Debugging the code in Eclipse shows all is OK.
However, when I build release version from a makefile, it produces different result. I have narrowed the problem down to this line:
if( counter1 == (uint16_t)COUNTER1_LIMIT )
{
...
}
where counter1 is uint16_t.
What am I doing wrong with those defines?
This solves the problem:
if( counter1 == 16 )
but that's not the way to go.
The reason for the bug is that floating point numbers are accurate, see the millions of others posts on SO about this, for example Why Are Floating Point Numbers Inaccurate?
But in your specific case the problem is that you use floating point where it isn't needed or useful. You just need a compile-time constant. Fix the expression like this:
#define RANGE1_ms 64u
#define COUNTER1_LIMIT (16000u / 64u * RANGE1_ms / 1000u )
Avoid FP math with the pre-processor.
// Avoid the following
#define FS 16000.0f
#define COUNTER1_LIMIT ( ( RANGE1_ms/1000.0f)* FS/BS )
Alternative 1: use integer math that rounds quotients to nearest. Adding half the divisor works when dividend/divisor are positive.
#define RANGE1_ms 64
#define FS 16000
#define BS 64
#define ms_PER_s 1000
#define COUNTER1_LIMIT_N (1ul * RANGE1_ms * FS)
#define COUNTER1_LIMIT_D (1ul * ms_PER_s * BS )
#define COUNTER1_LIMIT_I ((COUNTER1_LIMIT_N + COUNTER1_LIMIT_D/2)/COUNTER1_LIMIT_D)
#define COUNTER1_LIMIT_F (1.0*COUNTER1_LIMIT_N/COUNTER1_LIMIT_D)
if (counter1 == COUNTER1_LIMIT_I)
Alternative 2:
When constants like FS truly need to be FP like 16123.4f, use a rounding function rather than truncation with an integer cast like (uint16_t)
#include <math.h>
if (counter1 == lround(COUNTER1_LIMIT))
Alternative 3:
When constants like FS truly need to be FP like 16123.4f, add 0.5 then truncate with an integer cast like (uint16_t). The add 0.5 trick works when the value is positive. It fails with a number of values when adding 0.5 is not exact. Yet has the advantage: it can be computed, as in OP's case, at compile time.
if (counter1 == (uint16_t)(COUNTER1_LIMIT + 0.5))
Floating point numbers are susceptible to loss of precision. The 16.0 can get converted to 15.9999 when loaded as a temporary. Casting it to uint16_t makes it 15 that doesn't compare against 16.
You need a function to round the floating point values. That you can call on COUNTER1_LIMIT.
Other option would be to promote counter1 to float and check if the absolute difference between this and COUNTER1_LIMIT is less than a small value like 0.001.
It can be done as
float diff = counter1 - COUNTER1_LIMIT;
if(diff > -0.001 && diff < 0.001) {
...
}
This should work for you.
RANGE1_ms/1000.0f is 64/1000.0f . The problem is, computers cannot represent 0.064 exactly. Ultimately, numbers are represented as a*2b, where a and b are integers, which is impossible for 0.064 . So, RANGE1_ms/1000.0f is approximately 0.064. When you multiply it by 16000f and divide by 64, you receive approximately 16f. It may be 15.999999, or 16.000003, or something. When you cast it to uint16_t, it becomes either 15 or 16.
One way is to cast it as (uint16_t)(COUNTER1_LIMIT+0.5). It will round it to the closest integer. Alternatively, if your COUNTER1_LIMIT is always integer (that is you know that the expression should produce integer number), you may do
#define FS_BY_1000 16
#define COUNTER1_LIMIT (RANGE1_ms * FS_BY_1000/BS)

C macro to get the smallest power of two greater than a given number

I need a C macro to get the smallest of power two greater than a given number.
For example, FIRSTFREEBIT(0x16) (binary 1_0110) must be equal to 0x20.
I am going to use it as:
#include <someheader.h> // defines SOME_X and SOME_Y
enum {
x = SOME_X,
y = SOME_Y,
z = FIRSTFREEBIT(x|y),
t = z << 1,
};
A similar, but slightly different SO question:
Algorithm for finding the smallest power of two that's greater or equal to a given value
Here's my code, you are welcome to invent something better:
#define __OR_RSHIFT__(n,x) ((x)|(x)>>n)
#define FIRST_UNUSED_BIT(x) (1+__OR_RSHIFT__(16,__OR_RSHIFT__(8,__OR_RSHIFT__(4,__OR_RSHIFT__(2,__OR_RSHIFT__(1,x))))))
Look at the __builtin_clz GCC intrinsic. It will give you the number of leading zero bits, which could be used to determine the position of the first bit set. Then do a left bit shift of 1, times the position.

How to generate a series of random numbers with the C/C++ preprocessor

I would like to generate a series of random numbers with the C preprocessor, and store them in variables for use by my program.
OBJECTIVES:
I would like to generate a "unique" set of random numbers every time I build my program. A small subset of the variables storing the random numbers will be overwritten with meaningful (i.e. non-random) numbers. I would like it to be impossible for a hacker, by debugging the program or comparing multiple builds, to be able to differentiate the meaningful numbers from the random numbers. I would like the build process to be automated and self-contained. I would like the implementation to be portable across Visual Studio and GCC.
CLARIFICATIONS:
The calculations must be done at compile time, not at program execution. Anyone debugging the program should only be able to see, for example, a variable being initialized to a constant (the random number).
The random numbers should be integers.
The random number generator should be seeded, in some manner, from __DATE__ and __TIME__, so that different builds will yield different random numbers.
It would be preferable, but not absolutely necessary, to be able to specify a range for the random numbers (e.g. from 1 to 100).
It would be preferable, but not absolutely necessary, to be able to specify the total number of random numbers to generate (e.g. declare 1000 variables and initialize each to a random number).
ATTEMPTS SO FAR:
Previous thread on arithmetic in the preprocessor: Can the C preprocessor perform integer arithmetic?
The take-away is that the #if condition can evaluate arithmetic.
Googling reveals that besides arithmetic, shift and bit operations can also be evaluated by the #if. I have confirmed this with Visual Studio C++.
Candidates for simple random number generators: http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369B5E30.65A55FD1#stat.fsu.edu
Any one of these generators, or any generator that is impossible to reverse engineer from a given series of random numbers, would be fine because I don't need a particularly well behaved generator. For the sake of this exercise, we can use the following as an example:
unsigned long jcong=380116160;
#define CONG (jcong=69069*jcong+1234567)
I think the basic problem is that there is state that is stored in the variable jcong between successive calls to the generator. Variable assignment is not supported in the preprocessor, as far as I know. Perhaps there is some clever recursive macro that can do the trick?
The closest I could get, but not satisfying my objective of being performed by the preprocessor, is:
unsigned long jcong=380116160;
unsigned long randomBlock[] = {jcong=69069*jcong+1234567, jcong=69069*jcong+1234567};
I have confirmed in Visual Studio C++ that this does indeed initialize the array members to different random numbers. However, the debugger still steps through the initialization.
This is a pure programming/implementation question, so please, no proselytizing on the evils of the preprocessor or the futility of fighting hackers.
So, here is the solution that is close to requirements:
// pprand.h
#include <boost/preprocessor/slot.hpp>
#ifndef PP_RAND_SEED
#define PP_RAND_SEED (((PP_RAND_MIN + PP_RAND_MAX) * 0x1f7) ^ 0x1e3f75a9)
#endif
#define BOOST_PP_VALUE ((PP_RAND_SEED * 214013 + 2531011) % 65536)
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#undef PP_RAND_SEED
#define PP_RAND_SEED BOOST_PP_SLOT(1)
#define BOOST_PP_VALUE (PP_RAND_MIN + PP_RAND_SEED % (PP_RAND_MAX - PP_RAND_MIN))
#include BOOST_PP_ASSIGN_SLOT(2)
#undef BOOST_PP_VALUE
#ifdef PP_RAND
#undef PP_RAND
#endif
#define PP_RAND BOOST_PP_SLOT(2)
You can use it like this:
// Pseudo random number range.
#define PP_RAND_MIN 0
#define PP_RAND_MAX 100
// Pseudo random number seed.
#define PP_RAND_SEED 123
#include "pprand.h"
// Got it!
#pragma message("PP_RAND value:" _CRT_STRINGIZE(PP_RAND))
To read more about this approach visit my blog: http://alexander-stoyan.blogspot.com/2012/07/getting-pseudo-random-numbers-at.html
You have to replace the Random generator sequence with something that actually generates acceptable semi-random values, but that part should be easy.
You have to define a random seed with -DSEED=... at compilation.
No idea how to do that with __TIME__ and __DATE__ because they are strings.
#include <stdio.h>
template <int N>
struct Random {
enum { value = 7 * Random<N-1>::value + 17 };
};
template <>
struct Random<1> {
enum { value = SEED};
};
template <int N, int BEG, int END>
struct RandomIn {
enum { value = BEG + Random<N>::value % (END-BEG) };
};
int main() {
printf("%d %d", RandomIn<2, 5, 10>::value, RandomIn<3, 5, 10>::value);
return 0;
}

Question about round_up macro

#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
With the above macro, could someone please help me on understanding the "(s)-1" part, why's that?
and also macros like:
#define PAGE_ROUND_DOWN(x) (((ULONG_PTR)(x)) & (~(PAGE_SIZE-1)))
#define PAGE_ROUND_UP(x) ( (((ULONG_PTR)(x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1)) )
I know the "(~(PAGE_SIZE-1)))" part will zero out the last five bits, but other than that I'm clueless, especially the role '&' operator plays.
Thanks,
The ROUND_UP macro is relying on integer division to get the job done. It will only work if both parameters are integers. I'm assuming that N is the number to be rounded and S is the interval on which it should be rounded. That is, ROUND_UP(12, 5) should return 15, since 15 is the first interval of 5 larger than 12.
Imagine we were rounding down instead of up. In that case, the macro would simply be:
#define ROUND_DOWN(N,S) ((N / S) * S)
ROUND_DOWN(12,5) would return 10, because (12/5) in integer division is 2, and 2*5 is 10. But we're not doing ROUND_DOWN, we're doing ROUND_UP. So before we do the integer division, we want to add as much as we can without losing accuracy. If we added S, it would work in almost every case; ROUND_UP(11,5) would become (((11+5) / 5) * 5), and since 16/5 in integer division is 3, we'd get 15.
The problem comes when we pass a number that's already rounded to the multiple specified. ROUND_UP(10, 5) would return 15, and that's wrong. So instead of adding S, we add S-1. This guarantees that we'll never push something up to the next "bucket" unnecessarily.
The PAGE_ macros have to do with binary math. We'll pretend we're dealing with 8-bit values for simplicity's sake. Let's assume that PAGE_SIZE is 0b00100000. PAGE_SIZE-1 is thus 0b00011111. ~(PAGE_SIZE-1) is then 0b11100000.
A binary & will line up two binary numbers and leave a 1 anywhere that both numbers had a 1. Thus, if x was 0b01100111, the operation would go like this:
0b01100111 (x)
& 0b11100000 (~(PAGE_SIZE-1))
------------
0b01100000
You'll note that the operation really only zeroed-out the last 5 bits. That's all. But that was exactly that operation needed to round down to the nearest interval of PAGE_SIZE. Note that this only worked because PAGE_SIZE was exactly a power of 2. It's a bit like saying that for any arbitrary decimal number, you can round down to the nearest 100 simply by zeroing-out the last two digits. It works perfectly, and is really easy to do, but wouldn't work at all if you were trying to round to the nearest multiple of 76.
PAGE_ROUND_UP does the same thing, but it adds as much as it can to the page before cutting it off. It's kinda like how I can round up to the nearest multiple of 100 by adding 99 to any number and then zeroing-out the last two digits. (We add PAGE_SIZE-1 for the same reason we added S-1 above.)
Good luck with your virtual memory!
Using integer arithmetic, dividing always rounds down. To fix that, you add the largest possible number that won't affect the result if the original number was evenly divisible. For the number S, that largest possible number is S-1.
Rounding to a power of 2 is special, because you can do it with bit operations. A multiple of 2 will aways have a zero in the bottom bit, a multiple of 4 will always have zero in the bottom two bits, etc. The binary representation of a power of 2 is a single bit followed by a bunch of zeros; subtracting 1 will clear that bit, and set all the bits to the right. Inverting that value creates a bit mask with zeros in the places that need to be cleared. The & operator will clear those bits in your value, thus rounding the value down. The same trick of adding (PAGE_SIZE-1) to the original value causes it to round up instead of down.
The page rounding macros assume that `PAGE_SIZE is a power of two, such as:
0x0400 -- 1 KiB
0x0800 -- 2 KiB`
0x1000 -- 4 KiB
The value of PAGE_SIZE - 1, therefore, is all one bits:
0x03FF
0x07FF
0x0FFF
Therefore, if integers were 16 bits (instead of 32 or 64 - it saves me some typing), then the value of ~(PAGE_SIZE-1) is:
0xFC00
0xFE00
0xF000
When you take the value of x (assuming, implausibly for real life, but sufficient for the purposes of exposition, that ULONG_PTR is an unsigned 16-bit integer) is 0xBFAB, then
PAGE_SIZE PAGE_ROUND_DN(0xBFAB) PAGE_ROUND_UP(0xBFAB)
0x0400 --> 0xBC00 0xC000
0x0800 --> 0xB800 0xC000
0x1000 --> 0xB000 0xC000
The macros round down and up to the nearest multiple of a page size. The last five bits would only be zeroed out if PAGE_SIZE == 0x20 (or 32).
Based on the current draft standard (C99) this macro is not entirely correct however, note that for negative values of N the result will almost certainly be incorrect.
The formula:
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
Makes use of the fact that integer division rounds down for non-negative integers and uses the S - 1 part to force it to round up instead.
However, integer division rounds towards zero (C99, Section 6.5.5. Multiplicative operators, item 6). For negative N, the correct way to 'round up' is: 'N / S', nothing more, nothing less.
It gets even more involved if S is also allowed to be a negative value, but let's not even go there... (see: How can I ensure that a division of integers is always rounded up? for a more detailed discussion of various wrong and one or two right solutions)
The & makes it so.. well ok, lets take some binary numbers.
(with 1000 being page size)
PAGE_ROUND_UP(01101b)=
01101b+1000b-1b & ~(1000b-1b) =
01101b+111b & ~(111b) =
01101b+111b & ...11000b = (the ... means 1's continuing for size of ULONG)
10100b & 11000b=
10000b
So, as you can see(hopefully) This rounds up by adding PAGE_SIZE to x and then ANDing so it cancels out the bottom bits of PAGE_SIZE that are not set
This is what I use:
#define SIGN(x) ((x)<0?-1:1)
#define ROUND(num, place) ((int)(((float)(num) / (float)(place)) + (SIGN(num)*0.5)) * (place))
float A=456.456789
B=ROUND(A, 50.0f) // 450.0
C=ROUND(A, 0.001) // 456.457

Resources