Cách để có được số chữ số trong một int?


386

Có cách nào gọn gàng hơn để có được độ dài của int hơn phương thức này không?

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

7
xác định độ dài của một int xin vui lòng.
Tom

24
Tôi nghĩ rằng anh ấy muốn đếm các chữ số trong số.
Alberto Zaccagni

3
Các câu trả lời mà mọi người đưa ra cho bạn là chính xác ... họ cung cấp cho bạn độ dài của int mà không chuyển đổi nó thành một chuỗi ... nhưng tại sao bạn không muốn chuyển đổi nó thành một chuỗi? Nó có phải là một điều tốc độ? Nếu vậy, tôi không tin rằng các phương pháp này sẽ nhanh hơn ... bạn có thể muốn thực hiện một số thử nghiệm (hoặc quyết định xem nó có quan trọng không.)
Beska

3
@ptomli chữ số thập lục phân vẫn là chữ số, chỉ trong một hệ thống cơ sở khác.
Đánh dấu Pim

2
@Ptomli Chắc chắn, nhưng cả trong hàm Integer.toString và trong cuộc hội thoại chung, số thập phân là mặc định. Khi ngân hàng nói với tôi, "Viết số tiền của séc của bạn vào ô này", tôi không hỏi họ liệu tôi nên viết nó dưới dạng thập phân, thập lục phân hay bát phân. Chúng tôi giả sử thập phân trừ khi có quy định khác hoặc được gọi theo ngữ cảnh.
Jay

Câu trả lời:


349

Giải pháp dựa trên Chuỗi của bạn là hoàn toàn OK, không có gì "không gọn gàng" về nó. Bạn phải nhận ra rằng về mặt toán học, các con số không có độ dài cũng như chúng không có chữ số. Độ dài và chữ số là cả hai thuộc tính của biểu diễn vật lý của một số trong một cơ sở cụ thể, tức là Chuỗi.

Một giải pháp dựa trên logarit thực hiện (một số) những điều tương tự như giải pháp dựa trên Chuỗi thực hiện bên trong và có thể làm như vậy (không đáng kể) vì nó chỉ tạo ra độ dài và bỏ qua các chữ số. Nhưng tôi thực sự sẽ không xem xét nó rõ ràng hơn trong ý định - và đó là yếu tố quan trọng nhất.


54
+1 để xem xét ý định của mã khi chọn cách giải quyết vấn đề
Pupeno

5
Datapoint: Trên máy của tôi, phương thức log dường như chỉ chạy nhanh gấp đôi so với các phương thức độ dài chuỗi. Tôi sẽ không gọi nó là không đáng kể nếu phương thức được gọi nhiều hoặc trong một đoạn mã quan trọng về thời gian.
CPerkins

1
Xem bài kiểm tra đơn vị điểm chuẩn của tôi dưới đây (có thể là thiếu sót vì tôi không phải là chuyên gia điểm chuẩn). Qua một số lượng lớn các lần chạy (100 000 000), tốc độ là 11 giây đến 8 giây trên máy của tôi khó gấp đôi.
Jean

5
@CPerkins. Tối ưu hóa sớm. Bạn biết chi tiêu.
Michael Borgwardt

11
Một số bổ sung (khá muộn): Nó có thể không hoạt động chính xác cho các giá trị âm, tùy thuộc vào việc bạn có mong muốn "-" là một chữ số hay không. Thêm Math.abs()sẽ khắc phục điều này, mặc dù.
YingYang

265

Logarit là bạn của bạn:

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

NB: chỉ có giá trị cho n> 0.


2
Và điều này nhanh hơn hay tốt hơn so với việc sử dụng biến thể của tôi?
fnst

+1 Bạn đánh bại tôi trong một giây và câu trả lời của bạn là đúng, trong đó câu trả lời của tôi hơi bị tắt. Tuy nhiên, xin lưu ý rằng trình biên dịch sẽ khiếu nại do thiếu cast đến int
Dirk

