数字及其对数作为编译常量而不手动更改两者?
Number and its logarithm as compile constants without manually changing both?
我有一个常量 WIDTH
,它始终是 2 的幂,例如#define WIDTH 1024
.
我有一个关联的 #define WIDTH_BINARY_LOG 10
,每次我修改 WIDTH
时,我 必须 更改它,使其成为 WIDTH
的二进制对数.这是不可取的,因为有时我会忘记这样做,结果事情变得一团糟。不幸的是 pow()
在宏中也不可用。
用法是
*z = zx >> WIDTH_BINARY_LOG
.
考虑到 WIDTH_BINARY_LOG
的最大可能值为 16
,我计划解决此问题,具体用法如下:
*z = zx >> BINARY_LOG(WIDTH)
具有以下定义:
#define BINARY_LOG_1 0
#define BINARY_LOG_2 1
#define BINARY_LOG_4 2
#define BINARY_LOG_8 3
#define BINARY_LOG_16 4
#define BINARY_LOG_32 5
#define BINARY_LOG_64 6
#define BINARY_LOG_128 7
#define BINARY_LOG_256 8
#define BINARY_LOG_512 9
#define BINARY_LOG_1024 10
#define BINARY_LOG_2048 11
#define BINARY_LOG_4096 12
#define BINARY_LOG_8192 13
#define BINARY_LOG_16384 14
#define BINARY_LOG_32768 15
#define BINARY_LOG_65536 16
#define BINARY_LOG(n) BINARY_LOG_##n
或
#define BINARY_LOG(n) BINARY_LOG_#n
然而,gcc 在每种情况下都抱怨得很厉害。我究竟做错了什么?假设上述方法完全不值得,其他人将如何解决这个问题?
可以用宏来完成。我在我的代码中使用了 this answer:
#define WIDTH 2048
#define BINARY_LOG_1 0
#define BINARY_LOG_2 1
#define BINARY_LOG_4 2
#define BINARY_LOG_8 3
#define BINARY_LOG_16 4
#define BINARY_LOG_32 5
#define BINARY_LOG_64 6
#define BINARY_LOG_128 7
#define BINARY_LOG_256 8
#define BINARY_LOG_512 9
#define BINARY_LOG_1024 10
#define BINARY_LOG_2048 11
#define BINARY_LOG_4096 12
#define BINARY_LOG_8192 13
#define BINARY_LOG_16384 14
#define BINARY_LOG_32768 15
#define BINARY_LOG_65536 16
#define PPCAT_NX(A, B) A ## B
#define BINARY_LOG(B) PPCAT_NX(BINARY_LOG_, B)
BINARY_LOG(WIDTH)
gcc -E test.c
的输出(仅宏替换阶段):
>gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 24 "test.c"
11
由于已经有可行的答案,我想指出一些不同的解决方案:
使用可在编译时求值的 constexpr (C++11) 从给定的指数计算 WIDTH。这看起来比使用宏恕我直言要好得多:(请参阅 Casey 在 c++11 fast constexpr integer powers 中的回答)
#include <cstdint>
constexpr int64_t ipow(int64_t base, int exp, int64_t result = 1) {
return exp < 1 ? result : ipow(base*base, exp/2, (exp % 2) ? result*base : result);
}
int64_t foo(int64_t base, int exp) {
return ipow(base, exp);
}
我有一个常量 WIDTH
,它始终是 2 的幂,例如#define WIDTH 1024
.
我有一个关联的 #define WIDTH_BINARY_LOG 10
,每次我修改 WIDTH
时,我 必须 更改它,使其成为 WIDTH
的二进制对数.这是不可取的,因为有时我会忘记这样做,结果事情变得一团糟。不幸的是 pow()
在宏中也不可用。
用法是
*z = zx >> WIDTH_BINARY_LOG
.
考虑到 WIDTH_BINARY_LOG
的最大可能值为 16
,我计划解决此问题,具体用法如下:
*z = zx >> BINARY_LOG(WIDTH)
具有以下定义:
#define BINARY_LOG_1 0
#define BINARY_LOG_2 1
#define BINARY_LOG_4 2
#define BINARY_LOG_8 3
#define BINARY_LOG_16 4
#define BINARY_LOG_32 5
#define BINARY_LOG_64 6
#define BINARY_LOG_128 7
#define BINARY_LOG_256 8
#define BINARY_LOG_512 9
#define BINARY_LOG_1024 10
#define BINARY_LOG_2048 11
#define BINARY_LOG_4096 12
#define BINARY_LOG_8192 13
#define BINARY_LOG_16384 14
#define BINARY_LOG_32768 15
#define BINARY_LOG_65536 16
#define BINARY_LOG(n) BINARY_LOG_##n
或
#define BINARY_LOG(n) BINARY_LOG_#n
然而,gcc 在每种情况下都抱怨得很厉害。我究竟做错了什么?假设上述方法完全不值得,其他人将如何解决这个问题?
可以用宏来完成。我在我的代码中使用了 this answer:
#define WIDTH 2048
#define BINARY_LOG_1 0
#define BINARY_LOG_2 1
#define BINARY_LOG_4 2
#define BINARY_LOG_8 3
#define BINARY_LOG_16 4
#define BINARY_LOG_32 5
#define BINARY_LOG_64 6
#define BINARY_LOG_128 7
#define BINARY_LOG_256 8
#define BINARY_LOG_512 9
#define BINARY_LOG_1024 10
#define BINARY_LOG_2048 11
#define BINARY_LOG_4096 12
#define BINARY_LOG_8192 13
#define BINARY_LOG_16384 14
#define BINARY_LOG_32768 15
#define BINARY_LOG_65536 16
#define PPCAT_NX(A, B) A ## B
#define BINARY_LOG(B) PPCAT_NX(BINARY_LOG_, B)
BINARY_LOG(WIDTH)
gcc -E test.c
的输出(仅宏替换阶段):
>gcc -E test.c
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
# 24 "test.c"
11
由于已经有可行的答案,我想指出一些不同的解决方案:
使用可在编译时求值的 constexpr (C++11) 从给定的指数计算 WIDTH。这看起来比使用宏恕我直言要好得多:(请参阅 Casey 在 c++11 fast constexpr integer powers 中的回答)
#include <cstdint>
constexpr int64_t ipow(int64_t base, int exp, int64_t result = 1) {
return exp < 1 ? result : ipow(base*base, exp/2, (exp % 2) ? result*base : result);
}
int64_t foo(int64_t base, int exp) {
return ipow(base, exp);
}