例えば、
n = 3432, result 4
n = 45, result 2
n = 33215, result 5
n = -357, result 3
文字列に変換してから文字列の長さを取得できると思いますが、それは複雑でハックのようです。
floor (log10 (abs (x))) + 1
再帰的アプローチ:-)
_int numPlaces (int n) {
if (n < 0) return numPlaces ((n == INT_MIN) ? MAX_INT: -n);
if (n < 10) return 1;
return 1 + numPlaces (n / 10);
}
_
または反復:
_int numPlaces (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;
while (n > 9) {
n /= 10;
r++;
}
return r;
}
_
または生の速度:
_int numPlaces (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
/* 2147483647 is 2^31-1 - add more ifs as needed
and adjust this final return as well. */
return 10;
}
_
上記のものは、MININTの処理を改善するために変更されています。賢明な方法に従わない奇妙なシステム2n 整数の2の補数規則、さらに調整が必要な場合があります。
生の速度バージョンは、実際には、以下に変更した浮動小数点バージョンよりも優れています。
_int numPlaces (int n) {
if (n == 0) return 1;
return floor (log10 (abs (n))) + 1;
}
_
1億回の繰り返しで、次の結果が得られます。
_Raw speed with 0: 0 seconds
Raw speed with 2^31-1: 1 second
Iterative with 2^31-1: 5 seconds
Recursive with 2^31-1: 6 seconds
Floating point with 1: 6 seconds
Floating point with 2^31-1: 7 seconds
_
それは実際に少し驚きました-IntelチップはまともなFPUを持っていると思いましたが、一般的なFP操作はまだ手で最適化された整数コードと競合できません。
stormsoulの提案に従って更新:
Stormsoulによる多重反復ソリューションのテストでは4秒の結果が得られるため、除算反復ソリューションよりもはるかに高速ですが、最適化されたifステートメントソリューションとは一致しません。
ランダムに生成された1000個の数値のプールから引数を選択すると、未加工の速度が2秒に押し出されたため、毎回同じ引数を使用することには利点があるように見えますが、それでもリストされている最速のアプローチです。
-O2でコンパイルすると、速度は向上しましたが、相対位置は向上しませんでした(これを確認するために、反復回数を10倍に増やしました)。
さらなる分析は、CPU効率の内部動作(さまざまなタイプの最適化、キャッシュの使用、分岐予測、実際に使用しているCPU、部屋の周囲温度など)に真剣に取り組む必要があります。有料の仕事の邪魔になります:-)。それは興味深い転用でしたが、ある時点で、最適化のための投資利益率は問題になるには小さすぎます。私たちは質問に答えるのに十分な解決策を持っていると思います(結局のところ、それはスピードについてではありませんでした)。
更なる更新:
これは、アーキテクチャに依存しない明白なエラーを除いて、この回答に対する私の最終更新です。ストームソウルの勇気ある測定努力に触発され、ここに答えで示されているすべての方法のサンプル図とともに、テストプログラム(ストームソウル独自のテストプログラムごとに修正)を投稿しています。これは特定のマシンであることに注意してください。走行距離は走行場所によって異なる場合があります(テストコードを投稿する理由です)。
あなたが望むようにそれをしてください:
_#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>
#define numof(a) (sizeof(a) / sizeof(a[0]))
/* Random numbers and accuracy checks. */
static int rndnum[10000];
static int rt[numof(rndnum)];
/* All digit counting functions here. */
static int count_recur (int n) {
if (n < 0) return count_recur ((n == INT_MIN) ? INT_MAX : -n);
if (n < 10) return 1;
return 1 + count_recur (n / 10);
}
static int count_diviter (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
while (n > 9) {
n /= 10;
r++;
}
return r;
}
static int count_multiter (int n) {
unsigned int num = abs(n);
unsigned int x, i;
for (x=10, i=1; ; x*=10, i++) {
if (num < x)
return i;
if (x > INT_MAX/10)
return i+1;
}
}
static int count_ifs (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
/* 2147483647 is 2^31-1 - add more ifs as needed
and adjust this final return as well. */
return 10;
}
static int count_revifs (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n > 999999999) return 10;
if (n > 99999999) return 9;
if (n > 9999999) return 8;
if (n > 999999) return 7;
if (n > 99999) return 6;
if (n > 9999) return 5;
if (n > 999) return 4;
if (n > 99) return 3;
if (n > 9) return 2;
return 1;
}
static int count_log10 (int n) {
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n == 0) return 1;
return floor (log10 (n)) + 1;
}
static int count_bchop (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n >= 100000000) {
r += 8;
n /= 100000000;
}
if (n >= 10000) {
r += 4;
n /= 10000;
}
if (n >= 100) {
r += 2;
n /= 100;
}
if (n >= 10)
r++;
return r;
}
/* Structure to control calling of functions. */
typedef struct {
int (*fnptr)(int);
char *desc;
} tFn;
static tFn fn[] = {
NULL, NULL,
count_recur, " recursive",
count_diviter, " divide-iterative",
count_multiter, " multiply-iterative",
count_ifs, " if-statements",
count_revifs, "reverse-if-statements",
count_log10, " log-10",
count_bchop, " binary chop",
};
static clock_t clk[numof (fn)];
int main (int c, char *v[]) {
int i, j, k, r;
int s = 1;
/* Test code:
printf ("%11d %d\n", INT_MIN, count_recur(INT_MIN));
for (i = -1000000000; i != 0; i /= 10)
printf ("%11d %d\n", i, count_recur(i));
printf ("%11d %d\n", 0, count_recur(0));
for (i = 1; i != 1000000000; i *= 10)
printf ("%11d %d\n", i, count_recur(i));
printf ("%11d %d\n", 1000000000, count_recur(1000000000));
printf ("%11d %d\n", INT_MAX, count_recur(INT_MAX));
/* */
/* Randomize and create random pool of numbers. */
srand (time (NULL));
for (j = 0; j < numof (rndnum); j++) {
rndnum[j] = s * Rand();
s = -s;
}
rndnum[0] = INT_MAX;
rndnum[1] = INT_MIN;
/* For testing. */
for (k = 0; k < numof (rndnum); k++) {
rt[k] = (fn[1].fnptr)(rndnum[k]);
}
/* Test each of the functions in turn. */
clk[0] = clock();
for (i = 1; i < numof (fn); i++) {
for (j = 0; j < 10000; j++) {
for (k = 0; k < numof (rndnum); k++) {
r = (fn[i].fnptr)(rndnum[k]);
/* Test code:
if (r != rt[k]) {
printf ("Mismatch error [%s] %d %d %d %d\n",
fn[i].desc, k, rndnum[k], rt[k], r);
return 1;
}
/* */
}
}
clk[i] = clock();
}
/* Print out results. */
for (i = 1; i < numof (fn); i++) {
printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
}
return 0;
}
_
コンパイルには正しいコマンドラインを使用する必要があることを忘れないでください。特に、may
log10()
を機能させるには、数学ライブラリを明示的にリストする必要があります。 Debianで使用したコマンドラインは_gcc -o testprog testprog.c -lm
_でした。
そして、結果の観点から、ここにリーダーボードがあります私の環境用:
最適化レベル0:
_Time for reverse-if-statements: 1704
Time for if-statements: 2296
Time for binary chop: 2515
Time for multiply-iterative: 5141
Time for divide-iterative: 7375
Time for recursive: 10469
Time for log-10: 26953
_
最適化レベル3:
_Time for if-statements: 1047
Time for binary chop: 1156
Time for reverse-if-statements: 1500
Time for multiply-iterative: 2937
Time for divide-iterative: 5391
Time for recursive: 8875
Time for log-10: 25438
_
最短の答え:snprintf(0,0,"%+d",n)-1
Vのrの桁数を取得するためのバイナリ検索擬似アルゴリズム.
if (v < 0 ) v=-v;
r=1;
if (v >= 100000000)
{
r+=8;
v/=100000000;
}
if (v >= 10000) {
r+=4;
v/=10000;
}
if (v >= 100) {
r+=2;
v/=100;
}
if( v>=10)
{
r+=1;
}
return r;
結果がゼロになるまでループで10で除算します。反復回数は10進数の桁数に対応します。
ゼロ値で0桁を取得すると想定すると:
int countDigits( int value )
{
int result = 0;
while( value != 0 ) {
value /= 10;
result++;
}
return result;
}
X86アセンブリとルックアップテーブルを使用する定額版:
int count_bsr(int i) {
struct {
int max;
int count;
} static digits[32] = {
{ 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
{ 99, 2 }, { 99, 2 }, { 99, 2 },
{ 999, 3 }, { 999, 3 }, { 999, 3 },
{ 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
{ 99999, 5 }, { 99999, 5 }, { 99999, 5 },
{ 999999, 6 }, { 999999, 6 }, { 999999, 6 },
{ 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
{ 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
{ 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
{ INT_MAX, 10 }, { INT_MAX, 10 }
};
register const int z = 0;
register unsigned log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
return digits[log2].count + ( i > digits[log2].max );
}
もう1つは、より小さなルックアップテーブルと here から取得したlog10近似値です。
int count_bsr2( int i ) {
static const unsigned limits[] =
{0, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000};
register const int z = 0;
register int l, log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
l = (log2 + 1) * 1233 >> 12;
return (l + ((unsigned)i >= limits[l]));
}
これらは両方とも、x86では-INT_MINがINT_MINと等しいという事実を利用しています。
更新:
ここでの提案によると、count_bsrのタイミングと、バイナリ検索と比較してわずかに高速な64ビットのみcount_bsr_modルーチンとランダムな符号分布を持つセットを生成するように修正された非常に素晴らしいpaxdiabloのテストプログラムを使用したバイナリチョップアルゴ。テストは、「-O3 -falign-functions = 16 -falign-jumps = 16 -march = corei7-avx」オプションを使用してgcc 4.9.2で構築され、ターボおよびスリープ状態がオフの静止状態のSandy Bridgeシステムで実行されました。
bsr modの時間:270000 bsrの時間:340000 バイナリチョップの時間:800000 バイナリ検索の時間:770000 バイナリ検索mod:470000
テストのソース、
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <time.h>
#define numof(a) (sizeof(a) / sizeof(a[0]))
/* Random numbers and accuracy checks. */
static int rndnum[10000];
static int rt[numof(rndnum)];
/* All digit counting functions here. */
static int count_bchop (int n) {
int r = 1;
if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;
if (n >= 100000000) {
r += 8;
n /= 100000000;
}
if (n >= 10000) {
r += 4;
n /= 10000;
}
if (n >= 100) {
r += 2;
n /= 100;
}
if (n >= 10)
r++;
return r;
}
static int count_bsearch(int i)
{
if (i < 0)
{
if (i == INT_MIN)
return 11; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
i = -i;
}
if (i < 100000) {
if (i < 1000) {
if (i < 10) return 1;
else if (i < 100) return 2;
else return 3;
} else {
if (i < 10000) return 4;
else return 5;
}
} else {
if (i < 10000000) {
if (i < 1000000) return 6;
else return 7;
} else {
if (i < 100000000) return 8;
else if (i < 1000000000) return 9;
else return 10;
}
}
}
// Integer log base 10, modified binary search.
static int count_bsearch_mod(int i) {
unsigned x = (i >= 0) ? i : -i;
if (x > 99)
if (x > 999999)
if (x > 99999999)
return 9 + (x > 999999999);
else
return 7 + (x > 9999999);
else
if (x > 9999)
return 5 + (x > 99999);
else
return 3 + (x > 999);
else
return 1 + (x > 9);
}
static int count_bsr_mod(int i) {
struct {
int m_count;
int m_threshold;
} static digits[32] =
{
{ 1, 9 }, { 1, 9 }, { 1, 9 }, { 1, 9 },
{ 2, 99 }, { 2, 99 }, { 2, 99 },
{ 3, 999 }, { 3, 999 }, { 3, 999 },
{ 4, 9999 }, { 4, 9999 }, { 4, 9999 }, { 4, 9999 },
{ 5, 99999 }, { 5, 99999 }, { 5, 99999 },
{ 6, 999999 }, { 6, 999999 }, { 6, 999999 },
{ 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 }, { 7, 9999999 },
{ 8, 99999999 }, { 8, 99999999 }, { 8, 99999999 },
{ 9, 999999999 }, { 9, 999999999 }, { 9, 999999999 },
{ 10, INT_MAX }, { 10, INT_MAX }
};
__asm__ __volatile__ (
"cdq \n\t"
"xorl %%edx, %0 \n\t"
"subl %%edx, %0 \n\t"
"movl %0, %%edx \n\t"
"bsrl %0, %0 \n\t"
"shlq $32, %%rdx \n\t"
"movq %P1(,%q0,8), %q0 \n\t"
"cmpq %q0, %%rdx \n\t"
"setg %%dl \n\t"
"addl %%edx, %0 \n\t"
: "+a"(i)
: "i"(digits)
: "rdx", "cc"
);
return i;
}
static int count_bsr(int i) {
struct {
int max;
int count;
} static digits[32] = {
{ 9, 1 }, { 9, 1 }, { 9, 1 }, { 9, 1 },
{ 99, 2 }, { 99, 2 }, { 99, 2 },
{ 999, 3 }, { 999, 3 }, { 999, 3 },
{ 9999, 4 }, { 9999, 4 }, { 9999, 4 }, { 9999, 4 },
{ 99999, 5 }, { 99999, 5 }, { 99999, 5 },
{ 999999, 6 }, { 999999, 6 }, { 999999, 6 },
{ 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 }, { 9999999, 7 },
{ 99999999, 8 }, { 99999999, 8 }, { 99999999, 8 },
{ 999999999, 9 }, { 999999999, 9 }, { 999999999, 9 },
{ INT_MAX, 10 }, { INT_MAX, 10 }
};
register const int z = 0;
register unsigned log2;
if (i < 0) i = -i;
__asm__ __volatile__ (
"bsr %1, %0;" \
"cmovz %2, %0;"\
: "=r" (log2) \
: "rm" (i), "r"(z));
return digits[log2].count + ( i > digits[log2].max );
}
/* Structure to control calling of functions. */
typedef struct {
int (*fnptr)(int);
const char *desc;
} tFn;
static tFn fn[] = {
{ NULL, NULL },
{ count_bsr_mod, " bsr mod" },
{ count_bsr, " bsr" },
{ count_bchop, " binary chop" },
{ count_bsearch, " binary search" },
{ count_bsearch_mod," binary search mod"}
};
static clock_t clk[numof (fn)];
int main (int c, char *v[]) {
int i, j, k, r;
int s = 1;
/* Test code:
printf ("%11d %d\n", INT_MIN, count_bsearch(INT_MIN));
//for (i = -1000000000; i != 0; i /= 10)
for (i = -999999999; i != 0; i /= 10)
printf ("%11d %d\n", i, count_bsearch(i));
printf ("%11d %d\n", 0, count_bsearch(0));
for (i = 1; i != 1000000000; i *= 10)
printf ("%11d %d\n", i, count_bsearch(i));
printf ("%11d %d\n", 1000000000, count_bsearch(1000000000));
printf ("%11d %d\n", INT_MAX, count_bsearch(INT_MAX));
return 0;
/* */
/* Randomize and create random pool of numbers. */
int p, n;
p = n = 0;
srand (time (NULL));
for (j = 0; j < numof (rndnum); j++) {
rndnum[j] = ((Rand() & 2) - 1) * Rand();
}
rndnum[0] = INT_MAX;
rndnum[1] = INT_MIN;
/* For testing. */
for (k = 0; k < numof (rndnum); k++) {
rt[k] = (fn[1].fnptr)(rndnum[k]);
}
/* Test each of the functions in turn. */
clk[0] = clock();
for (i = 1; i < numof (fn); i++) {
for (j = 0; j < 10000; j++) {
for (k = 0; k < numof (rndnum); k++) {
r = (fn[i].fnptr)(rndnum[k]);
/* Test code:
if (r != rt[k]) {
printf ("Mismatch error [%s] %d %d %d %d\n",
fn[i].desc, k, rndnum[k], rt[k], r);
return 1;
}
/* */
}
}
clk[i] = clock();
}
/* Print out results. */
for (i = 1; i < numof (fn); i++) {
printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));
}
return 0;
}
floor (log10 (abs (x))) + 1
または、サイクルを節約したい場合は、単に比較を行うことができます。
if(x<10)
return 1;
if(x<100)
return 2;
if(x<1000)
return 3;
etc etc
これにより、対数、さらには乗算または除算などの計算コストの高い関数が回避されます。それはエレガントではありませんが、これは関数にカプセル化することで隠すことができます。維持するのは複雑でも難しいことでもないので、コーディングの習慣が悪いためにこのアプローチを却下しません。そうする気がするのは、お風呂の水で赤ちゃんを捨てることでしょう。
これは、除算や乗算を行わない展開されたバイナリ検索です。それに与えられた数の分布に応じて、展開されたif文で行われた他の値を打ち負かすかもしれませんが、ループと乗算/除算/ log10を使用するものを常に打ち負かすべきです。
範囲全体を含む乱数の均一な分布により、私のマシンでは、paxdiabloのcount_bchop()の実行時間の平均79%、count_ifs()の時間の88%、count_revifs()の時間の97%でした。
指数分布の場合(n桁の数の確率はm桁の数の確率と等しく、ここでm≠- n)count_ifs()とcount_revifs()は両方とも私の機能に勝っています。この時点でなぜかわかりません。
int count_bsearch(int i)
{
if (i < 0)
{
if (i == INT_MIN)
return 10; // special case for -2^31 because 2^31 can't fit in a two's complement 32-bit integer
i = -i;
}
if (i < 100000) {
if (i < 1000) {
if (i < 10) return 1;
else if (i < 100) return 2;
else return 3;
} else {
if (i < 10000) return 4;
else return 5;
}
} else {
if (i < 10000000) {
if (i < 1000000) return 6;
else return 7;
} else {
if (i < 100000000) return 8;
else if (i < 1000000000) return 9;
else return 10;
}
}
}
私はグーグル検索中にこれに出くわしました: http://www.hackersdelight.org/hdcodetxt/ilog.c.txt
簡単なベンチマークは、バイナリ検索方法が勝つことを明確に示しました。 lakshmanarajの コードは非常に優れています。 Alexander Korobkaの は最大30%高速です。 Deadcode's はまだ少し高速ですが(〜10%)、上記のリンクからの次のトリックがさらに10%の改善をもたらすことがわかりました。
_// Integer log base 10, modified binary search.
int ilog10c(unsigned x) {
if (x > 99)
if (x < 1000000)
if (x < 10000)
return 3 + ((int)(x - 1000) >> 31);
// return 3 - ((x - 1000) >> 31); // Alternative.
// return 2 + ((999 - x) >> 31); // Alternative.
// return 2 + ((x + 2147482648) >> 31); // Alternative.
else
return 5 + ((int)(x - 100000) >> 31);
else
if (x < 100000000)
return 7 + ((int)(x - 10000000) >> 31);
else
return 9 + ((int)((x-1000000000)&~x) >> 31);
// return 8 + (((x + 1147483648) | x) >> 31); // Alternative.
else
if (x > 9)
return 1;
else
return ((int)(x - 1) >> 31);
// return ((int)(x - 1) >> 31) | ((unsigned)(9 - x) >> 31); // Alt.
// return (x > 9) + (x > 0) - 1; // Alt.
}
_
これは桁数ではなくログ10なので、digits = ilog10c(x)+1
であることに注意してください。
ネガはサポートしていませんが、_-
_で簡単に修正できます。
if (x == MININT) return 10; // abs(MININT) is not defined
x = abs (x);
if (x<10) return 1;
if (x<100) return 2;
if (x<1000) return 3;
if (x<10000) return 4;
if (x<100000) return 5;
if (x<1000000) return 6;
if (x<10000000) return 7;
if (x<100000000) return 8;
if (x<1000000000) return 9;
return 10; //max len for 32-bit integers
とても上品です。しかし、他のすべてのソリューションよりも高速です。整数除算とFPログはコストがかかります。パフォーマンスが問題にならない場合、log10ソリューションが私のお気に入りです。
C言語に合わせて少し調整します。
floor( log10( abs( (number)?number:1 ) ) + 1 );
int n = 437788;
int N = 1;
while (n /= 10) N++;
私は遅れていることは知っていますが、このコードは他のすべての答えよりも+ x1速いです。
int digits(long long x)
{
x < 0 ? x = -x : 0;
return x < 10 ? 1 :
x < 100 ? 2 :
x < 1000 ? 3 :
x < 10000 ? 4 :
x < 100000 ? 5 :
x < 1000000 ? 6 :
x < 10000000 ? 7 :
x < 100000000 ? 8 :
x < 1000000000 ? 9 :
x < 10000000000 ? 10 : 0;
}
int x = -937810;
printf("%d : %d digits\n", x, digits(x));
アウト:
-937810 : 6 digits
符号付き整数の長さ(つまり、桁数)を見つける簡単な方法は次のとおりです。
_while ( abs(n) > 9 )
{
num /= 10;
++len;
}
_
ここで、n
は長さを求める整数であり、len
は整数の桁数に等しくなります。これは、n
の両方の値(負または正)で機能します。
正の整数のみを使用している場合、abs()
の呼び出しはオプションです。
Floor(log10(...))を使用しないでください。これらは、追加する浮動小数点関数と遅い関数です。最速の方法はこの関数になると思います:
int ilog10(int num)
{
unsigned int num = abs(num);
unsigned int x, i;
for(x=10, i=1; ; x*=10, i++)
{
if(num < x)
return i;
if(x > INT_MAX/10)
return i+1;
}
}
一部の人々が提案したバイナリ検索バージョンは、分岐の予測ミスにより遅くなる可能性があることに注意してください。
編集:
私はいくつかのテストを行い、いくつかの本当に興味深い結果を得ました。 Paxでテストされたすべての関数、およびlakshmanarajで指定されたバイナリ検索関数と一緒に関数の時間を計りました。テストは、次のコードスニペットによって実行されます。
start = clock();
for(int i=0; i<10000; i++)
for(int j=0; j<10000; j++)
tested_func(numbers[j]);
end = clock();
tested_func_times[pass] = end-start;
Numbers []配列には、int型の範囲全体でランダムに生成された数値が含まれます(MIN_INTを除く)。 SAME numbers []配列でテストされた各関数に対してテストが繰り返されました。テスト全体が10回行われ、結果はすべてのパスで平均されました。コードは、-O3最適化レベルを使用してGCC 4.3.2でコンパイルされました。
結果は次のとおりです。
floating-point log10: 10340ms
recursive divide: 3391ms
iterative divide: 2289ms
iterative multiplication: 1071ms
unrolled tests: 859ms
binary search: 539ms
本当に驚きました。バイナリ検索は、思ったよりもはるかに優れたパフォーマンスを発揮しました。 GCCがこのコードをasmにコンパイルする方法を確認しました。 O_O。今、これは印象的です。考えられるよりもはるかに最適化されており、ほとんどの分岐を本当に巧妙に回避しています。それが速いのも不思議ではありません。
C#の場合、これは非常に高速でシンプルなソリューションです...
private static int NumberOfPlaces(int n)
{
//fast way to get number of digits
//converts to signed string with +/- intact then accounts for it by subtracting 1
return n.ToString("+#;-#;+0").Length-1;
}
私は推測する、最も簡単な方法は次のとおりだろう:
int digits = 0;
if (number < 0) digits = 1;
while (number) {
number /= 10;
digits++;
}
数字は答えを与えます。
この式ceil(log10(abs(x)))を使用して、数値の桁数を見つけることができます。ここで、ceilは、numberよりも大きい整数を返します。