2
@Tom Tại sao bạn lại cho rằng nó đắt? Người ta có thể cho rằng bộ đồng xử lý toán học sẽ thực thi nó, vì vậy nó có thể gần với tốc độ của một phép cộng. Ngay cả khi java không sử dụng bộ đồng xử lý ngay bây giờ, thì đó cũng là một giả định tốt rằng nó có thể ... (Chúng tôi sẽ bỏ qua hàm ý thậm chí vô học hơn của bạn rằng Java chậm vì có thể bạn không quan tâm đến bằng chứng - hoặc nếu bạn là bạn hãy đến shotout.alioth.debian.org và tự mình tìm hiểu)
Bill K

8
Hoạt động ... trừ khi giá trị bạn đang kiểm tra = 0, sẽ cho bạn kết quả lẻ (-2147483647). API Math.log10: "Nếu đối số là số 0 dương hoặc số 0 âm, thì kết quả là vô cực âm."
mujimu

2
+1 Trình bày một phương thức không liên quan đến việc phân bổ bộ nhớ đối tượng, đây là điều bắt buộc để tối đa hóa việc sử dụng lại để tránh các bộ sưu tập GC.
Michael Wojcik

159

Cách tiếp cận nhanh nhất: phân chia và chinh phục.

Giả sử phạm vi của bạn là 0 đến MAX_INT, thì bạn có 1 đến 10 chữ số. Bạn có thể tiếp cận khoảng thời gian này bằng cách chia và chinh phục, với tối đa 4 so sánh cho mỗi đầu vào. Đầu tiên, bạn chia [1..10] thành [1..5] và [6..10] với một so sánh, và sau đó mỗi chiều dài 5 khoảng bạn chia bằng cách sử dụng một so sánh thành một chiều dài 3 và một khoảng cách 2 chiều dài. Khoảng cách 2 chiều dài yêu cầu thêm một so sánh (tổng 3 so sánh), khoảng cách 3 chiều dài có thể được chia thành chiều dài 1 khoảng (giải pháp) và khoảng cách 2 chiều dài. Vì vậy, bạn cần 3 hoặc 4 so sánh.

Không phân chia, không hoạt động điểm nổi, không logarit đắt tiền, chỉ so sánh số nguyên.

Mã (dài nhưng nhanh):

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

Điểm chuẩn (sau khi khởi động JVM) - xem mã bên dưới để xem cách điểm chuẩn được chạy:

  1. phương pháp cơ bản (với String.length): 2145ms
  2. phương pháp log10: 711ms = 3.02 lần nhanh hơn đường cơ sở
  3. phân chia lặp lại: 2797ms = 0,77 lần so với đường cơ sở
  4. chia và chinh phục: 74ms = 28,99
    lần so với đường cơ sở

Mã đầy đủ:

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

Một lần nữa, điểm chuẩn:

  1. phương pháp cơ bản (với String.length): 2145ms
  2. phương pháp log10: 711ms = 3.02 lần nhanh hơn đường cơ sở
  3. phân chia lặp lại: 2797ms = 0,77 lần so với đường cơ sở
  4. chia và chinh phục: 74ms = 28,99
    lần so với đường cơ sở

Chỉnh sửa: Sau khi tôi viết điểm chuẩn, tôi đã lấy một đỉnh lén vào Integer.toString từ Java 6 và tôi thấy rằng nó sử dụng:

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

Tôi đã đánh giá nó dựa trên giải pháp phân chia và chinh phục của mình:

  1. chia và chinh phục: 104ms
  2. Giải pháp Java 6 - lặp lại và so sánh: 406ms

Của tôi nhanh gấp 4 lần giải pháp Java 6.


7
cái này trông thật tuyệt bạn có thể viết nó gọn hơn một chút bằng cách sử dụng toán tử ?: để được chấp nhận nhiều hơn
André Pareis

88
nói về tối ưu hóa sớm: D
Gordon Gustafson

2
Tôi thích nó! Làm thế nào về một khối chuyển đổi thay vì if-elseses lồng nhau?
Kebman

2
Tôi đã không nhận ra tất cả những điều này nếu các câu lệnh khác sẽ nhanh hơn nhiều so với chuyển đổi int thành String sau đó gọi .length. +1
Ogen

15
Sử dụng toán tử ternary, đưa nó xuống 101 ký tự: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
Jonathan Gawrych

13

