我需要存储在整数变量中的初始化数据的大小。
假设。
u32 var = 0x0; should return 0
u32 var = 0x12; should return 1
u32 var = 0x1234; should return 2
u32 var = 0x123456; should return 3
u32 var = 0x12345678; should return 4
答案 0 :(得分:1)
log2(x)将为您提供二进制值的指数。一些C实现已经内置了这个功能。如果没有,这里有一些替代方案:How to write log base(2) in c/c++
可以对得到的指数进行划分和舍入,以便提供所需的值。
首次尝试(未经测试)是:
int byteCount(const int x)
{
if (x == 0) return 0; /* Avoid error */
return (int)trunc((log10(x)/log10(2))/8+1);
}
<强>更新强>: 看来我的代码字面意思。这是一个优化版本:
int byteCount(const u32 x)
{
if (x == 0) return 0; /* Avoid error */
return (int)trunc((log10(x)/0.301029995663981)/8+1);
}
答案 1 :(得分:1)
您需要计算非零字节数吗?
u8 countNonZeroBytes(u32 n) {
u8 result = n == 0 ? 0 : 1;
while (n >> 8 != 0) {
result++;
n = n >> 8;
}
return result;
}
答案 2 :(得分:0)
这可以根据您的要求给出答案。
u8 CountNonZeroBytes(u32 n) {
u32 mask = 0xFF;
u8 i, result = 0;
for (i = 0; i < sizeof(n); i++) {
if (mask & n)
result++;
mask = mask << 8;
}
return result;
}
答案 3 :(得分:0)
这是log2
的“前导零”方法的一个版本,它不使用浮点数。优化器将进行循环展开,因此它等同于“四个比较”版本。它比浮点版本快 4x 。
u32
bytecnt(u32 val)
{
int bitno;
u32 msk;
u32 bycnt;
bycnt = 0;
for (bitno = 24; bitno >= 0; bitno -= 8) {
msk = 0xFF << bitno;
if (val & msk) {
bycnt = bitno / 8;
bycnt += 1;
break;
}
}
return bycnt;
}
这是一个比较两种算法的测试程序[请注意,我使用的是Jaime的浮点版本进行比较]:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
typedef unsigned int u32;
#define RATIO \
do { \
if (tvslow > tvfast) \
ratio = tvslow / tvfast; \
else \
ratio = tvfast / tvslow; \
printf("%.3fx\n",ratio); \
} while (0)
int opt_f;
// _tvgetf -- get timestamp
double
_tvgetf(void)
{
struct timespec ts;
double val;
#if 1
clock_gettime(CLOCK_REALTIME,&ts);
#else
clock_gettime(CLOCK_MONOTONIC_RAW,&ts);
#endif
val = ts.tv_nsec;
val /= 1e9;
val += ts.tv_sec;
return val;
}
u32
bytecnt(u32 val)
{
int bitno;
u32 msk;
u32 bycnt;
bycnt = 0;
for (bitno = 24; bitno >= 0; bitno -= 8) {
msk = 0xFF << bitno;
if (val & msk) {
bycnt = bitno / 8;
bycnt += 1;
break;
}
}
return bycnt;
}
u32
bytecnt2(u32 val)
{
u32 bycnt;
do {
if (val & (0xFF << 24)) {
bycnt = 4;
break;
}
if (val & (0xFF << 16)) {
bycnt = 3;
break;
}
if (val & (0xFF << 8)) {
bycnt = 2;
break;
}
if (val & (0xFF << 0)) {
bycnt = 1;
break;
}
bycnt = 0;
} while (0);
return bycnt;
}
int byteCount(const int x)
{
if (x == 0) return 0; /* Avoid error */
return (int)trunc((log10(x)/log10(2))/8+1);
}
u32 byteCount2(u32 x)
{
if (x == 0) return 0; /* Avoid error */
return (u32)trunc((log10(x)/log10(2))/8+1);
}
static double l2 = 0;
u32 byteCount3(u32 x)
{
if (x == 0) return 0; /* Avoid error */
return (u32)trunc((log10(x)/l2)/8+1);
}
u32 byteCount4(u32 x)
{
if (x == 0) return 0; /* Avoid error */
return (u32)trunc((log10(x)/0.301029995663981)/8+1);
}
void
test(u32 val)
{
u32 bicnt;
u32 lgcnt;
bicnt = bytecnt(val);
lgcnt = byteCount2(val);
if (bicnt != lgcnt) {
printf("%8.8X: bicnt=%8.8X lgcnt=%8.8X\n",
val,bicnt,lgcnt);
exit(1);
}
}
double
timeit(u32 (*proc)(u32),const char *who)
{
double tvbeg;
double tvdif;
double tvper;
int trycnt;
int trymax;
u32 val;
trymax = 1000000;
trymax *= 10;
tvbeg = _tvgetf();
for (trycnt = 1; trycnt < trymax; ++trycnt) {
for (val = 1; val != 0; val <<= 1)
proc(val);
}
tvdif = _tvgetf();
tvdif -= tvbeg;
tvper = tvdif;
tvper /= trymax;
tvper /= 32;
printf("%.9f %.9f -- %s\n",tvdif,tvper,who);
return tvdif;
}
int
main(int argc,char **argv)
{
char *cp;
u32 val;
double tvfast;
double tvslow;
double ratio;
--argc;
++argv;
l2 = log10(2);
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'f':
opt_f = 1;
break;
}
}
// do quick validity test
printf("quick validity test ...\n");
test(0);
for (val = 1; val != 0; val <<= 1)
test(val);
// speed tests
printf("speed tests ...\n");
tvfast = timeit(bytecnt2,"bytecnt2");
tvslow = timeit(bytecnt,"bytecnt");
RATIO;
tvslow = timeit(byteCount2,"byteCount2");
RATIO;
tvslow = timeit(byteCount3,"byteCount3");
RATIO;
tvslow = timeit(byteCount4,"byteCount4");
RATIO;
// do full validity test
if (opt_f) {
for (val = 1; val != 0; ++val)
test(val);
}
return 0;
}
以下是测试输出:
quick validity test ...
speed tests ...
1.180300474 0.000000004 -- bytecnt2
1.363260031 0.000000004 -- bytecnt
1.155x
6.759670734 0.000000021 -- byteCount2
5.727x
6.653460503 0.000000021 -- byteCount3
5.637x
6.636421680 0.000000021 -- byteCount4
5.623x
<强>更新强>
为了清楚起见,我的byteCount提议未进行优化。例如,您可以将log10(2)转换为常量。我认为这会有明显的性能提升。
我已更新测试程序以合并更改。
但是,优化器已经消除了原始代码中的log10(2)
(即只有一次调用log10
),因此手动编码它几乎没有效果。
其他几个人为零字节数做了类似的循环实现[我不相信OP想要的,基于“sizeof”短语]。
事实证明,最快的版本也是最简单,最无聊的,而且[IMO]最直接。这是我添加的内容:bytecnt2
,这是Paul R建议的“四个比较”。
使用更好[或可比较]的性能来做浮点数会很好。我会给它一个通过,即使是2倍[仅供参考,在得到结果之前,我认为他们将成为球场(例如在10%以内)]。
但是,F.P。对于OP的预期结果,实现也很简单。
答案 4 :(得分:0)
如果您不介意使用gcc扩展,这是一个非常好的解决方案:
顺便说一句,你的问题应该更清楚。你的术语令人困惑。 “大小”和“初始化”都是在其既定含义之外使用的。
额外的安全/便携:(可能不需要):
size_t leading_zeroes(uint32_t v)
{
if (v == 0) // __builtin_clz is undefined for 0
return sizeof(uint32_t) * CHAR_BIT;
return __builtin_clz(v);
}
size_t trailing_bytes(uint32_t v)
{
return sizeof(uint32_t) - leading_zeroes(v) / CHAR_BIT;
}
更简单的版本:
size_t leading_zeroes(uint32_t v)
{
if (v == 0) // __builtin_clz is undefined for 0
return 32;
return __builtin_clz(v);
}
size_t trailing_bytes(uint32_t v)
{
return 4 - leading_zeroes(v) / 8;
}