整数の桁数を決定する効率的な方法


144

C ++で整数にある桁数を決定する非常に効率的な方法は何ですか?


11
どの拠点に?2?10?
Jacob Krall

2
私はベース10でそれをしたいと思います
セス

1
関連する質問をしたことがあります:intの最初の桁を取得するにはどうすればよいですか?以下と同じ方法論の多くが人々の答えに使用されました。タスクに関連する場合のリンクは次のとおりです
Dinah

インラインアセンブリは適格ですか?
ジェルジAndrasek

1
これらの答えはすべて基数10に関するものですが、目的の基数の結果を計算するように変更するのは非常に簡単です。
Ira Baxter

回答:


106

さて、あなたが整数のサイズを知っていると仮定すると、最も効率的な方法はルックアップです。はるかに短い対数ベースのアプローチよりも高速である必要があります。「-」を数える必要がない場合は、+ 1を削除してください。

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

    if (x >= 10000) {
        if (x >= 10000000) {
            if (x >= 100000000) {
                if (x >= 1000000000)
                    return 10;
                return 9;
            }
            return 8;
        }
        if (x >= 100000) {
            if (x >= 1000000)
                return 7;
            return 6;
        }
        return 5;
    }
    if (x >= 100) {
        if (x >= 1000)
            return 4;
        return 3;
    }
    if (x >= 10)
        return 2;
    return 1;
}

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}

5
おそらく私の答えよりも速く、よくやった。さらに効率を上げるために、入力数がほとんど小さいことがわかっている場合(100,000未満と推測しています)、テストを逆にします。if(x <10)return 1; if(x <100)return 2; など、関数がより少ないテストを実行し、より速く終了します。
squelart 2009

29
あるいは、ifステートメントを並べ替えてネストし、線形検索ではなくバイナリ検索を実行することもできます。
dave4420 2009

1
それは良い考えではありません。アーキテクチャが256ビット整数に拡張されるとどうなりますか。このコードに戻って変更することを忘れないでください。現実には起こり得ないことであり、これはおそらく、正しいサイズのバッファーを構築するために使用されることになるでしょう。
マーティンヨーク

3
数値が均一に分布していると仮定すると、逆線形検索(最大桁数から1まで)は、N桁の数値の方がN-1桁の数値よりもかなり多いため、バイナリ検索よりも平均で高速になる場合があります 。stanford.edu/〜 seander /…
fa。

6
256ビットまたは128ビットの整数については、それほど心配する必要はありません。宇宙の電子数を数える必要がない限り(私が最後に行ったときは10 ^ 78です)、64ビットで十分です。32ビットマシンは~~ 15年続きました。64ビットマシンはずっと長く続くと思います。より大きな数の場合、多精度演算は問題なく、桁数の計算の効率が問題になるかどうか疑問に思います。
Ira Baxter

74

最も簡単な方法は次のとおりです。

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}

log10は<cmath>またはで定義されてい<math.h>ます。これをプロファイリングして、ここに掲載されている他のどれよりも速いかどうかを確認する必要があります。浮動小数点の精度に関して、これがどれほど堅牢かはわかりません。また、引数は負の値として符号なしであり、ログは実際には混合しません。


7
32ビット整数と56ビット浮動小数点の場合、これはおそらく機能します。入力が長い(64ビット)場合、56ビットの倍精度ログが原因で、10 ^ nの大きな値に近い値の場合に誤った回答が生成される可能性があります。2 ^ 50を超えると問題が発生します。
Ira Baxter、

1
ログ関数がどれほど正確かという問題もあります。私はそれらが最新のライブラリーでどれほど正確であるかを確認していません。
David Thornley、

@DavidThornley:コンパイラのコマンドラインで指定しない限り、ログやその他の数学関数は完全に正確です。一部はコンパイル時にx86組み込みに変換されます。一部は存在せず、既存の組み込み関数の式に拡張されます。たとえば、使用している-fpfast場合、x87ではなくSSE組み込み関数の使用を確認できます。これにより、精度IIRCの保証が少なくなります。デフォルトでは問題ありません。
v.oddou 2014年

@DavidThornley:それは精度以上のものです。問題は、関連するすべてのkについてlog10(10 ^ k)≥kが保証されているかどうかです。つまり、不可避の丸め誤差が正しい方向に進むことが保証されています。結果としてk + epsは機能しますが、k-epsは機能しません。そして、「完全に正確」はナイーブです。
gnasher729 2015

1
テストi> 0はi> 9に最適化できる
Pat