Hai nhận xét về điểm chuẩn của bạn: Java là một môi trường phức tạp, với việc biên dịch và thu gom rác đúng lúc, v.v., để có được sự so sánh công bằng, bất cứ khi nào tôi chạy một điểm chuẩn, tôi luôn: (a) kèm theo hai bài kiểm tra trong một vòng lặp chạy chúng theo trình tự 5 hoặc 10 lần. Thông thường thời gian chạy trên lần thứ hai đi qua vòng lặp khá khác so với lần đầu tiên. Và (b) Sau mỗi "cách tiếp cận", tôi thực hiện System.gc () để thử kích hoạt bộ sưu tập rác. Mặt khác, cách tiếp cận đầu tiên có thể tạo ra một loạt các đối tượng, nhưng không đủ để buộc một bộ sưu tập rác, sau đó cách tiếp cận thứ hai tạo ra một vài đối tượng, đống bị cạn kiệt và bộ sưu tập rác chạy. Sau đó, cách tiếp cận thứ hai là "tính phí" cho việc nhặt rác còn lại của cách tiếp cận đầu tiên. Rất không công bằng!

Điều đó nói rằng, cả hai điều trên không tạo ra sự khác biệt đáng kể trong ví dụ này.

Có hoặc không có những sửa đổi đó, tôi đã nhận được kết quả rất khác so với bạn đã làm. Khi tôi chạy cái này, vâng, cách tiếp cận toString đã cho thời gian chạy từ 6400 đến 6600 millis, trong khi cách tiếp cận nhật ký topok 20.000 đến 20.400 millis. Thay vì nhanh hơn một chút, cách tiếp cận nhật ký chậm hơn 3 lần đối với tôi.

Lưu ý rằng hai cách tiếp cận liên quan đến chi phí rất khác nhau, vì vậy điều này không hoàn toàn gây sốc: Cách tiếp cận toString sẽ tạo ra rất nhiều đối tượng tạm thời phải được làm sạch, trong khi cách tiếp cận nhật ký cần tính toán mạnh mẽ hơn. Vì vậy, có thể sự khác biệt là trên một máy có ít bộ nhớ hơn, toString yêu cầu nhiều vòng thu gom rác hơn, trong khi trên máy có bộ xử lý chậm hơn, việc tính toán nhật ký thêm sẽ đau đớn hơn.

Tôi cũng đã thử một cách tiếp cận thứ ba. Tôi đã viết chức năng nhỏ này:

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

Nó chạy trong 1600 đến 1900 millis - ít hơn 1/3 so với cách tiếp cận toString và 1/10 cách tiếp cận nhật ký trên máy của tôi.

Nếu bạn có phạm vi số rộng, bạn có thể tăng tốc hơn nữa bằng cách bắt đầu chia cho 1.000 hoặc 1.000.000 để giảm số lần qua vòng lặp. Tôi đã không chơi với điều đó.


Bạn đã thử thay đổi đầu vào? VM hotspot có thể tối ưu hóa biểu đồ này theo cách khác, dẫn đến điểm chuẩn sai, bởi vì nó luôn trả lại cùng một thứ được tính toán trước.
Erik Aigner

11

Sử dụng Java

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

sử dụng import java.lang.Math.*;lúc đầu

Sử dụng C

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

sử dụng inclue math.hlúc đầu


1
Chỉ cần FYI, sẽ dẫn đến vô cùng nếu the_integer0, vì vậy hãy kiểm tra xem.
Erik Aigner

10

Chưa thể để lại nhận xét, vì vậy tôi sẽ đăng dưới dạng câu trả lời riêng.

Giải pháp dựa trên logarit không tính toán số chữ số chính xác cho các số nguyên rất dài, ví dụ:

long n = 99999999999999999L;

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

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

Giải pháp dựa trên logarit tính toán số chữ số không chính xác trong các số nguyên lớn


thử (int) (Math.log10 (n + j)) thay vì j là 10 - (n - n / 10 * 10).
Đá Erick

8

Vì số chữ số trong cơ sở 10 của một số nguyên chỉ là 1 + cắt ngắn (log10 (số)) , bạn có thể làm:

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

Đã chỉnh sửa vì lần chỉnh sửa cuối cùng của tôi đã sửa lỗi ví dụ mã, nhưng không phải mô tả.


Mát mẻ. nhưng tôi nghĩ nó cần abs (số) và "0" cũng là trường hợp đặc biệt?
DmitryK

