intの桁数を取得する方法は?


386

このメソッドよりもintの長さを取得するためのより良い方法はありますか?

int length = String.valueOf(1000).length();

7
intの長さを定義してください。
トム、

24
彼は数字の桁を数えたいと思います。
アルベルト・ザッカニ2009

3
人々があなたに与えている答えは正しいです...彼らはあなたにそれを文字列に変換せずにあなたの長さを与えます...しかしなぜそれを文字列に変換したくないのですか?スピードってこと?もしそうなら、私はこれらの方法がより速くなるとは確信していません...あなたはいくつかのテストをしたいかもしれません(またはそれが重要かどうかを決定します。)
Beska

3
@ptomliの16進数字は、別の基本システムでも数字のままです。
マーク・ピム

2
@Ptomliもちろん、Integer.toString関数と一般的な会話の両方で、10進数がデフォルトです。銀行から「このボックスに小切手の金額を記入してください」と言われたときは、10進数、16進数、8進数のどちらで記入するかは尋ねません。特に明記されていない限り、または文脈によって要求されない限り、10進数を想定しています。
ジェイ

回答:


349

あなたの文字列ベースのソリューションは完全に問題なく、それについて「きちんとした」ものは何もありません。数学的には、数値には長さがなく、数字もないことを理解する必要があります。長さと数字はどちらも、特定の基数、つまり文字列での数値の物理表現のプロパティです。

対数ベースのソリューションは、文字列ベースのソリューションが内部で行うことと同じことを(一部)行い、長さのみを生成して桁を無視するため、おそらく(わずかに)より高速になります。しかし、私は実際にはそれを意図としてより明確に考えることはしません-そしてそれが最も重要な要素です。


54
+1は、問題を解決する方法を選択するときにコードの意図を考慮する
pupeno 2008

5
データポイント:私のマシンでは、logメソッドは文字列長メソッドの2倍の速さで実行されているようです。メソッドが頻繁に呼び出されたり、コードのタイムクリティカルなセクションで呼び出されたりしても、それほど重要ではありません。
CPerkins、2009

1
以下のベンチマークの単体テストを参照してください(これも欠陥がある可能性があるため、ベンチマークの専門家ではありません)。実行回数が多い(100 000 000)場合、私のマシンの速度は11秒から8秒で、2倍も速くはありません。
ジャン・

5
@CPerkins。時期尚早の最適化。あなたは酒を知っています。
マイケルボルグワート

11
いくつかの(かなり遅い)追加:「-」が数字であると期待するかどうかに応じて、負の値に対しては正しく機能しない可能性があります。Math.abs()ただし、追加するとこれは修正されます。
YingYang

265

対数はあなたの友達です:

int n = 1000;
int length = (int)(Math.log10(n)+1);

注意:n> 0の場合のみ有効です。


2
そして、これは私のバリアントを使用するよりも速いですか?
fnst

+1あなたは私を1秒ずつ殴りましたが、あなたの答えは正解でした。ただし、int
Dirk

2
@トムなぜそれが高いと思いますか?数値演算コプロセッサがそれを実行すると想定しているため、加算の速度に近い場合があります。Javaが現在コプロセッサを使用していない場合でも、それが適切であると想定します...もしあなたがshootout.alioth.debian.orgに行って自分で調べてみたら)
ビルK

8
動作します...チェックしている値= 0でない限り、奇妙な結果になります(-2147483647)。Math.log10 API:「引数が正のゼロまたは負のゼロの場合、結果は負の無限大です。」
mujimu

2
+1オブジェクトのメモリ割り当てを含まないメソッドの提示。これは、GCコレクションを回避するために再利用を最大化するために必要です。
Michael Wojcik 2012

159

最速のアプローチ:分割統治。

範囲が0〜MAX_INTであるとすると、1〜10桁になります。各入力ごとに最大4つの比較を使用して、分割統治を使用してこの間隔にアプローチできます。最初に、[1..10]を1つの比較で[1..5]と[6..10]に分割し、次に、1つの比較を使用して1つの長さ3と1つの長さ2の間隔に分割する各長さ5の間隔を分割します。長さ2の間隔にはさらに1つの比較(合計3つの比較)が必要です。長さ3の間隔は、長さ1の間隔(ソリューション)と長さ2の間隔に分けることができます。したがって、3つまたは4つの比較が必要です。

