Ефективний спосіб визначення кількості цифр у цілому


144

Що є дуже ефективним способом визначення кількості цифр у цілому цілі в C ++?


11
В якій базі? 2? 10?
Джейкоб Кралл

2
Я хотів би зробити це в базі 10
Сет,

1
Одного разу я задав відповідне запитання: як можна отримати першу цифру в int? Багато тих же методологій, що наведені нижче, використовувались у відповідях людей. Ось посилання на випадок, якщо це стосується вашого завдання [ stackoverflow.com/questions/701322/]
Діна,

Чи кваліфікована вбудована збірка?
Дьорджі Андрасек

1
Хоча всі ці відповіді стосуються бази 10, змінити обчислити результат для будь-якої бажаної бази досить просто.
Іра Бакстер

Відповіді:


106

Ну, найефективнішим способом, припускаючи, що ви знаєте розмір цілого числа, буде пошук. Має бути швидшим, ніж значно коротший підхід на основі логарифму. Якщо ви не переймаєтесь підрахунком "-", видаліть +1.

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

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

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}

5
Напевно, швидше, ніж моя відповідь, молодець. Для додаткової ефективності, якщо ви знаєте, що ваші вхідні цифри будуть здебільшого невеликими (я здогадуюсь менше 100 000), перевірте тести: якщо (x <10) повернути 1; якщо (x <100) повернути 2; і т. д., щоб функція зробила менше тестів і швидше виходила.
скрип

29
Або, можливо, упорядкуйте та вкладіть оператори if, щоб зробити двійковий пошук замість лінійного пошуку.
dave4420

1
Це не дуже гарна ідея. Що відбувається, коли архітектура розширюється до 256 бітових цілих чисел. Вам потрібно пам’ятати, щоб повернутися та змінити цей код. У реальному житті цього не відбудеться, і це, мабуть, буде використано для створення буфера правильного розміру, який ви зараз відкриваєте перед усіма видами буфера через проблеми запуску на великих архітекторах.
Мартін Йорк

3
припускаючи рівномірний розподіл чисел, зворотний лінійний пошук (починаючи з максимальних цифр до 1) може бути в середньому швидшим, ніж двійковий пошук, оскільки число з N цифрами набагато більше, ніж з цифр N-1 graphics.stanford.edu/~ морський транспорт /…
фа.

6
Я б не переживав дуже сильно про 256 або 128 бітові цілі числа. Якщо вам не потрібно буде порахувати кількість електронів у Всесвіті (10 ^ 78 востаннє я це зробив), 64 біт буде добре. 32-бітні машини тривали ~~ 15 років. Я б здогадався, що 64-бітні машини прослужать набагато довше. Для більшої кількості, багатоточна арифметика буде добре, і я сумніваюся, чи буде ефективність обчислення цифр підрахунок.
Іра Бакстер

74

Найпростіший спосіб - це зробити:

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}

log10 визначено в <cmath>або <math.h>. Вам потрібно буде профайлювати це, щоб побачити, чи швидше він, ніж будь-який з інших, розміщених тут. Я не впевнений, наскільки це надійно щодо точності плаваючої точки. Також аргумент не підписаний, оскільки негативні значення і журнал насправді не змішуються.


7
Для 32-бітових ints та 56-бітових плавців це, ймовірно, працює. Якщо вхід довгий (64 біт), то 56 біт журналу подвійної точності можуть призвести до того, що це дасть неправильну відповідь у випадках значень, близьких до великих значень 10 ^ n. Очікуйте неприємностей вище 2 ^ 50.
Іра Бакстер

1
Існує також питання, наскільки точні функції журналу. Я не перевіряв, наскільки вони точні в сучасних бібліотеках, і не було б зручно сліпо довіряти їм, щоб вони були добрими до однієї частини в мільярд.
Девід Торнлі