60

多分私は質問を誤解しましたが、これはそれをしませんか?

int NumDigits(int x)  
{  
    x = abs(x);  
    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 :  
        10)))))))));  
}  

29
そして、このソリューションが最速になっても私は驚かないでしょう。
VisioN 2014年

32
int digits = 0; while (number != 0) { number /= 10; digits++; }

注:「0」は0桁になります。1桁で表示するために0が必要な場合は、次を使用します。

int digits = 0; do { number /= 10; digits++; } while (number != 0);

(ケビン・フィーガンに感謝)

最後に、プロファイラーを使用して、ここでのすべての答えのうち、あなたのマシンでより速くなるものを知ってください...


3
これは、私が採用したアンロールループアプローチよりも速い場合とそうでない場合があります。違いをプロファイルする必要があります(長期的には無視できるはずです)。
Vitali

確かに、プロファイリングは本当に確実に知る唯一の方法です!Ben Sのceil(log10())回答が消えたので、そのコメントで回答を更新しました。
スケルト2009

11

実用的なジョーク:これは、最も効率的な方法(桁数は、コンパイル時に計算されます):

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};

書式、入力要素などの数値フィールドに必要な幅を決定するのに役立ちます。


4
1つ目は、ソリューションが0に対して機能しないことです。2つ目は、ソリューションが変数の一般的なケースに適用できないことです。3番目に、定数リテラルを使用している場合は、定数の桁数がわかっています。
Vitali

0でも機能します。また、どのベースでも機能します。残りは私がすでに概説した有効なポイントです。
blinnov.com 2009

3
実際にはそうは思いません。これは失敗し0、base 1:) でも失敗し、baseがとして指定されて0いる場合、ゼロ除算エラーが発生します。それは修正できます。とにかく、私は非常に古い投稿をめちゃくちゃにしているので、申し訳ありませんが、これは冗談である必要はなく、実際に役立つと思うだけです。
tjm

9

あなたが受け入れた回答のはるかに短いバージョンについては、ビットをくすぐるハックを参照してください。また、最初に大きな定数をチェックすることにより、入力が正規分布である場合に、より早く答えを見つけるという利点もあります。 (v >= 1000000000)値の76%をキャッチするので、最初にチェックする方が平均して速くなります。


ビットいじりが実際に速いかどうかは不明です。最悪の場合でも、変更したアプローチでは4つの比較が必要です(パーティション分割をさらに詳しく調べれば、3に下げることができるかもしれませんが、そうは思われません)。これが算術演算+メモリ負荷に打たれることを真剣に疑っています(十分にアクセスされた場合、それらはCPUキャッシュに消えます)。それらが示す例では、ログベース2をいくつかの抽象的なIntegerLogBase2関数(それ自体は実際には安価ではありません)として非表示にすることを忘れないでください。
Vitali

フォローアップと同じように、数値が正規分布している場合は、順序チェックを行う方が高速です。ただし、最悪の場合には2倍遅いという退化したケースがあります。入力スペースではなく桁数による分割アプローチは、動作に縮退ケースがなく、常に最適に実行されることを意味します。さらに、数値が均一に分散されることを前提としていることを思い出してください。実際に、彼らは> <a href=" en.wikipedia.org/wiki/...に関連するいくつかの分布に従うする可能性が高い私の推測になります。
ビタリ

ビットをいじるハックは上記のパーティション方式よりも高速ではありませんが、ここでフロートのようなより一般的なケースがある場合、それらは潜在的に興味深いものです。
コーウィンジョイ

1
ちょっとしたハックは、int log2を前提として、int log10を取得する方法を提案します。これは、int log2を取得するいくつかの方法を提案します。ほとんどの場合、比較/分岐はほとんど含まれません。(私はあなたが予測できない枝、ビタリのコストを過小評価していると思います)。インラインx86 asmを使用できる場合、BSR命令は値のint log2(つまり、最上位セットビットのビットインデックス)を提供します。K8では少し遅い(10サイクルのレイテンシ)が、Core 2では速い(2または3サイクルのレイテンシ)。K8であっても、比較よりもはるかに高速です。
Peter Cordes

K10では、lzcntは先行ゼロをカウントするため、bsrとほぼ同じですが、0の入力は結果が未定義の特別なケースではなくなりました。待ち時間:BSR:4、LZCNT:2.
Peter Cordes

8

文字列に変換してから組み込み関数を使用する

unsigned int i;
cout<< to_string(i).length()<<endl;

7
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;