除算、浮動小数点演算、高価な対数、整数比較のみ。

コード(長いが高速):

if (n < 100000){
        // 5 or less
        if (n < 100){
            // 1 or 2
            if (n < 10)
                return 1;
            else
                return 2;
        }else{
            // 3 or 4 or 5
            if (n < 1000)
                return 3;
            else{
                // 4 or 5
                if (n < 10000)
                    return 4;
                else
                    return 5;
            }
        }
    } else {
        // 6 or more
        if (n < 10000000) {
            // 6 or 7
            if (n < 1000000)
                return 6;
            else
                return 7;
        } else {
            // 8 to 10
            if (n < 100000000)
                return 8;
            else {
                // 9 or 10
                if (n < 1000000000)
                    return 9;
                else
                    return 10;
            }
        }
    }

ベンチマーク(JVMウォームアップ後)-ベンチマークがどのように実行されたかを確認するには、以下のコードを参照してください。

  1. ベースラインメソッド(String.lengthを使用):2145ms
  2. log10メソッド:711ms =ベースラインの3.02倍
  3. 分割の繰り返し:2797ms =ベースラインの0.77倍の速さ
  4. 分割統治:74ms =
    ベースラインの28.99 倍

完全なコード:

public static void main(String[] args)
throws Exception
{

    // validate methods:
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method2(i))
            System.out.println(i);
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));

    // work-up the JVM - make sure everything will be run in hot-spot mode
    allMethod1();
    allMethod2();
    allMethod3();
    allMethod4();

    // run benchmark
    Chronometer c;

    c = new Chronometer(true);
    allMethod1();
    c.stop();
    long baseline = c.getValue();
    System.out.println(c);

    c = new Chronometer(true);
    allMethod2();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");

    c = new Chronometer(true);
    allMethod3();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");

    c = new Chronometer(true);
    allMethod4();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
}


private static int method1(int n)
{
    return Integer.toString(n).length();
}
private static int method2(int n)
{
    if (n == 0)
        return 1;
    return (int)(Math.log10(n) + 1);
}
private static int method3(int n)
{
    if (n == 0)
        return 1;
    int l;
    for (l = 0 ; n > 0 ;++l)
        n /= 10;
    return l;
}
private static int method4(int n)
{
    if (n < 100000)
    {
        // 5 or less
        if (n < 100)
        {
            // 1 or 2
            if (n < 10)
                return 1;
            else
                return 2;
        }
        else
        {
            // 3 or 4 or 5
            if (n < 1000)
                return 3;
            else
            {
                // 4 or 5
                if (n < 10000)
                    return 4;
                else
                    return 5;
            }
        }
    }
    else
    {
        // 6 or more
        if (n < 10000000)
        {
            // 6 or 7
            if (n < 1000000)
                return 6;
            else
                return 7;
        }
        else
        {
            // 8 to 10
            if (n < 100000000)
                return 8;
            else
            {
                // 9 or 10
                if (n < 1000000000)
                    return 9;
                else
                    return 10;
            }
        }
    }
}