@DavidThornley: журнал або інші математичні функції ідеально точні, якщо не вказано в командному рядку компілятора. деякі з них будуть перетворені на x86 властивості під час компіляції. деякі не існують, і вони розширяться у формули існуючих суті. Наприклад, якщо при використанні -fpfastви могли побачити використання SSE-інструментів, а не x87, що дає меншу гарантію на точність IIRC. але за замовчуванням немає проблем.
v.oddou

@DavidThornley: Це більш ніж точність. Питання полягає в тому, гарантується чи ні, що log10 (10 ^ k) ≥ k для всіх відповідних k. Тобто це гарантовано, що будь-яка неминуча помилка округлення йде в правильному напрямку. k + eps в результаті працює, k - eps - не. І «Ідеально точно» - це наївно.
gnasher729

1
Тест i> 0 можна оптимізувати до i> 9
Пат

60

Можливо, я неправильно зрозумів питання, але це не робить?

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

29
І я не здивуюсь, якщо це рішення буде найшвидшим.
VisioN

32
int digits = 0; while (number != 0) { number /= 10; digits++; }

Примітка: "0" матиме 0 цифр! Якщо вам потрібно 0, щоб мати 1 цифру, скористайтеся:

int digits = 0; do { number /= 10; digits++; } while (number != 0);

(Спасибі Кевін Феган)

Зрештою, скористайтеся профілером, щоб знати, який з усіх відповідей тут буде швидшим на вашій машині ...


3
Це може бути, а може і не бути швидшим, ніж я взяв підхід до розкрученого циклу - вам потрібно буде проаналізувати різницю (вона має бути незначною у довгостроковій перспективі).
Віталій

Домовились, профілювання - єдиний спосіб справді знати напевно! Я оновив свою відповідь цим коментарем, оскільки відповідь ceil (log10 ()) Бена S зник.
скрип

11

Розіграші: Це найефективніший спосіб (кількість цифр обчислюються під час компіляції):

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};

Може бути корисним для визначення ширини, необхідної для поля цифр у форматуванні, введення елементів тощо.


4
По-перше, ваше рішення не працює для 0. По-друге, ваше рішення не застосовується до загального випадку змінної. По-третє, якщо ви використовуєте постійний літерал, ви вже знаєте, скільки цифр у нього є.
Віталій

Він працює і для 0. Він також працює для будь-якої бази. Решта - це дійсні моменти, які я вже окреслив.
blinnov.com

3
Я не думаю, що це насправді. Він не працює, 0а також виходить з ладу на базі 1:) і дає поділ на нульові помилки, якщо базі задано як 0. Це все-таки можна виправити. У будь-якому разі я задираюсь над дуже давньою публікацією, так що вибачте, я просто думаю, що це не повинно бути жартом і насправді може бути корисним.
Тім

9

Дивіться Bit Twiddling Hacks для набагато коротшої версії відповіді, яку ви прийняли. Це також має перевагу швидше знайти відповідь, якщо ваш вклад зазвичай розподілений, попередньо перевіривши великі константи. (v >= 1000000000)ловить 76% значень, тому перевірка того, що перший буде в середньому швидше.


Незрозуміло, чи справді біт-подвійність швидше. Навіть у гіршому випадку мій модифікований підхід вимагає 4 порівнянь (можливо, я міг би його знизити до 3, якщо я вивчив би поділ далі, хоча це виглядає малоймовірним). Я серйозно сумніваюся, що це буде побито арифметичними операціями + навантаженнями пам'яті (хоча якщо достатньо доступу, вони зникають у кеш-процесорі). Пам’ятайте, у прикладі, який вони дають, вони також приховують базу журналів 2 як деяку абстрактну функцію IntegerLogBase2 (що саме по собі насправді не дешево).
Віталій

Так само, як і в подальшому, так, якщо номери звичайно розподіляються, перевірка порядку є швидшою. Однак, у найгіршому випадку цей випадок є удвічі повільнішим. Підхід з розподілом за кількістю цифр замість місця введення означає, що поведінка не має виродженого випадку і завжди працює оптимально. Крім того, пам’ятайте, що ви робите припущення, що числа будуть розподілені рівномірно. Насправді вони, швидше за все, дотримуватимуться певного розповсюдження, пов’язаного з <a href=" en.wikipedia.org/wiki/…>, я б здогадався.
Віталій,