3
これはLOCの点では効率的ですが、受け入れられた回答に記載されているように、ログの使用はおそらく最高のパフォーマンスを提供しません。
イアン

@イアンどうして?それは、ほんの2、3のFPU命令です。他の回答のすべての分岐とループよりもマイルが良い。
ローンの侯爵

5

以前のポスターでは、10で割るループが提案されていました。最新のマシンでの乗算ははるかに高速なので、代わりに次のコードをお勧めします。

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }

1
悪魔は詳細にあります-たとえば、std :: numeric_limits <int> :: max == numberで何が起こるか-終了に問題がある可能性があります
pgast

2
このケースが心配な場合は、IFを1つ追加して非常に大きな値を処理できます。
Ira Baxter、

2
x86マシンでは、この場合に使用される定数10の乗算は、コンパイラーによって実際にLEA R2、[8 * R1 + R1]、ADD R1、R2として実装できるため、最大2クロックかかることに注意してください。変数による乗算は数十クロックかかり、除算ははるかに悪いです。
Ira Baxter

除算アプローチの利点は、負の数を気にする必要がないことです。
Johannes Schaub-litb 2013年

1
私は、分割アプローチと対比して、マルチサイン化アプローチ(標識問題を取り除くためのファブを使用)のベンチマークを行いました。私のマシンでは、除算アプローチは乗算アプローチよりもファクター2が遅い これが時期尚早の最適化であるかどうかは、実際にはどこでどのように呼び出されるかに依存します。
Spacemoose 2014

5

ppcアーキテクチャには、ビットカウント命令があります。これにより、1つの命令で正の整数の2を底とする対数を決定できます。たとえば、32ビットは次のようになります。

#define log_2_32_ppc(x) (31-__cntlzw(x))

大きな値で小さなエラーマージンを処理できる場合は、別のいくつかの指示を使用してそれをログベース10に変換できます。

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))

これはプラットフォーム固有であり、少し不正確ですが、分岐、除算、または浮動小数点への変換も含まれません。すべてはあなたが必要とするものに依存します。

私は手元にあるppc命令しか知りませんが、他のアーキテクチャにも同様の命令があるはずです。


このソリューションは、log2(15)= 4ビットおよびlog2(9)= 4ビットを計算します。ただし、15と9では、印刷するために異なる桁数の10進数が必要です。したがって、数字が多すぎて数字が印刷されることを気にしない限り、機能しません。ただし、その場合は、intの答えとして常に「10」を選択できます。
Ira Baxter

ああ、近似関数です。いいね。
doug65536 2013年

4
 #include <iostream>
 #include <math.h>

 using namespace std;

 int main()
 {
     double num;
     int result;
     cout<<"Enter a number to find the number of digits,  not including decimal places: ";
     cin>>num;
     result = ((num<=1)? 1 : log10(num)+1);
     cout<<"Number of digits "<<result<<endl;
     return 0;
 }

これはおそらく、問題を解決する最も簡単な方法です。10進数の前の数字のみを気にし、10未満の数字は1桁だと仮定します。


1

アイラバクスターの答えが好きです。以下は、さまざまなサイズを処理し、最大整数値を処理するテンプレートバリアントです(ループから上限チェックを引き上げるために更新されています)。

#include <boost/integer_traits.hpp>

template<typename T> T max_decimal()
{
    T t = 1;

    for (unsigned i = boost::integer_traits<T>::digits10; i; --i)
        t *= 10;

    return t;
}

template<typename T>
unsigned digits(T v)
{
    if (v < 0) v = -v;

    if (max_decimal<T>() <= v)
        return boost::integer_traits<T>::digits10 + 1;

    unsigned digits = 1;
    T boundary = 10;

    while (boundary <= v) {
        boundary *= 10;
        ++digits;
    }

    return digits;
}

ループから追加のテストを引き上げてパフォーマンスを向上させるには、max_decimal()を特殊化して、プラットフォーム上の各タイプの定数を返す必要があります。十分に魔法のあるコンパイラーは、max_decimal()の呼び出しを定数に最適化できますが、今日のほとんどのコンパイラーでは、特殊化の方が優れています。現状では、max_decimalはループから削除されたテストよりもコストがかかるため、このバージョンはおそらく遅くなります。

読者のための演習として、それらはすべて残しておきます。


上限チェックを最初に別の条件付きテストにして、ループの繰り返しごとにチェックしないようにする必要があります。
Ira Baxter、