private static int allMethod1()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method1(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method1(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method1(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method1(i);

    return x;
}
private static int allMethod2()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method2(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method2(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method2(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method2(i);

    return x;
}
private static int allMethod3()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method3(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method3(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method3(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method3(i);

    return x;
}
private static int allMethod4()
{
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method4(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method4(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method4(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method4(i);

    return x;
}

ここでも、ベンチマーク:

  1. ベースラインメソッド(String.lengthを使用):2145ms
  2. log10メソッド:711ms =ベースラインの3.02倍
  3. 分割の繰り返し:2797ms =ベースラインの0.77倍の速さ
  4. 分割統治:74ms =
    ベースラインの28.99 倍

編集: ベンチマークを書いた後、Java 6からInteger.toStringにピークを入れました。

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

私はそれを私の分割統治ソリューションに対してベンチマークしました:

  1. 分割統治:104ms
  2. Java 6ソリューション-反復して比較:406ms

鉱山は、Java 6ソリューションの約4倍の速度です。


7
これは素晴らしいですね。あなたは使ってもう少しコンパクトにそれを書くことができます:演算子より承認を取得するには?
アンドレ・Pareis

88
時期尚早の最適化について話す:D
Gordon Gustafson

2
私はそれが好きです!ネストされたif-elsesesではなく、switchブロックはどうでしょうか?
Kebman 2013年

2
else ifステートメントがintをStringに変換して.lengthを呼び出すよりもはるかに高速である場合、私はこれらすべてを理解していませんでした。+1
Ogen 2014

15
三項演算子を使用して、101個の文字にそれをダウンさせます:n<100000?n<100?n<10?1:2:n<1000?3:n<10000?4:5:n<10000000?n<1000000?6:7:n<100000000?8:n<1000000000?9:10
ジョナサンGawrych

13

ベンチマークに関する2つのコメント:Javaは、ジャストインタイムのコンパイルとガベージコレクションなどを備えた複雑な環境であるため、公正な比較を行うために、ベンチマークを実行するときはいつでも、常に(a)2つのテストを囲みます。それらを順番に5回または10回実行するループ内。多くの場合、ループの2番目のパスのランタイムは、最初のものとはかなり異なります。(b)各「アプローチ」の後で、私はSystem.gc()を実行して、ガベージコレクションをトリガーしようとします。そうしないと、最初のアプローチでオブジェクトの束が生成される可能性がありますが、ガベージコレクションを強制するのに十分ではなく、2番目のアプローチではいくつかのオブジェクトが作成され、ヒープが使い果たされ、ガベージコレクションが実行されます。次に、2番目のアプローチは、最初のアプローチで残されたごみを拾うために「課金」されます。とても不公平です!

とはいえ、上記のどちらもこの例では大きな違いはありませんでした。

これらの変更の有無にかかわらず、私はあなたとは非常に異なる結果を得ました。私がこれを実行したとき、はい、toStringアプローチは6400〜6600ミリ秒の実行時間を与えましたが、logアプローチは20,000〜20,400ミリ秒を要しました。ログアプローチは少し高速ではなく、3倍遅くなりました。

2つのアプローチは非常に異なるコストを伴うため、これはまったく衝撃的ではありません。toStringアプローチはクリーンアップする必要のある多くの一時オブジェクトを作成しますが、ログアプローチはより強力な計算を行います。つまり、メモリが少ないマシンでは、toStringに必要なガベージコレクションの回数が増える一方、遅いプロセッサを搭載したマシンでは、ログの余分な計算がさらに面倒になるという違いがあるかもしれません。

私も3番目の方法を試しました。私はこの小さな関数を書きました:

static int numlength(int n)
{
    if (n == 0) return 1;
    int l;
    n=Math.abs(n);
    for (l=0;n>0;++l)
        n/=10;
    return l;           
}

これは1600〜1900ミリ秒で実行されました。私のマシンでは、toStringアプローチの1/3未満、ログアプローチの1/10未満です。

数値の範囲が広い場合は、1,000または1,000,000で除算し始めて、ループの回数を減らすことでさらに高速化できます。私はそれで遊んだことがありません。


入力を変えてみましたか?ホットスポットVMは、このグラフを最適化しないと、毎回同じ事前計算されたものを返すため、誤ったベンチマークが発生します。
Erik Aigner

11

Javaの使用

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;

import java.lang.Math.*;最初に使用

Cの使用

int nDigits = floor(log10(abs(the_integer))) + 1;

使用する inclue math.h最初に


1
参考までに、の場合the_integerは無限大になり0ます。確認してください。
Erik Aigner

10

まだコメントを残すことができないので、別の回答として投稿します。

対数ベースのソリューションは、非常に大きな長整数の正しい桁数を計算しません。次に例を示します。

long n = 99999999999999999L;

// correct answer: 17
int numberOfDigits = String.valueOf(n).length();

// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1); 

対数ベースのソリューションは、大きな整数の誤った桁数を計算します


代わりに(int)(Math.log10(n + j))を試してください。jは10-(n-n / 10 * 10)です。
エリックストーン

8

整数の基数10の桁数は1 + truncate(log10(number))なので、次のことができます。

public class Test {

    public static void main(String[] args) {

        final int number = 1234;
        final int digits = 1 + (int)Math.floor(Math.log10(number));

        System.out.println(digits);
    }
}

編集した私の最後の編集は、記述のコード例を固定ではなくので。


涼しい。しかし、abs(number)が必要だと思います。また、「0」も特殊なケースですか?
DmitryK 2009

はい。記号を説明する必要がある場合は、1 +(int)Math.floor(Math.log10(Math.abs(number)))+((number <0)?1:0)
ダーク

5
これMath.floorは少し冗長ですよね。キャストするintと、とにかく丸められます。
CompuChip 2014

5

マリアンのソリューションは、誰かがそれをコピーして貼り付けたい場合に備えて、長いタイプの数値(最大9,223,372,036,854,775,807)に適応しました。プログラムでこれを書いたのは、10000までの数字の方がはるかに可能性が高かったためです。そのため、特定のブランチを作成しました。とにかく、それは大きな違いはありません。

public static int numberOfDigits (long n) {     
    // Guessing 4 digit numbers will be more probable.
    // They are set in the first branch.
    if (n < 10000L) { // from 1 to 4
        if (n < 100L) { // 1 or 2
            if (n < 10L) {
                return 1;
            } else {
                return 2;
            }
        } else { // 3 or 4
            if (n < 1000L) {
                return 3;
            } else {
                return 4;
            }
        }           
    } else  { // from 5 a 20 (albeit longs can't have more than 18 or 19)
        if (n < 1000000000000L) { // from 5 to 12
            if (n < 100000000L) { // from 5 to 8
                if (n < 1000000L) { // 5 or 6
                    if (n < 100000L) {
                        return 5;
                    } else {
                        return 6;
                    }
                } else { // 7 u 8
                    if (n < 10000000L) {
                        return 7;
                    } else {
                        return 8;
                    }
                }
            } else { // from 9 to 12
                if (n < 10000000000L) { // 9 or 10
                    if (n < 1000000000L) {
                        return 9;
                    } else {
                        return 10;
                    }
                } else { // 11 or 12
                    if (n < 100000000000L) {
                        return 11;
                    } else {
                        return 12;
                    }
                }
            }
        } else { // from 13 to ... (18 or 20)
            if (n < 10000000000000000L) { // from 13 to 16
                if (n < 100000000000000L) { // 13 or 14
                    if (n < 10000000000000L) { 
                        return 13;
                    } else {
                        return 14;
                    }
                } else { // 15 or 16
                    if (n < 1000000000000000L) {
                        return 15;
                    } else {
                        return 16;
                    }
                }
            } else { // from 17 to ...¿20?
                if (n < 1000000000000000000L) { // 17 or 18
                    if (n < 100000000000000000L) {
                        return 17;
                    } else {
                        return 18;
                    }
                } else { // 19? Can it be?
                    // 10000000000000000000L is'nt a valid long.
                    return 19;
                }
            }
        }
    }
}

この質問のタイトルを「int / longの桁数を取得する方法」に変更する必要がありますか?(「long」タグを追加)
JAIL

4

別の文字列アプローチ。短くて甘い-どんな整数でもn

int length = ("" + n).length();

正の整数nとゼロに対してのみ機能します。("" + Math.abs(n)).length()負の整数の長さを取得するために使用できます。
ThisClark

3

やっていい?;)

ダークの解に基づく

final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));

3

普通の数学はどうですか?0になるまで10で割ります。

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }

1
あなたはそれをテストしましたか?人間の視点では意味がありませんが、マシンの「考え方」と同じように機能するわけではありませんよね。--- 1つのことを提案します。200万の数値の配列を作成しLong.MAX_VALUEます。これは、コードの最も複雑なケースでありSystem.nanoTime()、他のソリューションの最も複雑なケースに対してクロックトライアルを実行するために使用します。++実際には、次の範囲に設定されたランダマイザーで満たされた配列で試してください0Long.MAX_VALUEは、「平均的な複雑さ」のテストのためだけ toに ++結果が見つかるかもしれません...非常に衝撃的です。
XenoRo

@thelimaこれはゼロまたはネガティブでは正しく機能しませんが、それはマイナーなバグです。原則は私には正しいようです。どのような「衝撃的な」結果を参照していますか?
ジェイ

ただコンピュータと言ってみましょう...ええと...彼らは分割が好きではありません。そして、大きな数の大きな「キュー」を処理する必要があり、処理された各数の各桁に除算が必要な場合...ええと...もの「本当に本当に遅くなるのは本当に速い」...意味... ---これが、テストに基づくコードと、除算ではなく「if」を使用した各10進数字との比較を使用してここで多くの回答を見る理由です。最悪のケースです。---多数の除算と対数を使用してテストを行う...
XenoRo

@TheLima何言ってるの?int,thisループの場合、最大11回実行されます。あなたの主張の証拠はありますか?
ローン侯爵

@EJPハードウェアの観点から見ると、除算は反復的なプロセスです。私が知っている最速の除算アルゴリズムはradix4で、反復ごとに4ビットを生成します。したがって、32ビットの除算には少なくとも8回の反復が必要です。たとえば、乗算は並行して行うことができ、より単純な乗算に分解することもできます。ビットレベルまで下げる(5つの操作のみが必要)、または部分的なブレークダウンと最後にルックアップテーブルを使用する(クラシックサイズとスピードのトレードオフ)。「反復回数」だけではありません。除算の問題は「ハードウェアレベルでの各反復の意味/処理」にあります
XenoRo

2

Marian's Solution、現在Ternaryで:

 public int len(int n){
        return (n<100000)?((n<100)?((n<10)?1:2):(n<1000)?3:((n<10000)?4:5)):((n<10000000)?((n<1000000)?6:7):((n<100000000)?8:((n<1000000000)?9:10)));
    }

そのため我々はできます。


2
それはちょっと読みにくいです。多分いくつかのスペースや改行を追加します。
michaelb958--GoFundMonica 2013

しかし、いまいましいそれはポータブルです!
Trevor Rudolph

1

好奇心が強い、私はそれをベンチマークしようとした...

import org.junit.Test;
import static org.junit.Assert.*;


public class TestStack1306727 {

    @Test
    public void bench(){
        int number=1000;
        int a= String.valueOf(number).length();
        int b= 1 + (int)Math.floor(Math.log10(number));

        assertEquals(a,b);
        int i=0;
        int s=0;
        long startTime = System.currentTimeMillis();
        for(i=0, s=0; i< 100000000; i++){
            a= String.valueOf(number).length();
            s+=a;
        }
        long stopTime = System.currentTimeMillis();
        long runTime = stopTime - startTime;
        System.out.println("Run time 1: " + runTime);
        System.out.println("s: "+s);
        startTime = System.currentTimeMillis();
        for(i=0,s=0; i< 100000000; i++){
            b= number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
            s+=b;
        }
        stopTime = System.currentTimeMillis();
        runTime = stopTime - startTime;
        System.out.println("Run time 2: " + runTime);
        System.out.println("s: "+s);
        assertEquals(a,b);


    }
}

結果は次のとおりです。

実行時間1:6765
s:400000000
実行時間2:6000
s:400000000

今、私は私のベンチマークが実際に何かを意味するのかどうか疑問に思っていますが、ベンチマーク自体の複数の実行で一貫した結果(ミリ秒以内の変動)を取得します... :)これを試して最適化するのは役に立たないようです...


編集:ptomliのコメントに続いて、上のコードで「number」を「i」に置き換え、ベンチの5回の実行で次の結果を得ました。

実行時間1:11500
s:788888890
実行時間2:8547
s:788888890

実行時間1:11485
s:788888890
実行時間2:8547
s:788888890

実行時間1:11469
s:788888890
実行時間2:8547
s:788888890

実行時間1:11500
s:788888890
実行時間2:8547
s:788888890

実行時間1:11484
s:788888890
実行時間2:8547
s:788888890

1
ただ面白くするために、たとえば0から1兆までの数の値の分布の違いは何ですか?:)
ptomli 2009

0

この再帰的な方法はどうですか?

    private static int length = 0;

    public static int length(int n) {
    length++;
    if((n / 10) < 10) {
        length++;
    } else {
        length(n / 10);
    }
    return length;
}

0

簡単な解決策:

public class long_length {
    long x,l=1,n;
    for (n=10;n<x;n*=10){
        if (x/n!=0){
            l++;
        }
    }
    System.out.print(l);
}

0

本当に簡単な解決策:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}

空の本体を含むループを1行で呼び出すのは簡単ではありません。また、10の累乗を法として、同じ結果が得られるかどうかを確認します(比較を使用することはできませんか?)。
Teepeemm、2015

0

または、代わりに長さが目的の数値よりも大きいか小さいかを確認できます。

    public void createCard(int cardNumber, int cardStatus, int customerId) throws SQLException {
    if(cardDao.checkIfCardExists(cardNumber) == false) {
        if(cardDao.createCard(cardNumber, cardStatus, customerId) == true) {
            System.out.println("Card created successfully");
        } else {

        }
    } else {
        System.out.println("Card already exists, try with another Card Number");
        do {
            System.out.println("Enter your new Card Number: ");
            scan = new Scanner(System.in);
            int inputCardNumber = scan.nextInt();
            cardNumber = inputCardNumber;
        } while(cardNumber < 95000000);
        cardDao.createCard(cardNumber, cardStatus, customerId);
    }
}

}


わかりません。別の質問に答えているようです。
Teepeemm、2015

0

乗算ベースのソリューションはまだ見ていません。対数、除算、および文字列ベースのソリューションは、何百万ものテストケースに対してかなり扱いにくくなるため、以下を対象としますints

/**
 * Returns the number of digits needed to represents an {@code int} value in 
 * the given radix, disregarding any sign.
 */
public static int len(int n, int radix) {
    radixCheck(radix); 
    // if you want to establish some limitation other than radix > 2
    n = Math.abs(n);

    int len = 1;
    long min = radix - 1;

    while (n > min) {
        n -= min;
        min *= radix;
        len++;
    }

    return len;
}

基数10では、これは機能します。これは、nが本質的に9、99、999と比較されるためです。

残念ながら、これはオーバーフローによるlongすべてのインスタンスを置き換えるだけでは移植できませんint。一方で、それはたまたま起こりますだろう拠点2と10のために働く(がひどく、他の拠点のほとんどのために失敗しました)。オーバーフローポイントのルックアップテーブル(または除算テスト... ew)が必要です

/**
 * For radices 2 &le r &le Character.MAX_VALUE (36)
 */
private static long[] overflowpt = {-1, -1, 4611686018427387904L,
    8105110306037952534L, 3458764513820540928L, 5960464477539062500L,
    3948651115268014080L, 3351275184499704042L, 8070450532247928832L,
    1200757082375992968L, 9000000000000000000L, 5054470284992937710L,
    2033726847845400576L, 7984999310198158092L, 2022385242251558912L,
    6130514465332031250L, 1080863910568919040L, 2694045224950414864L,
    6371827248895377408L, 756953702320627062L, 1556480000000000000L,
    3089447554782389220L, 5939011215544737792L, 482121737504447062L,
    839967991029301248L, 1430511474609375000L, 2385723916542054400L,
    3902460517721977146L, 6269893157408735232L, 341614273439763212L,
    513726300000000000L, 762254306892144930L, 1116892707587883008L,
    1617347408439258144L, 2316231840055068672L, 3282671350683593750L,
    4606759634479349760L};

public static int len(long n, int radix) {
    radixCheck(radix);
    n = abs(n);

    int len = 1;
    long min = radix - 1;
    while (n > min) {
        len++;
        if (min == overflowpt[radix]) break;
        n -= min;
        min *= radix;

    }

    return len;
}

0

設計あり(問題に基づく)。これは、分割統治の代替手段です。最初に列挙型を定義します(それがunsigned int専用であることを考慮して)。

public enum IntegerLength {
    One((byte)1,10),
    Two((byte)2,100),
    Three((byte)3,1000),
    Four((byte)4,10000),
    Five((byte)5,100000),
    Six((byte)6,1000000),
    Seven((byte)7,10000000),
    Eight((byte)8,100000000),
    Nine((byte)9,1000000000);

    byte length;
    int value;

    IntegerLength(byte len,int value) {
        this.length = len;
        this.value = value;
    }

    public byte getLenght() {
        return length;
    }

    public int getValue() {
        return value;
    }
}

次に、列挙型の値を通過するクラスを定義し、適切な長さを比較して返します。

public class IntegerLenght {
    public static byte calculateIntLenght(int num) {    
        for(IntegerLength v : IntegerLength.values()) {
            if(num < v.getValue()){
                return v.getLenght();
            }
        }
        return 0;
    }
}

このソリューションの実行時間は、分割統治アプローチと同じです。


分割統治は中央から始まり、残りの探索領域を二等分します。これは線形実行時間を持っています。しかし、9つの比較だけでは問題になりません。しかし、これはめちゃくちゃになりませんかnum>=Nine.getValue()
Teepeemm

0

たいていの場合、これを「提示」したいという理由でこれを実行したいと考えています。つまり、最終的に明示的または暗黙的に最終的に「toString-ed」(または別の方法で変換)する必要があるということです。提示する前(たとえば印刷)。

その場合は、必要な「toString」を明示的にして、ビットを数えるようにしてください。


0

再帰ループを使用してこれを実現できます

    public static int digitCount(int numberInput, int i) {
        while (numberInput > 0) {
        i++;
        numberInput = numberInput / 10;
        digitCount(numberInput, i);
        }
        return i;
    }

    public static void printString() {
        int numberInput = 1234567;
        int digitCount = digitCount(numberInput, 0);

        System.out.println("Count of digit in ["+numberInput+"] is ["+digitCount+"]");
    }

0

この関数は、Integer.javaソースコードを調べて作成しました。

private static int stringSize(int x) {
    final int[] sizeTable = {9, 99, 999, 9_999, 99_999, 999_999, 9_999_999,
            99_999_999, 999_999_999, Integer.MAX_VALUE};
    for (int i = 0; ; ++i) {
        if (x <= sizeTable[i]) {
            return i + 1;
        }
    }
}

0

StringライブラリやIntegerクラスを使用している人もいます。何も問題はありませんが、桁数を取得するアルゴリズムはそれほど複雑ではありません。この例ではlongを使用していますが、intでも同じように機能します。

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}