Зловживання бітових подвійних процесів не швидше, ніж метод розділів вище, але вони можуть бути цікавими, якщо у вас був більш загальний випадок, як float тут.
Корвін Радість

1
Трохи подвійні хакі пропонують спосіб отримати int log10, враховуючи int log2. Він пропонує декілька способів отримати int log2, в основному залучаючи кілька порівнянь / гілок. (Я думаю, ви недооцінюєте вартість непередбачуваних гілок, Віталі). Якщо ви можете використовувати вбудований x86 asm, інструкція BSR надасть вам int log2 значення (тобто бітовий індекс найбільш значущого набору бітів). Це трохи повільно на K8 (10 циклів затримки), але швидко на Core 2 (2 або 3 циклу затримки). Навіть на K8, цілком може бути швидшим порівняння.
Пітер Кордес

У K10 lzcnt рахує провідні нулі, тому це майже те саме, що bsr, але вхід 0 більше не є особливим випадком із невизначеними результатами. Затримки: BSR: 4, LZCNT: 2.
Пітер Кордес

8

перетворити в рядок, а потім використовувати вбудовані функції

unsigned int i;
cout<< to_string(i).length()<<endl;

7
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;

3
Хоча це ефективно з точки зору LOC, як зазначається в прийнятій відповіді, використання журналу, ймовірно, не дасть найкращих показників.
Іван

@Ian Чому ні? Це лише пара інструкцій ФПУ. Милі краще за всі гілки та петлі в інших відповідях.
Маркіз Лорн

5

Попередній плакат пропонував цикл, який ділиться на 10. Оскільки множення на сучасних машинах відбувається набагато швидше, я б рекомендував наступний код:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }

1
чорт у деталях - що трапиться з скажімо std :: numeric_limits <int> :: max == число - може виникнути проблеми із закінченням
pgast

2
Якщо ви турбуєтесь про цей випадок, ви можете додати ще один ІФ для обробки дуже великих значень.
Іра Бакстер,

2
Я повинен зауважити, що на машинах x86 множник на постійну 10, як це використовується в цьому випадку, може реально реалізувати компілятор як LEA R2, [8 * R1 + R1], ADD R1, R2, так що це займає 2 тактових максимум. Множення на змінні займає десятки годин, а ділення набагато гірше.
Іра Бакстер

Перевага підходу до поділу полягає в тому, що вам не потрібно турбуватися про негативні числа.
Йоханнес Шауб - ліб

1
Я порівняв підхід до мультиплікації (за допомогою файлів для усунення випуску знаків) проти підходу до поділу. На моїй машині підхід до поділу є фактором 2 повільнішим, ніж підхід множення. Чи це передчасна оптимізація чи ні, насправді залежить від того, де і як це називається.
Spacemoose

5

У архітектурі ppc є невелика інструкція підрахунку. З цим ви можете визначити базу журналу 2 додатного цілого числа в одній інструкції. Наприклад, 32 біт буде:

#define log_2_32_ppc(x) (31-__cntlzw(x))

Якщо ви можете впоратися з невеликим похибкою у великих значеннях, ви можете перетворити це в базу даних 10 з допомогою кількох інших інструкцій:

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))

Це конкретна платформа і трохи неточна, але також не передбачає гілок, поділу або перетворення на плаваючу точку. Все залежить від того, що вам потрібно.

Мені відомі лише інструкції з ppc, але інші архітектури повинні мати подібні інструкції.


Це рішення обчислює log2 (15) = 4 біти і log2 (9) = 4 біти. Але для друку 15 та 9 потрібні різні числа десяткових цифр. Так що це не працює, якщо ви не заперечуєте над тим, щоб друкувати свої цифри із занадто великою кількістю цифр. Але в цьому випадку ви завжди можете вибрати "10" як відповідь для int.
Іра Бакстер