あなたはそのtemp tに10を入れたくありません。コンパイラーは、tによる乗算を実変数による乗算であると見なし、汎用の乗算命令を使用する場合があります。代わりに「result * = 10;」と書いた場合 コンパイラーは定数10の乗算に確実に気づき、数回のシフトと加算でそれを実装します。これは非常に高速です。
Ira Baxter

tによる乗算が常に10による乗算である場合、はい、コンパイラは強度を削減できます。ただし、この場合、tはループ不変ではありません(これは、私が使用していた整数べき関数の単なる変更です)。正しい最適化は、定数を返す型の特殊化です。ただし、この場合、関数は常に10の累乗であり、任意の整数の累乗ではありません。また、強度を減らすと良い結果が得られます。だから私は変更を加えました...今回はさらに変更が実際に練習として残されています!(Stack Overflowは大きな時間のシンクです...)
janm

1
#include <stdint.h> // uint32_t [available since C99]

/// Determine the number of digits for a 32 bit integer.
/// - Uses at most 4 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27669966
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c
         ---+---   ---+---
         10 | 4     5 | 4
          9 | 4     4 | 4
          8 | 3     3 | 3
          7 | 3     2 | 3
          6 | 3     1 | 3
     \endcode
*/
unsigned NumDigits32bs(uint32_t x) {
    return // Num-># Digits->[0-9] 32->bits bs->Binary Search
    ( x >= 100000u // [6-10] [1-5]
    ?   // [6-10]
        ( x >= 10000000u // [8-10] [6-7]
        ?   // [8-10]
            ( x >= 100000000u // [9-10] [8]
            ? // [9-10]
                ( x >=  1000000000u // [10] [9]
                ?   10
                :    9
                )
            : 8
            )
        :   // [6-7]
            ( x >=  1000000u // [7] [6]
            ?   7
            :   6
            )
        )
    :   // [1-5]
        ( x >= 100u // [3-5] [1-2]
        ?   // [3-5]
            ( x >= 1000u // [4-5] [3]
            ? // [4-5]
                ( x >=  10000u // [5] [4]
                ?   5
                :   4
                )
            : 3
            )
        :   // [1-2]
            ( x >=  10u // [2] [1]
            ?   2
            :   1
            )
        )
    );
}

0

さらに別のコードスニペット。基本的にはVitaliと同じですが、バイナリ検索を採用しています。Powers配列は、符号なしの型インスタンスごとに1回遅延初期化されます。符号付き型のオーバーロードはマイナス記号を処理します。

#include <limits>
#include <type_traits>
#include <array>

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_unsigned<T>::value>::type* = 0 )
{
    typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;
    static array_type powers_of_10;
    if ( powers_of_10.front() == 0 )
    {
        T n = 1;
        for ( T& i: powers_of_10 )
        {
            i = n;
            n *= 10;
        }
    }

    size_t l = 0, r = powers_of_10.size(), p;
    while ( l+1 < r )
    {
        p = (l+r)/2;
        if ( powers_of_10[p] <= v )
            l = p;
        else
            r = p;
    }
    return l + 1;
};

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
    typedef typename std::make_unsigned<T>::type unsigned_type;
    if ( v < 0 )
        return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
    else
        return NumberOfDecPositions ( static_cast<unsigned_type>(v) );
}

さらなる最適化に関心がある場合は、powers配列の最初の要素は使用されず、2回l表示されることに注意してください+1


0

ケースの桁数及び各桁の値を使用、これを必要とされています。

int64_t = number, digitValue, digits = 0;    // or "int" for 32bit

while (number != 0) {
    digitValue = number % 10;
    digits ++;
    number /= 10;
}

digit現在ループで処理されている数値の位置に値を提供します。たとえば、数値1776の場合、数字の値は次のとおりです
。1番目のループでは6 6
番目のループでは
7 7 番目のループでは7 7
4番目のループでは1


0
// Meta-program to calculate number of digits in (unsigned) 'N'.    
template <unsigned long long N, unsigned base=10>
struct numberlength
{   // http://stackoverflow.com/questions/1489830/
    enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};

template <unsigned base>
struct numberlength<0, base>
{
    enum { value = 1 };
};

{
    assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );

assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );

上記の「blinnov.com」からの「実用的なジョーク」の修正
アドルフォ

0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c     #d | #c   #d | #c
         ---+---   ---+---     ---+---   ---+---
         20 | 5    15 | 5      10 | 5     5 | 5
         19 | 5    14 | 5       9 | 5     4 | 5
         18 | 4    13 | 4       8 | 4     3 | 4
         17 | 4    12 | 4       7 | 4     2 | 4
         16 | 4    11 | 4       6 | 4     1 | 4
     \endcode
