3

単純なプロジェクトの場合、大きな数字(4294967123など)を読み取り可能にする必要があるため、接頭辞(4294967123-> 4.29G、12345-> 12.34Kなど)が付いた最初の数字のみを書き込みます。

コード(簡略化)は次のようになります。

const char* postfixes=" KMGT";
char postfix(unsigned int x)
{
     return postfixes[(int) floor(log10(x))];
}

それは機能しますが、完全な精度の対数を計算し、それを丸めて再度intにキャストするよりも、よりエレガントで優れたソリューションがあると思います。

私が考えた他の解決策:

int i=0;
for(; x >= 1000 ; ++i) x/=1000;
return postfixes[i];

(これはかなり遅くなりますが、読みやすくなります)

数値はベンフォードの法則に従って分散され、10 ^ x付近で丸め誤差が発生しないため、数値は符号なし64ビット数値として扱われる必要があります(たとえば、Pythonmath.log(1000,10)では2.999996が返され、2になります)。私が見逃している他の高速で正確な方法はありますか?

4

5 に答える 5

17

log10/floor コードは完全に読み取り可能であり、そのパフォーマンス コストは、後で出力に対して行う文字列の書式設定のコストよりも小さくなります。

しかし、もしあなたが本当にそのパフォーマンスを必要としているとしたら...

log10(x) == log2(x) / log2(10) == log2(x) * 1/log2(10) であることに注意してください。

1/log2(10) は定数です

log2(x) は通常、CLZ やビットいじりハックなどの命令を使用して最新のアーキテクチャの整数パイプラインで安価に実行でき、64 ビット整数に対して 0 ~ 63 の数値を生成します。これは 6 ビットに収まるため、64 ビット型の固定小数点演算に使用できる基数の後に最大 58 ビットが残ります。

したがって、固定小数点演算を使用して log10 を見つけることができます。

unsigned long long integer_log10( unsigned long long _in )
{
    unsigned long long log10fp6x58 = 0x134413509f79ff0llu; // (unsigned long long) (double(1llu<<58) / log2(10.0))
    return (((integer_log2(_in)) * log10fp6x58)+(1llu<<57)) >> 58;
}

integer_log2 の実装はコンパイラ/プラットフォームに依存します。たとえば、GCC/PowerPC では、

unsigned long long integer_log2( unsigned long long _in )
{
    return 63 - __cntlzd(_in);
}

このアプローチは、任意の底の対数を見つけるために一般化できます。上記のように適切な定数を計算するだけです。

于 2009-07-30T10:20:38.767 に答える
0

まず、ゼロをフォーマットする必要がある場合は、その対数を取りたくありません。次に、きれいなものが必要なので、たとえば、999,800,000の「1000M」は必要ありません。第三に、おそらく丸めが必要です。

次のような擬似コードを使用することをお勧めします。


function format(long x by value)
int p=5, char suf
if x<100000 then return string(x)
if x>=10000000000000 then
   x/=100000000
   p+=8
if x>=1000000000 then
   x/=10000
   p+=4
if x>=10000000 then
   x/=100
   p+=2
if x>=1000000 then
   x/=10
   p+=1
x+=5
if x>=100000 then
   x/=10
   p+=1
switch(p/3)
   6: suf='E'
   5: suf='P'
   4: suf='T'
   3: suf='G'
   2: suf='M'
   1: suf='K'
switch(p mod 3)
   2: return format("000 A",x/1000,suf)
   1: return format("00.0 A",x/10000,(x%10000)/100,suf)
   0: return format("0.00 A",x/100000,(x%100000)/100,suf)
end function
于 2009-09-05T09:32:59.597 に答える