Нічого собі, приблизна функція. Приємно.
doug65536

4
 #include <iostream>
 #include <math.h>

 using namespace std;

 int main()
 {
     double num;
     int result;
     cout<<"Enter a number to find the number of digits,  not including decimal places: ";
     cin>>num;
     result = ((num<=1)? 1 : log10(num)+1);
     cout<<"Number of digits "<<result<<endl;
     return 0;
 }

Це, мабуть, найпростіший спосіб вирішення вашої проблеми, якщо ви припускаєте, що ви дбаєте лише про цифри перед десятковою, і якщо припустити, що все менше, ніж 10, це лише одна цифра.


1

Мені подобається відповідь Іри Бакстер. Ось варіант шаблону, який обробляє різні розміри і має справу з максимальними цілими значеннями (оновлено для підняття верхньої межі виходу з циклу):

#include <boost/integer_traits.hpp>

template<typename T> T max_decimal()
{
    T t = 1;

    for (unsigned i = boost::integer_traits<T>::digits10; i; --i)
        t *= 10;

    return t;
}

template<typename T>
unsigned digits(T v)
{
    if (v < 0) v = -v;

    if (max_decimal<T>() <= v)
        return boost::integer_traits<T>::digits10 + 1;

    unsigned digits = 1;
    T boundary = 10;

    while (boundary <= v) {
        boundary *= 10;
        ++digits;
    }

    return digits;
}

Щоб реально досягти покращеної продуктивності від зняття додаткового тесту з циклу, вам потрібно спеціалізуватися max_decimal (), щоб повернути константи для кожного типу на вашій платформі. Досить магічний компілятор може оптимізувати виклик max_decimal () до постійної, але спеціалізація краща для більшості компіляторів сьогодні. На жаль, ця версія, ймовірно, повільніше, оскільки max_decimal коштує дорожче, ніж тести, вилучені з циклу.

Я залишу все це як вправу для читача.


Ви хочете зробити спочатку верхню межу перевірити окремий умовний тест, щоб не перевіряти його на кожній ітерації циклу.
Іра Бакстер

Ви не хочете вводити 10 у цю темп. Компілятор може вважати множення на t множенням на реальну змінну та використовувати загальну інструкцію множення. Якщо ви замість цього написали "результат * = 10;" компілятор, безумовно, помітить множення на постійні 10 і здійснить це з декількома зрушеннями та додаваннями, що надзвичайно швидко.
Іра Бакстер

Якщо множення на t завжди було множенням на 10, то так, компілятор міг би зменшити силу. Однак в цьому випадку t не є інваріантним циклом (це лише модифікація цілої функції потужності, яку я лежав навколо). Правильна оптимізація - це спеціалізація на типі, що повертає константу. Однак ви праві, що в цьому випадку функція завжди піднімає 10 до потужності, а не довільне ціле число до потужності, а зниження сили дає хороший виграш. Тож я змінив ... На цей раз подальші зміни справді залишаються як вправа! (Переповнення стека є великий час раковина ...)
janm

1
#include <stdint.h> // uint32_t [available since C99]

/// Determine the number of digits for a 32 bit integer.
/// - Uses at most 4 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27669966
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c
         ---+---   ---+---
         10 | 4     5 | 4
          9 | 4     4 | 4
          8 | 3     3 | 3
          7 | 3     2 | 3
          6 | 3     1 | 3
     \endcode
*/
unsigned NumDigits32bs(uint32_t x) {
    return // Num-># Digits->[0-9] 32->bits bs->Binary Search
    ( x >= 100000u // [6-10] [1-5]
    ?   // [6-10]
        ( x >= 10000000u // [8-10] [6-7]
        ?   // [8-10]
            ( x >= 100000000u // [9-10] [8]
            ? // [9-10]
                ( x >=  1000000000u // [10] [9]
                ?   10
                :    9
                )
            : 8
            )
        :   // [6-7]
            ( x >=  1000000u // [7] [6]
            ?   7
            :   6
            )
        )
    :   // [1-5]
        ( x >= 100u // [3-5] [1-2]
        ?   // [3-5]
            ( x >= 1000u // [4-5] [3]
            ? // [4-5]
                ( x >=  10000u // [5] [4]
                ?   5
                :   4
                )
            : 3
            )
        :   // [1-2]
            ( x >=  10u // [2] [1]
            ?   2
            :   1
            )
        )
    );
}

