整数変数に格納された初期化データのサイズが必要です。C - 整数変数内の初期化データのサイズを確認します
とします。
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
整数変数に格納された初期化データのサイズが必要です。C - 整数変数内の初期化データのサイズを確認します
とします。
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
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);
}
UPDATE: 私のコードは、文字通りに解釈されているようです。
int byteCount(const u32 x)
{
if (x == 0) return 0; /* Avoid error */
return (int)trunc((log10(x)/0.301029995663981)/8+1);
}
このlog2(x)関数はどこにありますかmath.hで見つけられませんでした – user3423907
あなたのライブラリにそれがない場合は、私が提供したリンクに示唆されているように実装してください。基本的には:log2(x)= log10(x)/ log10(2) – Jaime
テストできるドラフトコードを追加しました – Jaime
ゼロ以外のバイト数をカウントする必要がありますか?
u8 countNonZeroBytes(u32 n) {
u8 result = n == 0 ? 0 : 1;
while (n >> 8 != 0) {
result++;
n = n >> 8;
}
return result;
}
正確には、私はこの機能を実行するためにcライブラリ関数が必要です。 – user3423907
@Andrew解決策はn = 0x12(1バイト)では正しくありません。 –
これを行うためのcライブラリ関数はありません。 –
これはあなたの要件に応じて答えを与えるはずです。ここで
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;
}
は、浮動小数点を使用していないlog2
に「先行ゼロ」アプローチのバージョンです。オプティマイザはループアンローリングを実行するので、 "4比較"バージョンと同等です。浮動小数点バージョンよりも速いのは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;
}
ここでは2つのアルゴリズム[Iは、比較のためハイメの浮動小数点バージョンを使用していることに注意してください]比較テストプログラムされています。ここでは
#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
更新日:
私:バイトの提案は、明確化のために、最適化されていません。たとえば、log10(2)を定数に変換できます。私はそれがパフォーマンスの顕著な増加を持っていると思う。
私は、変更を組み込むためにテストプログラムを更新しました。
しかし、オプティマイザはすでにを持っていたが、あなたの元のコード(log10
にすなわちだけコール)でlog10(2)
を排除し、それは全く影響をほとんどしていたハンドコーディング。
いくつか他の人が[私はOPが「はsizeof」というフレーズに基づいて、望んでいるとは考えていない]ゼロバイトの数に対して同様のループの実装を行いました。
最も速いバージョンは、最も単純で、最も退屈で、[IMO]が最も簡単であることが判明しました。これは私が追加したものです。bytecnt2
は、Paul Rによって提案された「4つの比較」です
浮動小数点を使用すると、パフォーマンスが向上します。 [FYI、結果を得る前に、が(たとえば10%以内)になると仮定しました。
しかし、F.P.実装はより少なく、OPの意図した結果のためには直接です。
IMO、4倍遅くて複雑なものは赤い旗です。微調整だけでなく、アプローチが正しくないことを示します。単純なビットシフト/マスキングが達成できるように、intをとり、比較的重量のある関数を使ってfloatに変換します。
Craig、私のbyteCount提案は、わかりやすくするために最適化されていません。たとえば、log10(2)を定数に変換できます。私はそれがパフォーマンスの顕著な増加を持っていると思う。 – Jaime
@Jaime私は自分の変更とテスト結果をもとに自分の答えを更新しました。 –
Craig、希望の結果を得るたびに「不正確な」アプローチはありません。読みやすさとパフォーマンスの間の妥協点です。数学者にとって私のアプローチはforループよりもはっきりしているかもしれません。もちろん、処理時間(マイクロ秒)がより広いプロセス(すなわち、秒)内で限界的でない限り、ほとんどの場合、性能は重要である。 – Jaime
あなたは利用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;
}
いずれかの4つの比較ゼロビットをリードする数えるか、単に行います。 –
「初期化済み」という意味ですか? "0x12"を含むu32のために、3つの最上位バイトはゼロに初期化されなければならなかった。そうでない場合は、3バイトのランダムなガベージとそれに続くu8の0x12があります。 – kfsone
'0x123456'で' 3'を生成したい場合、 '0x120056'はどうでしょうか? '2 '(すなわち、非ゼロバイトの数)または' 3'( "先行ゼロ"バージョン)をしますか? –