Đúng. Nếu bạn cần tính đến dấu hiệu, bạn sẽ phải làm một cái gì đó như 1 + (int) Math.floor (Math.log10 (Math.abs (số))) + ((số <0)? 1: 0)
Dirk

5
Các Math.floorlà một chút dư thừa, phải không? Đúc để intlàm tròn nó xuống nào.
CompuChip

5

Giải pháp của Marian phù hợp với số loại dài (lên tới 9.223.372.036.854.775.807), trong trường hợp ai đó muốn Sao chép & Dán nó. Trong chương trình tôi đã viết điều này cho các số lên tới 10000 có nhiều khả năng hơn, vì vậy tôi đã tạo một chi nhánh cụ thể cho chúng. Dù sao nó sẽ không tạo ra một sự khác biệt đáng kể.

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

Có nên đổi tiêu đề của câu hỏi này thành "Cách lấy số chữ số trong một số nguyên / dài?" (và đã thêm thẻ 'dài')
JAIL

4

Một cách tiếp cận chuỗi khác. Ngắn và ngọt ngào - cho bất kỳ số nguyên n.

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

Chỉ hoạt động cho số nguyên dương nvà số không. Có thể sử dụng ("" + Math.abs(n)).length()để có được chiều dài của số nguyên âm.
ThisClark

3

Tôi thử được không? ;)

dựa trên giải pháp của Dirk

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

3

Toán học cũ đơn giản như thế nào? Chia cho 10 cho đến khi bạn đạt 0.

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

1
Bạn đã thử nó chưa? Bạn biết rằng, ngay cả khó khăn cũng có ý nghĩa đối với quan điểm của con người, nó không thực sự hoạt động giống với "cách suy nghĩ" của máy, phải không? --- Hãy để tôi đề xuất một điều: Tạo một mảng gồm hai triệu số, tốt nhất Long.MAX_VALUElà trường hợp phức tạp tồi tệ nhất của mã của bạn và sử dụng System.nanoTime()để thực hiện một thử nghiệm đồng hồ chống lại các trường hợp phức tạp tồi tệ nhất của giải pháp khác. ++ Trên thực tế, hãy thử nó với một mảng lấp đầy bởi một tập Randomizer để phạm vi 0để Long.MAX_VALUEquá, chỉ dành riêng cho các "độ phức tạp trung bình" thử nghiệm ++ Bạn có thể thấy kết quả ... rất gây sốc.
XenoRo

@thelima Điều này không hoạt động chính xác cho số không hoặc tiêu cực, nhưng đó là một lỗi nhỏ. Nguyên tắc có vẻ đúng với tôi. Kết quả "gây sốc" nào mà bạn đang đề cập đến?
Jay

Chúng ta hãy nói rằng máy tính ... Chà ... Họ không thích phân chia. Và trong trường hợp cần xử lý "hàng đợi" số lượng lớn, và mỗi chữ số trong mỗi số được xử lý sẽ yêu cầu phân chia ... Chà ... Mọi thứ "bắt đầu trở nên rất chậm rất nhanh" ... Nếu bạn bắt được tôi nghĩa là ... --- Đây là lý do tại sao bạn thấy nhiều câu trả lời ở đây bằng cách sử dụng mã dựa trên kiểm tra và so sánh với từng chữ số thập phân bằng cách sử dụng 'if, thay vì chia: Nếu không nhanh hơn, ít nhất nó vẫn duy trì hầu hết tốc độ của nó trong trường hợp xấu nhất. --- Thực hiện kiểm tra giữa việc sử dụng các bộ phận và logarit trên số lượng lớn ...
XenoRo

@TheLima bạn đang nói về cái gì vậy? Đối với một int,vòng lặp này thực hiện tối đa 11 lần. Bạn có một số bằng chứng cho khẳng định của bạn?
Hầu tước Lorne

@EJP Từ quan điểm phần cứng, phân chia là một quá trình lặp lại. Thuật toán phân chia nhanh nhất mà tôi biết là radix4, tạo ra 4 bit mỗi lần lặp; do đó, một phân chia 32 bit cần ít nhất 8 lần lặp. Phép nhân, ví dụ, có thể được thực hiện song song, và cũng được chia thành các phép nhân đơn giản hơn; hoặc xuống mức bit (chỉ yêu cầu 5 thao tác) hoặc bị hỏng một phần cộng với bảng tra cứu ở cuối (Đánh đổi tốc độ VS kích thước cổ điển). Nó không chỉ là về "bao nhiêu lần lặp"; vấn đề với sự phân chia nằm ở "những gì mỗi lần lặp ngụ ý / làm, ở mức độ phần cứng"
XenoRo