0

文字列APIなし、ユーティリティなし、型変換なし、純粋なJava反復のみ->

public static int getNumberOfDigits(int input) {
    int numOfDigits = 1;
    int base = 1;
    while (input >= base * 10) {
        base = base * 10;
        numOfDigits++;
    }
    return numOfDigits;
 }

よければ、より大きな値を長くすることができます。


-1
    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);

「10で割る」ソリューションは、2年前にSinistaによって最初に投稿されました。
Teepeemm、2015

-1

簡単な再帰的な方法

int    get_int_lenght(current_lenght, value)
{
 if (value / 10 < 10)
    return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}

未検証


3
あなたはおそらくそれをテストするべきです(そしてそれが有効なJavaであり、適切にフォーマットされていることを確認してください)。しかし、再帰的な "divide by 10"アプローチが3年前にJedi Dulaによって投稿されました。
Teepeemm

-2

10による連続除算を使用して、数字を表示することができます。

int a=0;

if (no < 0) {
    no = -no;
} else if (no == 0) {
    no = 1;
}

while (no > 0) {
    no = no / 10;
    a++;
}

System.out.println("Number of digits in given number is: "+a);

"divide by 10"アプローチは、3年前にSinistaによって最初に投稿されました。それが私があなたが反対票を得たと考えることができる唯一の理由です。
Teepeemm、2015

