Нахождение длины целого числа в C - PullRequest
54 голосов
/ 18 июня 2010

Хотелось бы узнать, как найти длину целого числа в C.

Например:

  • 1 => 1
  • 25 => 2
  • 12512 => 5
  • 0 => 1

и т. Д.

Как это сделать в C?

Ответы [ 23 ]

94 голосов
/ 18 июня 2010

C:

Почему бы просто не взять в логе-10 абсолютное значение числа, округлить его и добавить?Это работает для положительных и отрицательных чисел, которые не равны 0, и избегает необходимости использовать какие-либо функции преобразования строк.

Функции log10, abs и floor предоставляются math.h.Например:

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

Вы должны заключить это в предложение, гарантируя, что the_integer != 0, так как log10(0) возвращает -HUGE_VAL в соответствии с man 3 log.

Кроме того, вы можете захотетьдобавить единицу к окончательному результату, если ввод отрицательный, если вас интересует длина числа, включая его отрицательный знак.

Java:

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

NB Природа вычислений с плавающей запятой, используемых в этом методе, может привести к тому, что он будет медленнее, чем более прямой подход.См. Комментарии к ответу Кангкана для обсуждения эффективности.

44 голосов
/ 18 июня 2010

Если вас интересует быстрое и очень простое решение, следующее может быть самым быстрым (это зависит от распределения вероятностей рассматриваемых чисел):

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

int printLen(int x) {
    return x < 0 ? lenHelper(-x) + 1 : lenHelper(x);
}

Хотя он может и не выиграть призы за самое гениальное решение, его тривиально понять, а также тривиально выполнить - значит, это быстро.

На Q6600 с использованием MSC я сравнил это с помощью следующего цикла:

int res = 0;
for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);

Это решение занимает 0,062 с, второе по быстродействию решение Пита Киркхэма, использующего умный логарифмический подход, занимает 0,115 с - почти вдвое дольше. Однако для чисел около 10000 и ниже смарт-журнал работает быстрее.

За счет некоторой ясности вы можете более надежно превзойти Smart-Log (по крайней мере, на Q6600):

int lenHelper(unsigned x) { 
    // this is either a fun exercise in optimization 
    // or it's extremely premature optimization.
    if(x >= 100000) {
        if(x >= 10000000) {
            if(x >= 1000000000) return 10;
            if(x >= 100000000) return 9;
            return 8;
        }
        if(x >= 1000000) return 7;
        return 6;
    } else {
        if(x >= 1000) {
            if(x >= 10000) return 5;
            return 4;
        } else {
            if(x >= 100) return 3;
            if(x >= 10) return 2;
            return 1;
        }
    }
}

Это решение по-прежнему составляет 0,062 с для больших чисел и уменьшается до 0,09 с для меньших чисел - в обоих случаях быстрее, чем подход с использованием «умного журнала». (gcc создает более быстрый код; 0,052 для этого решения и 0,09 с для интеллектуального журнала).

24 голосов
/ 18 июня 2010
int get_int_len (int value){
  int l=1;
  while(value>9){ l++; value/=10; }
  return l;
}

и второй будет работать и для отрицательных чисел:

int get_int_len_with_negative_too (int value){
  int l=!value;
  while(value){ l++; value/=10; }
  return l;
}
18 голосов
/ 18 июня 2010

Вы можете написать такую ​​функцию:

unsigned numDigits(const unsigned n) {
    if (n < 10) return 1;
    return 1 + numDigits(n / 10);
}
10 голосов
/ 18 июня 2010

длина n:

length =  ( i==0 ) ? 1 : (int)log10(n)+1;
7 голосов
/ 18 июня 2010

Количество цифр целого числа x равно 1 + log10(x). Так что вы можете сделать это:

#include <math.h>
#include <stdio.h>

int main()
{
    int x;
    scanf("%d", &x);
    printf("x has %d digits\n", 1 + (int)log10(x));
}

Или вы можете запустить цикл для подсчета цифр самостоятельно: делайте целочисленное деление на 10, пока число не станет 0:

int numDigits = 0;
do
{
    ++numDigits;
    x = x / 10;
} while ( x );

Вы должны быть немного осторожны, чтобы вернуть 1, если целое число равно 0 в первом решении, и вам также может потребоваться обработать отрицательные целые числа (работайте с -x, если x < 0).

7 голосов
/ 18 июня 2010

Да, используя sprintf.

int num;
scanf("%d",&num);
char testing[100];
sprintf(testing,"%d",num);
int length = strlen(testing);

Кроме того, вы можете сделать это математически, используя функцию log10.

int num;
scanf("%d",&num);
int length;
if (num == 0) {
  length = 1;
} else {    
  length = log10(fabs(num)) + 1;
  if (num < 0) length++;
}
6 голосов
/ 18 июня 2010

Наиболее эффективным способом может быть использование метода быстрого логарифмирования, аналогичного используемому для определения старшего бита, установленного в целом числе.

size_t printed_length ( int32_t x )
{
    size_t count = x < 0 ? 2 : 1;

    if ( x < 0 ) x = -x;

    if ( x >= 100000000 ) {
        count += 8;
        x /= 100000000;
    }

    if ( x >= 10000 ) {
        count += 4;
        x /= 10000;
    }

    if ( x >= 100 ) {
        count += 2;
        x /= 100;
    }

    if ( x >= 10 )
        ++count;

    return count;
}

Эта (возможно, преждевременная) оптимизация занимает 0,65 с для 20 миллионов вызовов на моем нетбуке; итеративное деление, такое как у zed_0xff, занимает 1,6 с, рекурсивное деление, такое как Кангкан, занимает 1,8 с, а использование функций с плавающей запятой (код Джордана Льюиса) - колоссальные 6,6 с. Использование snprintf занимает 11,5 с, но даст вам размер, необходимый snprintf для любого формата, а не только для целых чисел. Джордан сообщает, что на его процессоре не поддерживается порядок времени, что делает число с плавающей запятой быстрее, чем у меня.

Возможно, проще всего спросить у snprintf длину печати:

#include <stdio.h>

size_t printed_length ( int x )
{
    return snprintf ( NULL, 0, "%d", x );
}

int main ()
{
    int x[] = { 1, 25, 12512, 0, -15 };

    for ( int i = 0; i < sizeof ( x ) / sizeof ( x[0] ); ++i )
        printf ( "%d -> %d\n", x[i], printed_length ( x[i] ) );

    return 0;
}
5 голосов
/ 09 апреля 2011

Правильная snprintf реализация:

int count = snprintf(NULL, 0, "%i", x);
4 голосов
/ 14 февраля 2015
int digits=1;

while (x>=10){
    x/=10;
    digits++;
}
return digits;
...