*/
unsigned NumDigits64bs(uint64_t x) {
    return // Num-># Digits->[0-9] 64->bits bs->Binary Search
    ( x >= 10000000000ul // [11-20] [1-10]
    ?
        ( x >= 1000000000000000ul // [16-20] [11-15]
        ?   // [16-20]
            ( x >= 100000000000000000ul // [18-20] [16-17]
            ?   // [18-20]
                ( x >= 1000000000000000000ul // [19-20] [18]
                ? // [19-20]
                    ( x >=  10000000000000000000ul // [20] [19]
                    ?   20
                    :   19
                    )
                : 18
                )
            :   // [16-17]
                ( x >=  10000000000000000ul // [17] [16]
                ?   17
                :   16
                )
            )
        :   // [11-15]
            ( x >= 1000000000000ul // [13-15] [11-12]
            ?   // [13-15]
                ( x >= 10000000000000ul // [14-15] [13]
                ? // [14-15]
                    ( x >=  100000000000000ul // [15] [14]
                    ?   15
                    :   14
                    )
                : 13
                )
            :   // [11-12]
                ( x >=  100000000000ul // [12] [11]
                ?   12
                :   11
                )
            )
        )
    :   // [1-10]
        ( x >= 100000ul // [6-10] [1-5]
        ?   // [6-10]
            ( x >= 10000000ul // [8-10] [6-7]
            ?   // [8-10]
                ( x >= 100000000ul // [9-10] [8]
                ? // [9-10]
                    ( x >=  1000000000ul // [10] [9]
                    ?   10
                    :    9
                    )
                : 8
                )
            :   // [6-7]
                ( x >=  1000000ul // [7] [6]
                ?   7
                :   6
                )
            )
        :   // [1-5]
            ( x >= 100ul // [3-5] [1-2]
            ?   // [3-5]
                ( x >= 1000ul // [4-5] [3]
                ? // [4-5]
                    ( x >=  10000ul // [5] [4]
                    ?   5
                    :   4
                    )
                : 3
                )
            :   // [1-2]
                ( x >=  10ul // [2] [1]
                ?   2
                :   1
                )
            )
        )
    );
}

0

整数 'X'の場合、ループを使用せずに桁数を知りたい場合、このソリューションは1行で1つの数式でのみ機能するため、これはこの問題に対してこれまでに見た中で最も最適なソリューションです。

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 

INT_MAXと負の数も失敗します。
ranu

@ranuはINT_MAXに失敗しましたか?引数がいつ変換されるのdoubleか?または、INT_MAXの10進数を含む不可能な整数入力を参照していますか?ここで他のすべての答えも失敗するでしょうか?
ローンの侯爵

0
int numberOfDigits(int n){

    if(n<=9){
        return 1;
    }
    return 1 + numberOfDigits(n/10);
}

これは、ベース10で必要な場合に行うことです。非常に高速で、整数をカウントするスタックオーバーフロックを購入できません。


0
int num,dig_quant = 0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;
for(int i = 1; i<=num; i*=10){
    if(num / i  > 0){
      dig_quant += 1;
    }
}
 cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
 cout<<"\n\nGoodbye...\n\n";

0

より高速の方が効率的である場合、これはandrei alexandrescuの改善の改善です。彼のバージョンは、素朴な方法(すべての桁で10で割る)よりもすでに高速でした。以下のバージョンは一定時間で、少なくともすべてのサイズでx86-64とARMで高速ですが、バイナリコードの2倍のサイズを占めるため、キャッシュに適していません。

私のアレキのバージョン対このバージョンのベンチマーク愚行FacebookでPR

上の作品unsigned、ではありませんsigned

inline uint32_t digits10(uint64_t v) {
  return  1
        + (std::uint32_t)(v>=10)
        + (std::uint32_t)(v>=100)
        + (std::uint32_t)(v>=1000)
        + (std::uint32_t)(v>=10000)
        + (std::uint32_t)(v>=100000)
        + (std::uint32_t)(v>=1000000)
        + (std::uint32_t)(v>=10000000)
        + (std::uint32_t)(v>=100000000)
        + (std::uint32_t)(v>=1000000000)
        + (std::uint32_t)(v>=10000000000ull)
        + (std::uint32_t)(v>=100000000000ull)
        + (std::uint32_t)(v>=1000000000000ull)
        + (std::uint32_t)(v>=10000000000000ull)
        + (std::uint32_t)(v>=100000000000000ull)
        + (std::uint32_t)(v>=1000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000ull)
        + (std::uint32_t)(v>=100000000000000000ull)
        + (std::uint32_t)(v>=1000000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000000ull);
}