-2

番号を入力してを作成するArraylistと、whileループがすべての桁をに記録しますArraylist。次に、配列のサイズを取り出します。これは、入力した整数値の長さになります。

ArrayList<Integer> a=new ArrayList<>();

while(number > 0) 
{ 
    remainder = num % 10; 
    a.add(remainder);
    number = number / 10; 
} 

int m=a.size();

1
ただし、ArrayListや数字は必要ありません。
ローンの侯爵

-2

これは私が作った本当に簡単な方法で、どんな数でも機能します:

public static int numberLength(int userNumber) {

    int numberCounter = 10;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        int numberRatio = userNumber / numberCounter;
        if (numberRatio < 1) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }

    return digitLength; 
}

それが機能する方法は、数値カウンタ変数を使用することで、10 = 1桁のスペースです。たとえば、.1 = 1/10 => 1桁のスペース。したがって、int number = 103342;6を取得すると、.000001スペースに相当するため、6になります。また、誰かがより良い変数名を持っていますnumberCounterか?これ以上のことは考えられません。

編集:ちょうどより良い説明を考えました。基本的に、このwhileループが行っていることは、数値が1未満になるまで10で除算することです。基本的に、何かを10で割ると、それは1つの数値スペースだけ戻ります。そのため、数値の桁数が1未満になるまで10で割るだけです。

以下は、数値を小数でカウントできる別のバージョンです。

public static int repeatingLength(double decimalNumber) {

    int numberCounter = 1;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        double numberRatio = decimalNumber * numberCounter;

        if ((numberRatio - Math.round(numberRatio)) < 0.0000001) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }
    return digitLength - 1;
}

-3

変換してみint型文字列、その後の長さを取得する文字列を。これでintの長さが得られます。

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}

これは元のコードと完全に同等です。numberネガティブな場合は見逃します。
Teepeemm、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.