0

Ще один фрагмент коду, в основному такий же, як у Віталія, але використовує двійковий пошук. Масив повноважень ліниво ініціалізується один раз за непідписаний екземпляр типу. Перевантаження типу підписаного типу забезпечує піктограму мінус.

#include <limits>
#include <type_traits>
#include <array>

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_unsigned<T>::value>::type* = 0 )
{
    typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;
    static array_type powers_of_10;
    if ( powers_of_10.front() == 0 )
    {
        T n = 1;
        for ( T& i: powers_of_10 )
        {
            i = n;
            n *= 10;
        }
    }

    size_t l = 0, r = powers_of_10.size(), p;
    while ( l+1 < r )
    {
        p = (l+r)/2;
        if ( powers_of_10[p] <= v )
            l = p;
        else
            r = p;
    }
    return l + 1;
};

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
    typedef typename std::make_unsigned<T>::type unsigned_type;
    if ( v < 0 )
        return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
    else
        return NumberOfDecPositions ( static_cast<unsigned_type>(v) );
}

Якщо хтось піклується про подальшу оптимізацію, зауважте, що перший елемент масиву повноважень ніколи не використовується, і він lз’являється у +12 рази.


0

у випадку, якщо потрібна кількість цифр ТА значення кожної цифри, використовуйте це:

int64_t = number, digitValue, digits = 0;    // or "int" for 32bit

while (number != 0) {
    digitValue = number % 10;
    digits ++;
    number /= 10;
}

digitдає вам значення у розміщенні номера, яке зараз обробляється в циклі. наприклад для числа 1776 значення цифри дорівнює:
6 в 1-й петлі
7, у 2-й циклі
7 в 3-й петлі
1 в 4-й петлі


0
// Meta-program to calculate number of digits in (unsigned) 'N'.    
template <unsigned long long N, unsigned base=10>
struct numberlength
{   // http://stackoverflow.com/questions/1489830/
    enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};

template <unsigned base>
struct numberlength<0, base>
{
    enum { value = 1 };
};

{
    assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );

assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );

Виправлення на "Практичний жарт" з 'blinnov.com' вище
Адольфо

0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c     #d | #c   #d | #c
         ---+---   ---+---     ---+---   ---+---
         20 | 5    15 | 5      10 | 5     5 | 5
         19 | 5    14 | 5       9 | 5     4 | 5
         18 | 4    13 | 4       8 | 4     3 | 4
         17 | 4    12 | 4       7 | 4     2 | 4
         16 | 4    11 | 4       6 | 4     1 | 4
     \endcode
