2010-11-10 17 views
5

zasadzie chcę wrócić liczbę cyfr w int -> wartości tak:znaleźć „ciąg” o długości int

(int)1 => 1 
(int)123 => 3 
(int)12345678 => 8 

ja wiem nic o C, więc proszę nosić ze mną. Znam cel c, ale używam ints i floats zamiast NSNumbers. Zdaję sobie sprawę, że mógłbym zamienić ints w obiektywne obiekty c, ale wydaje mi się, że jest to faffy i jeśli mogę to zrobić za pomocą C, będę wiedział o tym na przyszłość.

Dzięki

Odpowiedz

22

użycie

int d = (value == 0 ? 1 : (int)(log10(value)+1)); 

Zauważ, że ta praca nie robi dla liczb ujemnych, będziesz musiał użyć

int d = (value == 0 ? 1 : ((int)(log10(fabs(value))+1) + (value < 0 ? 1 : 0))); 

który a dds 1 dla znaku minus, jeśli value jest ujemny.

+0

dziękuję martin. +1 za udzielanie mi liczb 0 i minus. :) –

+0

+1 dla tego samego – DVK

+2

(wartość <0? 1: 0) jest równoważna tylko (wartość <0) – Vovanium

5

Stosować logarytmy baza 10:

int length = (int)floor(log10((float)number)) + 1; // works for >0 
+0

wielkie dzięki. :) –

1

Bardziej ogólne rozwiązanie, zwłaszcza jeśli chcesz znać długość dla celów drukowania printf() wariantów jest:

snprintf(NULL, 0, "%d", myint); 

Zwracana wartość powinna powiedzieć długość łańcucha, który ma zostać wydrukowany.

+0

@pst: Dlaczego odciąłeś część '\ 0'? – aib

+0

NUL nie jest zawarty w długości łańcucha, ponieważ jest łańcuchem C. (Użyto tylko frazy). –

10

prawdopodobnie znacznie szybciej niż przy użyciu dziennik lub int na ciąg znaków konwersji i bez użycia jakichkolwiek funkcji bibliotecznych jest taka:

int nDigits(int i) 
{ 
    if (i < 0) i = -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; 
    return 10; 
} 

EDIT po Jeff Yates obaw:

Dla tych, którzy martwią Int różne rozmiary od 32 bitów (podobne do rozwiązania pmg, ale jeszcze szybciej, ponieważ zwielokrotnienie jest większa niż podział :-)

#include <limits.h> 

#define PO10_LIMIT (INT_MAX/10) 


int nDigits(int i) 
{ 
    int n,po10; 

    if (i < 0) i = -i; 
    n=1; 
    po10=10; 
    while(i>=po10) 
    { 
    n++; 
    if (po10 > PO10_LIMIT) break; 
    po10*=10; 
    } 
    return n; 
} 
+1

+1 dla najszybszego algorytmu – pmg

+0

Jest to dobre tylko wtedy, gdy 'int' jest wartością 32-bitową. Ponieważ rozmiar 'int' jest zależny od platformy w C i C++, nie będę się na tym opierał. –

+0

@Jeff Yates: Wiem! Jeśli to naprawdę jest problem, po prostu dodaj/usuń niektóre instrukcje. A jeśli naprawdę potrzebujesz rozwiązania działającego na różnych platformach, możesz pracować z #if testowaniem dla rozmiaru konkretnego typu int lub użyj rozwiązania PMG (które wciąż może być zoptymalizowane). – Curd

4

Oto kolejna opcja

int nDigits(unsigned i) { 
    int n = 1; 
    while (i > 9) { 
     n++; 
     i /= 10; 
    } 
    return n; 
} 

To szybciej niż przy użyciu log10, ale wolniej niż opcja twaróg jest z testami kaskadowy. Jednak nie ponosi int s są 32 bity :-)

1

Jeśli wartość całkowita (np 12345678u) jest stałą czasu kompilacji, można pozwolić kompilator określenia długości dla Ciebie:

template<typename T> 
constexpr unsigned int_decimal_digits(T value) 
{ 
    return ( value/10 
        ? int_decimal_digits<T>(value/10) + 1 
        : 1); 
} 

Zastosowanie:

unsigned n = int_decimal_digits(1234); 
// n = 4 

#include <limits.h> 
unsigned m = int_decimal_digits(ULLONG_MAX); 
// m = maximum length of a "long long unsigned" on your platform 

ten sposób kompilator będzie obliczyć liczbę miejsc po przecinku automatycznie i wypełnić wartości jako stałą. Powinno to być najszybsze z możliwych rozwiązań, ponieważ nie ma potrzeby wykonywania obliczeń w czasie wykonywania, a stałe całkowite są zwykle umieszczane w opcodes instrukcji. (Oznacza to, że podróżują one przez potok instrukcji, a nie przez pamięć danych/pamięć podręczną). Wymaga to jednak kompilatora obsługującego C++ 11.

Powiązane problemy