0

ユーザーが数字の桁数を正しく回答したかどうかを確認する必要があるプログラムで作業していたため、整数の桁数を確認する方法を開発する必要がありました。それは結局解決するのが比較的簡単なことでした。

double check=0, exponent=1000;

while(check<=1)
{
    check=number/pow(10, exponent);
    exponent--;
}

exponent=exponent+2;
cout<<exponent<<endl;

これは、現在10 ^ 1000桁未満の数値で機能する私の答えになりました(指数の値を変更することで変更できます)。

PS私はこの答えが10年遅れていることを知っていますが、他の人がそれを使用する可能性があるため、2020年にここに到着しました。


-1
template <typename type>
class number_of_decimal_digits {   
    const powers_and_max<type> mPowersAndMax;
public:
    number_of_decimal_digits(){
    }   
    inline size_t ndigits( type i) const {
        if(i<0){
             i += (i == std::numeric_limits<type>::min());
             i=-i;
        }
        const type* begin = &*mPowersAndMax.begin();
        const type* end = begin+mPowersAndMax.size();
        return 1 + std::lower_bound(begin,end,i) - begin;
    }
    inline size_t string_ndigits(const type& i) const {
        return (i<0) + ndigits(i);
    }
    inline size_t operator[](const type& i) const {
       return string_ndigits(i);
    }
};

でどこpowers_and_max我々は(10^n)-1すべてのためにn、このような

(10^n) < std::numeric_limits<type>::max()

そしてstd::numeric_limits<type>::max()配列で:

template <typename type>
struct powers_and_max : protected std::vector<type>{
    typedef std::vector<type> super;
    using super::const_iterator;
    using super::size;
    type& operator[](size_t i)const{return super::operator[](i)};
    const_iterator begin()const {return super::begin();} 
    const_iterator end()const {return super::end();} 
    powers_and_max() {
       const int size = (int)(log10(double(std::numeric_limits<type>::max())));
       int j = 0;
       type i = 10;
       for( ; j<size ;++j){
           push_back(i-1);//9,99,999,9999 etc;
           i*=10;
       }
       ASSERT(back()<std::numeric_limits<type>::max());
       push_back(std::numeric_limits<type>::max());
   }
};

ここに簡単なテストがあります:

number_of_decimal_digits<int>  ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);

もちろん、順序付けされたセットの他の実装が使用される可能性がpowers_and_maxあり、クラスタリングが存在するという知識があったとしても、クラスタがおそらく自己調整ツリー実装である可能性がある場所についての知識は最善ではないかもしれません


-1

効果的な方法

int num;
int count = 0;
while(num)
{
   num /= 10;
   ++count;
}

#include <iostream>

int main()
{
   int num;
   std::cin >> num;

   std::cout << "number of digits for " << num << ": ";

   int count = 0;
   while(num)
   {
      num /= 10;
      ++count;
   }

   std::cout << count << '\n';

   return 0;
}

-1

優先ソリューションのC ++ 11更新:

#include <limits>
#include <type_traits>
        template <typename T>
        typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
        numberDigits(T value) {
            unsigned int digits = 0;
            if (value < 0) digits = 1;
            while (value) {
                value /= 10;
                ++digits;
            }
            return digits;
        }

doubleなどによるテンプレートのインスタンス化を防止します。al。


-1
int numberOfDigits(double number){
    if(number < 0){
        number*=-1;
    }
    int i=0;
        while(number > pow(10, i))
            i++;    
    cout << "This number has " << i << " digits" << endl;
    return i;
}

-2

これが私のやり方です:

   int digitcount(int n)
    {
        int count = 1;
        int temp = n;
        while (true)
        {
            temp /= 10;
            if (temp != 0) ++count;
            if (temp == 0) break;
        }

        return count;
    }

2
しばらく真/ブレーク症候群:D
ПетърПетров

-1これは、6年前に最初の回答が示したのと同じアプローチであり、何も追加しません(実際にはかなり悪い)。

-4

ここに別のアプローチがあります:

digits = sprintf(numArr, "%d", num);    // where numArr is a char array
if (num < 0)
    digits--;

これは効率的ではなく、他の人が提案したものとは異なるだけです。


4
要求は非常に効率的でした。これは逆です。
Ira Baxter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.