*/
unsigned NumDigits64bs(uint64_t x) {
    return // Num-># Digits->[0-9] 64->bits bs->Binary Search
    ( x >= 10000000000ul // [11-20] [1-10]
    ?
        ( x >= 1000000000000000ul // [16-20] [11-15]
        ?   // [16-20]
            ( x >= 100000000000000000ul // [18-20] [16-17]
            ?   // [18-20]
                ( x >= 1000000000000000000ul // [19-20] [18]
                ? // [19-20]
                    ( x >=  10000000000000000000ul // [20] [19]
                    ?   20
                    :   19
                    )
                : 18
                )
            :   // [16-17]
                ( x >=  10000000000000000ul // [17] [16]
                ?   17
                :   16
                )
            )
        :   // [11-15]
            ( x >= 1000000000000ul // [13-15] [11-12]
            ?   // [13-15]
                ( x >= 10000000000000ul // [14-15] [13]
                ? // [14-15]
                    ( x >=  100000000000000ul // [15] [14]
                    ?   15
                    :   14
                    )
                : 13
                )
            :   // [11-12]
                ( x >=  100000000000ul // [12] [11]
                ?   12
                :   11
                )
            )
        )
    :   // [1-10]
        ( x >= 100000ul // [6-10] [1-5]
        ?   // [6-10]
            ( x >= 10000000ul // [8-10] [6-7]
            ?   // [8-10]
                ( x >= 100000000ul // [9-10] [8]
                ? // [9-10]
                    ( x >=  1000000000ul // [10] [9]
                    ?   10
                    :    9
                    )
                : 8
                )
            :   // [6-7]
                ( x >=  1000000ul // [7] [6]
                ?   7
                :   6
                )
            )
        :   // [1-5]
            ( x >= 100ul // [3-5] [1-2]
            ?   // [3-5]
                ( x >= 1000ul // [4-5] [3]
                ? // [4-5]
                    ( x >=  10000ul // [5] [4]
                    ?   5
                    :   4
                    )
                : 3
                )
            :   // [1-2]
                ( x >=  10ul // [2] [1]
                ?   2
                :   1
                )
            )
        )
    );
}

0

для цілого числа "X" ви хочете знати кількість цифр, добре, не використовуючи циклу, це рішення діє в одній формулі лише в одному рядку, тому це найоптимальніше рішення, яке я коли-небудь бачив у цій проблемі.

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 

Помилка для INT_MAX, а також для негативних чисел.
ranu

@ranu Не вдалося INT_MAX як? Коли аргумент перетворений на double? Або ви посилаєтесь на якийсь неможливий цілий вхід із десятковими цифрами INT_MAX? Що також не могло б пропустити будь-яку іншу відповідь тут?
Маркіз Лорн

0
int numberOfDigits(int n){

    if(n<=9){
        return 1;
    }
    return 1 + numberOfDigits(n/10);
}

Це те, що я б робив, якщо ви хочете, щоб це було базовим 10. Це досить швидко, і ви, звичайно, не отримаєте стек-оверлок, купіть підрахунок цілих чисел


0
int num,dig_quant = 0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;
for(int i = 1; i<=num; i*=10){
    if(num / i  > 0){
      dig_quant += 1;
    }
}
 cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
 cout<<"\n\nGoodbye...\n\n";

0

Якщо швидше є більш ефективним, це поліпшення вдосконалення Андреа Олександреску . Його версія була вже швидшою, ніж наївний шлях (ділившись на 10 на кожну цифру). Наведена нижче версія - це постійний час і швидше, щонайменше, на x86-64 та ARM для будь-яких розмірів, але займає вдвічі більше бінарного коду, тому вона не така зручна для кешу.

Орієнтири для цієї версії проти версії александреску на моєму піарі у Facebook нерозумно .

Працює над unsigned, ні signed.

inline uint32_t digits10(uint64_t v) {
  return  1
        + (std::uint32_t)(v>=10)
        + (std::uint32_t)(v>=100)
        + (std::uint32_t)(v>=1000)
        + (std::uint32_t)(v>=10000)
        + (std::uint32_t)(v>=100000)
        + (std::uint32_t)(v>=1000000)
        + (std::uint32_t)(v>=10000000)
        + (std::uint32_t)(v>=100000000)
        + (std::uint32_t)(v>=1000000000)
        + (std::uint32_t)(v>=10000000000ull)
        + (std::uint32_t)(v>=100000000000ull)
        + (std::uint32_t)(v>=1000000000000ull)
        + (std::uint32_t)(v>=10000000000000ull)
        + (std::uint32_t)(v>=100000000000000ull)
        + (std::uint32_t)(v>=1000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000ull)
        + (std::uint32_t)(v>=100000000000000000ull)
        + (std::uint32_t)(v>=1000000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000000ull);
}

0

Я працював над програмою, яка вимагала від мене перевірити, чи правильно користувач відповів, скільки цифр було в кількості, тому мені довелося розробити спосіб перевірити кількість цифр у цілому. Це в кінцевому підсумку було порівняно простою для вирішення.

