2010-03-24 5 views
19

W .NET jaki jest najlepszy sposób na znalezienie długości liczby całkowitej w postaci, jeśli był reprezentowany jako ciąg znaków?Znaleźć długość ciągu liczby całkowitej w .NET

np.

1 = 1 znak
10 = 2 znaki
99 = 2 znaków
100 = 3 znaków
1000 = 4 znaków

Oczywistą odpowiedzią jest konwersja int na ciąg i uzyskać jego długość, ale chcę uzyskać najlepszą możliwą wydajność bez konieczności tworzenia nowego łańcucha.

+9

Zawsze zrównoważyć bezpłatne mikrosekund próbujesz zyskać na czasie drogiej odczytu złej przyssawką (samodzielnie, chyba), który ma czytać i debuguj ten kod później. – reinierpost

+4

@reinierpost to nie mikro-optymalizacja, jeśli wspomniana metoda jest uruchamiana, jak miliard razy w pętli zwanej przez tysiące różnych wątków. –

+0

Duplikat tego? http://stackoverflow.com/questions/679602/fastest-way-to-calculate-the-decimal-length-of-an-integer-net –

Odpowiedz

36

można użyć logartihms obliczyć długość int:

public static int IntLength(int i) { 
    if (i <= 0) throw new ArgumentOutOfRangeException(); 

    return (int)Math.Floor(Math.Log10(i)) + 1; 
} 

testy przechodzi:

[Test] 
public void TestIntLength() { 
    Assert.AreEqual(1, IntLength(1)); 
    Assert.AreEqual(1, IntLength(9)); 
    Assert.AreEqual(2, IntLength(10)); 
    Assert.AreEqual(2, IntLength(99)); 
    Assert.AreEqual(3, IntLength(100)); 
    Assert.AreEqual(3, IntLength(999)); 
    Assert.AreEqual(4, IntLength(1000)); 
    Assert.AreEqual(10, IntLength(int.MaxValue)); 
} 

się Szybki test wykazał, że metoda logowania jest 4-krotnie szybsza niż metoda int.ToString(). Długość.

metoda pokazuje GVS poniżej (za pomocą If-deklaracje) jest kolejnym 6 razy szybciej niż metoda log (!):

public static int IntLengthIf(int i) { 
    if (i < 10) return 1; 
    if (i < 100) return 2; 
    if (i < 1000) return 3; 
    if (i < 10000) return 4; 
    if (i < 100000) return 5; 
    if (i < 1000000) return 6; 
    if (i < 10000000) return 7; 
    if (i < 100000000) return 8; 
    if (i < 1000000000) return 9; 
    throw new ArgumentOutOfRangeException(); 
} 

Oto dokładne czasy dla numerach od 1 do 10.000.000:

IntLengthToString: 4205ms 
IntLengthLog10: 1122ms 
IntLengthIf: 201ms 
+1

Aby poradzić sobie z liczbami ujemnymi, można uzyskać bezwzględną wartość i, a następnie dodać 1 do wyniku funkcji. –

+0

Jeśli masz już szybki test na to, powinieneś porównać go z rozwiązaniem GvS. To powinno być interesujące. –

+0

Mam zaktualizowaną moją odpowiedź. Metoda GvS jest znacznie szybsza. – stmax

3

Można użyć coś takiego:

 int integer = 100; 

     int charachtersCount = 0; 
     while (integer > 0) 
     { 
      integer = integer/10; 
      charachtersCount++; 
     } 

Ale czy naprawdę trzeba zoptymalizować to? Chciałbym rzeczywiście wolą używać znaków (wygląda o wiele lepiej):

integer.ToString().Length 
+0

Przyjemne rozwiązanie, ale jak powiedziałeś, wątpiłbym, że wydajność jest dobra. Domyślam się, że konwersja ciągów jest najlepsza. –

-1

Jeśli chcesz to zrobić przez matematyki można spróbować to:

int integer = 100 
int charCount = (int) Math.Ceiling(Math.Log10(integer+1)); 

wątpię, czy to jest bardzo dużo szybciej niż konwersja na ciąg chociaż

1

Jeśli potrzebujesz do czynienia z liczbami ujemnymi również można wziąć stmax solution z korkociągu:

public static int IntLength(int i) { 
    if (i == 0) return 1; // no log10(0) 
    int n = (i < 0) ? 2 : 1; 
    i = (i < 0) ? -i : i; 

    return (int)Math.Floor(Math.Log10(i)) + n; 
} 
12

Jeśli wejście jest w zakresie 0-10000

if (i < 10) return 1; 
if (i < 100) return 2; 
if (i < 1000) return 3; 
if (i < 10000) return 4; 
// etc 
+1

To jest najprostsze rozwiązanie i dobrze się czyta. Prawdopodobnie nie może konkurować ze zoptymalizowanym logarytmem zmiennoprzecinkowym. –

+2

Nie zamierzam robić tego testu, ale założę się, że to rozwiązanie jest szybsze od logarytmu. Logi wykonują kilka cykli zegara, aby obliczyć. –

+2

jest 6 razy szybszy niż moja metoda przy użyciu dzienników. – stmax

1

można zrobić:

int ndig = 1; 
if (n < 0){n = -n; ndig++;} 
if (n >= 100000000){n /= 100000000; ndig += 8;} 
if (n >=  10000){n /=  10000; ndig += 4;} 
if (n >=  100){n /=  100; ndig += 2;} 
if (n >=  10){n /=  10; ndig += 1;} 

lub coś podobnego. Wymaga 4 porównań i 0-4 podziałów.

(64 bitów trzeba dodać piąty poziom.)

+0

Ten dostaje sprytne punkty. Jest nieco wolniejszy od prostego, ale lubię go. – JeffC