2

Giải pháp của Marian, bây giờ với 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)));
    }

Bởi vì chúng ta có thể.


2
Điều đó hơi khó đọc. Có thể thêm một số khoảng trắng và / hoặc dòng mới.
michaelb958 - GoFundMonica

Nhưng chết tiệt là nó di động!
Trevor Rudolph

1

Tò mò, tôi đã cố gắng điểm chuẩn nó ...

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


    }
}

kết quả là:

Thời gian chạy 1: 6765
s: 400000000
Thời gian chạy 2: 6000
s: 400000000

Bây giờ tôi còn tự hỏi liệu điểm chuẩn của tôi có thực sự có ý nghĩa gì không nhưng tôi có nhận được kết quả nhất quán (các biến thể trong một ms) qua nhiều lần chạy chuẩn đó ... :) Có vẻ như thật vô ích khi thử và tối ưu hóa điều này ...


chỉnh sửa: theo nhận xét của ptomli, tôi đã thay thế 'số' bằng 'i' trong đoạn mã trên và nhận được kết quả sau hơn 5 lần chạy của băng ghế dự bị:

Thời gian chạy 1: 11500
s: 788888890
Thời gian chạy 2: 8547
s: 788888890

Thời gian chạy 1: 11485
s: 788888890
Thời gian chạy 2: 8547
s: 788888890

Thời gian chạy 1: 11469
s: 788888890
Thời gian chạy 2: 8547
s: 788888890

Thời gian chạy 1: 11500
s: 788888890
Thời gian chạy 2: 8547
s: 788888890

Thời gian chạy 1: 11484
s: 788888890
Thời gian chạy 2: 8547
s: 788888890

1
Chỉ để giải trí, sự khác biệt giữa phân phối giá trị số, từ 0 đến nghìn tỷ là gì? :)
ptomli

0

Điều gì về phương pháp đệ quy này?

    private static int length = 0;

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

0

giải pháp đơn giản:

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

Một giải pháp thực sự đơn giản:

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

Tôi sẽ không gọi một dòng cho vòng lặp với một cơ thể trống rỗng đơn giản. Cũng không modulo một sức mạnh 10 để xem bạn có nhận lại được điều tương tự không (bạn có thể sử dụng một phép so sánh không?).
Teepeemm

0

Hoặc thay vào đó, độ dài bạn có thể kiểm tra xem số lớn hơn hay nhỏ hơn số mong muốn.

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

}


Tôi không hiểu Có vẻ như bạn đang trả lời một câu hỏi khác.
Teepeemm

0

Tôi chưa thấy một giải pháp dựa trên nhân. Các giải pháp logarit, divison và dựa trên chuỗi sẽ trở nên khá khó sử dụng đối với hàng triệu trường hợp thử nghiệm, vì vậy đây là một cho 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;
}

Trong cơ sở 10, điều này hoạt động vì n về cơ bản được so sánh với 9, 99, 999 ... vì min là 9, 90, 900 ... và n đang bị trừ bởi 9, 90, 900 ...