double check=0, exponent=1000;

while(check<=1)
{
    check=number/pow(10, exponent);
    exponent--;
}

exponent=exponent+2;
cout<<exponent<<endl;

Це було моєю відповіддю, яка в даний час працює з числами менше 10 ^ 1000 цифр (можна змінити, змінивши значення показника).

PS Я знаю, що ця відповідь запізнюється на десять років, але я потрапив сюди на 2020 рік, щоб інші люди могли її використовувати.


-1
template <typename type>
class number_of_decimal_digits {   
    const powers_and_max<type> mPowersAndMax;
public:
    number_of_decimal_digits(){
    }   
    inline size_t ndigits( type i) const {
        if(i<0){
             i += (i == std::numeric_limits<type>::min());
             i=-i;
        }
        const type* begin = &*mPowersAndMax.begin();
        const type* end = begin+mPowersAndMax.size();
        return 1 + std::lower_bound(begin,end,i) - begin;
    }
    inline size_t string_ndigits(const type& i) const {
        return (i<0) + ndigits(i);
    }
    inline size_t operator[](const type& i) const {
       return string_ndigits(i);
    }
};

де в powers_and_maxнас є (10^n)-1для всіх nтаке, що

(10^n) < std::numeric_limits<type>::max()

і std::numeric_limits<type>::max()в масиві:

template <typename type>
struct powers_and_max : protected std::vector<type>{
    typedef std::vector<type> super;
    using super::const_iterator;
    using super::size;
    type& operator[](size_t i)const{return super::operator[](i)};
    const_iterator begin()const {return super::begin();} 
    const_iterator end()const {return super::end();} 
    powers_and_max() {
       const int size = (int)(log10(double(std::numeric_limits<type>::max())));
       int j = 0;
       type i = 10;
       for( ; j<size ;++j){
           push_back(i-1);//9,99,999,9999 etc;
           i*=10;
       }
       ASSERT(back()<std::numeric_limits<type>::max());
       push_back(std::numeric_limits<type>::max());
   }
};

ось простий тест:

number_of_decimal_digits<int>  ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);

Звичайно, будь-яка інша реалізація впорядкованого набору може бути використана для, powers_and_maxі якщо б було знання про те, що буде кластеризація, але невідомо про те, де кластер може бути, можливо, найкращою є саморегулююча реалізація дерева.


-1

ефективний спосіб

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

#include <iostream>

int main()
{
   int num;
   std::cin >> num;

   std::cout << "number of digits for " << num << ": ";

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

   std::cout << count << '\n';

   return 0;
}

-1

Оновлення бажаного рішення на C ++ 11:

#include <limits>
#include <type_traits>
        template <typename T>
        typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
        numberDigits(T value) {
            unsigned int digits = 0;
            if (value < 0) digits = 1;
            while (value) {
                value /= 10;
                ++digits;
            }
            return digits;
        }

перешкоджає ідентифікації шаблону з подвійним, та ін. ін.


-1
int numberOfDigits(double number){
    if(number < 0){
        number*=-1;
    }
    int i=0;
        while(number > pow(10, i))
            i++;    
    cout << "This number has " << i << " digits" << endl;
    return i;
}

-2

Це мій спосіб зробити це:

   int digitcount(int n)
    {
        int count = 1;
        int temp = n;
        while (true)
        {
            temp /= 10;
            if (temp != 0) ++count;
            if (temp == 0) break;
        }

        return count;
    }

2
в той час як синдром справжнього / розриву: D
Петър Петров

-1 це той самий підхід, який перший відповідь дав на шість років раніше, і він нічого не додає (насправді це значно гірше).

-4

Ось інший підхід:

digits = sprintf(numArr, "%d", num);    // where numArr is a char array
if (num < 0)
    digits--;

Це може бути не ефективно, просто щось інше, ніж те, що пропонували інші.


4
Прохання було надзвичайно ефективним. Це навпаки.
Іра Бакстер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.