2016-08-07 8 views
1

整数変数に格納された初期化データのサイズが必要です。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 
+1

いずれかの4つの比較ゼロビットをリードする数えるか、単に行います。 –

+0

「初期化済み」という意味ですか? "0x12"を含むu32のために、3つの最上位バイトはゼロに初期化されなければならなかった。そうでない場合は、3バイトのランダムなガベージとそれに続くu8の0x12があります。 – kfsone

+1

'0x123456'で' 3'を生成したい場合、 '0x120056'はどうでしょうか? '2 '(すなわち、非ゼロバイトの数)または' 3'( "先行ゼロ"バージョン)をしますか? –

答えて

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); 
} 

UPDATE: 私のコードは、文字通りに解釈されているようです。

int byteCount(const u32 x) 
{ 
    if (x == 0) return 0; /* Avoid error */ 
    return (int)trunc((log10(x)/0.301029995663981)/8+1); 
} 
+0

このlog2(x)関数はどこにありますかmath.hで見つけられませんでした – user3423907

+1

あなたのライブラリにそれがない場合は、私が提供したリンクに示唆されているように実装してください。基本的には:log2(x)= log10(x)/ log10(2) – Jaime

+0

テストできるドラフトコードを追加しました – Jaime

1

ゼロ以外のバイト数をカウントする必要がありますか?

u8 countNonZeroBytes(u32 n) { 
    u8 result = n == 0 ? 0 : 1; 
    while (n >> 8 != 0) { 
     result++; 
     n = n >> 8; 
    } 
    return result; 
} 
+0

正確には、私はこの機能を実行するためにcライブラリ関数が必要です。 – user3423907

+0

@Andrew解決策はn = 0x12(1バイト)では正しくありません。 –

+2

これを行うためのcライブラリ関数はありません。 –

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; 
} 
0

は、浮動小数点を使用していない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に変換します。

+0

Craig、私のbyteCount提案は、わかりやすくするために最適化されていません。たとえば、log10(2)を定数に変換できます。私はそれがパフォーマンスの顕著な増加を持っていると思う。 – Jaime

+0

@Jaime私は自分の変更とテスト結果をもとに自分の答えを更新しました。 –

+0

Craig、希望の結果を得るたびに「不正確な」アプローチはありません。読みやすさとパフォーマンスの間の妥協点です。数学者にとって私のアプローチはforループよりもはっきりしているかもしれません。もちろん、処理時間(マイクロ秒)がより広いプロセス(すなわち、秒)内で限界的でない限り、ほとんどの場合、性能は重要である。 – Jaime

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; 
}