Thật không may, điều này không khả dụng longchỉ bằng cách thay thế mọi trường hợp intdo tràn. Mặt khác, nó chỉ xảy ra như vậy, nó sẽ hoạt động cho các căn cứ 2 và 10 (nhưng thất bại nặng nề đối với hầu hết các căn cứ khác). Bạn sẽ cần một bảng tra cứu cho các điểm tràn (hoặc kiểm tra phân chia ... 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

Với thiết kế (dựa trên vấn đề). Đây là một sự thay thế của sự phân chia và chinh phục. Trước tiên chúng ta sẽ định nghĩa một enum (chỉ xem xét nó cho một số nguyên không dấu).

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

Bây giờ chúng ta sẽ định nghĩa một lớp đi qua các giá trị của enum và so sánh và trả về độ dài phù hợp.

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

Thời gian chạy của giải pháp này giống như phương pháp phân chia và chinh phục.


Một cuộc chia rẽ sẽ bắt đầu ở giữa và chia đôi khu vực tìm kiếm còn lại. Điều này có một thời gian chạy tuyến tính. Nhưng nó không quan trọng đối với chỉ 9 so sánh. Nhưng điều này sẽ không gây rối nếu num>=Nine.getValue()?
Teepeemm

0

Một người muốn làm điều này chủ yếu là vì anh ta / cô ta muốn "trình bày" nó, điều đó chủ yếu có nghĩa là cuối cùng nó cần phải là "toString-ed" (hoặc được chuyển đổi theo cách khác) một cách rõ ràng hoặc ngầm định; trước khi nó có thể được trình bày (ví dụ in).

Nếu đó là trường hợp thì chỉ cần cố gắng làm cho "toString" cần thiết rõ ràng và đếm các bit.


0

Chúng ta có thể đạt được điều này bằng cách sử dụng một vòng lặp đệ quy

    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

Tôi đã viết chức năng này sau khi tìm Integer.javamã nguồn.

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

Tôi thấy mọi người sử dụng các thư viện String hoặc thậm chí sử dụng lớp Integer. Không có gì sai với điều đó nhưng thuật toán để có được số chữ số không quá phức tạp. Tôi đang sử dụng một đoạn dài trong ví dụ này nhưng nó hoạt động tốt như với một int.

 private static int getLength(long num) {

    int count = 1;

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

    return count;
}

0

không API API, không dụng cụ, không chuyển đổi loại, chỉ lặp java thuần túy ->

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

Bạn có thể đi lâu cho các giá trị lớn hơn nếu bạn muốn.


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

Một giải pháp "chia cho 10" lần đầu tiên được Sinista đăng tải hai năm trước đó.
Teepeemm

-1

Cách đệ quy dễ dàng

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

không được kiểm tra


3
Bạn có thể nên kiểm tra nó sau đó (và đảm bảo rằng Java hợp lệ và được định dạng đúng). Nhưng một cách tiếp cận "chia cho 10" đệ quy đã được đăng bởi Jedi Dula 3 năm trước.
Teepeemm

-2

Bạn có thể các chữ số sử dụng phép chia liên tiếp cho mười:

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

Cách tiếp cận "chia cho 10" lần đầu tiên được đăng bởi Sinista 3 năm trước. Đó là lý do duy nhất tôi có thể nghĩ rằng bạn có một downvote.
Teepeemm

-2

Nhập số và tạo một Arraylist, và vòng lặp while sẽ ghi lại tất cả các chữ số vào Arraylist. Sau đó, chúng ta có thể lấy kích thước của mảng, sẽ là chiều dài của giá trị số nguyên bạn đã nhập.

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

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

int m=a.size();

1
Ngoại trừ việc bạn không cần ArrayList hoặc các chữ số.
Hầu tước Lorne

-2

Đây là một phương pháp thực sự đơn giản mà tôi đã thực hiện cho bất kỳ số nào:

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

Cách thức hoạt động của nó với biến đếm số là không gian 10 = 1 chữ số. Ví dụ .1 = 1 phần mười => không gian 1 chữ số. Do đó, nếu bạn có int number = 103342;6, vì đó tương đương với 0,000001 khoảng trống. Ngoài ra, có ai có tên biến tốt hơn chonumberCounter ? Tôi không thể nghĩ gì tốt hơn.

Chỉnh sửa: Chỉ cần nghĩ về một lời giải thích tốt hơn. Về cơ bản, điều mà vòng lặp này đang làm là làm cho nó chia số của bạn cho 10, cho đến khi nó nhỏ hơn một. Về cơ bản, khi bạn chia một cái gì đó cho 10 bạn sẽ di chuyển nó trở lại một không gian số, vì vậy bạn chỉ cần chia nó cho 10 cho đến khi bạn đạt <1 cho số lượng chữ số trong số của bạn.

Đây là một phiên bản khác có thể đếm số lượng số thập phân:

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

Hãy thử chuyển đổi int thành một chuỗi và sau đó lấy độ dài của chuỗi . Điều đó sẽ nhận được chiều dài của int .

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

Điều này hoàn toàn tương đương với mã gốc. Và sẽ bỏ lỡ khi numberlà tiêu cực.
Teepeemm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.