Що є дуже ефективним способом визначення кількості цифр у цілому цілі в C ++?
Що є дуже ефективним способом визначення кількості цифр у цілому цілі в C ++?
Відповіді:
Ну, найефективнішим способом, припускаючи, що ви знаєте розмір цілого числа, буде пошук. Має бути швидшим, ніж значно коротший підхід на основі логарифму. Якщо ви не переймаєтесь підрахунком "-", видаліть +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];
}
Найпростіший спосіб - це зробити:
unsigned GetNumberOfDigits (unsigned i)
{
return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}
log10 визначено в <cmath>
або <math.h>
. Вам потрібно буде профайлювати це, щоб побачити, чи швидше він, ніж будь-який з інших, розміщених тут. Я не впевнений, наскільки це надійно щодо точності плаваючої точки. Також аргумент не підписаний, оскільки негативні значення і журнал насправді не змішуються.
-fpfast
ви могли побачити використання SSE-інструментів, а не x87, що дає меншу гарантію на точність IIRC. але за замовчуванням немає проблем.
Можливо, я неправильно зрозумів питання, але це не робить?
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)))))))));
}
int digits = 0; while (number != 0) { number /= 10; digits++; }
Примітка: "0" матиме 0 цифр! Якщо вам потрібно 0, щоб мати 1 цифру, скористайтеся:
int digits = 0; do { number /= 10; digits++; } while (number != 0);
(Спасибі Кевін Феган)
Зрештою, скористайтеся профілером, щоб знати, який з усіх відповідей тут буде швидшим на вашій машині ...
Розіграші: Це найефективніший спосіб (кількість цифр обчислюються під час компіляції):
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 };
};
Може бути корисним для визначення ширини, необхідної для поля цифр у форматуванні, введення елементів тощо.
0
а також виходить з ладу на базі 1
:) і дає поділ на нульові помилки, якщо базі задано як 0
. Це все-таки можна виправити. У будь-якому разі я задираюсь над дуже давньою публікацією, так що вибачте, я просто думаю, що це не повинно бути жартом і насправді може бути корисним.
Дивіться Bit Twiddling Hacks для набагато коротшої версії відповіді, яку ви прийняли. Це також має перевагу швидше знайти відповідь, якщо ваш вклад зазвичай розподілений, попередньо перевіривши великі константи. (v >= 1000000000)
ловить 76% значень, тому перевірка того, що перший буде в середньому швидше.
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
Попередній плакат пропонував цикл, який ділиться на 10. Оскільки множення на сучасних машинах відбувається набагато швидше, я б рекомендував наступний код:
int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
У архітектурі 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, але інші архітектури повинні мати подібні інструкції.
#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, це лише одна цифра.
Мені подобається відповідь Іри Бакстер. Ось варіант шаблону, який обробляє різні розміри і має справу з максимальними цілими значеннями (оновлено для підняття верхньої межі виходу з циклу):
#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 коштує дорожче, ніж тести, вилучені з циклу.
Я залишу все це як вправу для читача.
#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
)
)
);
}
Ще один фрагмент коду, в основному такий же, як у Віталія, але використовує двійковий пошук. Масив повноважень ліниво ініціалізується один раз за непідписаний екземпляр типу. Перевантаження типу підписаного типу забезпечує піктограму мінус.
#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
з’являється у +1
2 рази.
у випадку, якщо потрібна кількість цифр ТА значення кожної цифри, використовуйте це:
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-й петлі
// 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) );
/// 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
)
)
)
);
}
для цілого числа "X" ви хочете знати кількість цифр, добре, не використовуючи циклу, це рішення діє в одній формулі лише в одному рядку, тому це найоптимальніше рішення, яке я коли-небудь бачив у цій проблемі.
int x = 1000 ;
cout<<numberOfDigits = 1+floor(log10(x))<<endl ;
double
? Або ви посилаєтесь на якийсь неможливий цілий вхід із десятковими цифрами INT_MAX? Що також не могло б пропустити будь-яку іншу відповідь тут?
int numberOfDigits(int n){
if(n<=9){
return 1;
}
return 1 + numberOfDigits(n/10);
}
Це те, що я б робив, якщо ви хочете, щоб це було базовим 10. Це досить швидко, і ви, звичайно, не отримаєте стек-оверлок, купіть підрахунок цілих чисел
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";
Якщо швидше є більш ефективним, це поліпшення вдосконалення Андреа Олександреску . Його версія була вже швидшою, ніж наївний шлях (ділившись на 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);
}
Я працював над програмою, яка вимагала від мене перевірити, чи правильно користувач відповів, скільки цифр було в кількості, тому мені довелося розробити спосіб перевірити кількість цифр у цілому. Це в кінцевому підсумку було порівняно простою для вирішення.
double check=0, exponent=1000;
while(check<=1)
{
check=number/pow(10, exponent);
exponent--;
}
exponent=exponent+2;
cout<<exponent<<endl;
Це було моєю відповіддю, яка в даний час працює з числами менше 10 ^ 1000 цифр (можна змінити, змінивши значення показника).
PS Я знаю, що ця відповідь запізнюється на десять років, але я потрапив сюди на 2020 рік, щоб інші люди могли її використовувати.
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
і якщо б було знання про те, що буде кластеризація, але невідомо про те, де кластер може бути, можливо, найкращою є саморегулююча реалізація дерева.
ефективний спосіб
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;
}
Оновлення бажаного рішення на 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;
}
перешкоджає ідентифікації шаблону з подвійним, та ін. ін.
Це мій спосіб зробити це:
int digitcount(int n)
{
int count = 1;
int temp = n;
while (true)
{
temp /= 10;
if (temp != 0) ++count;
if (temp == 0) break;
}
return count;
}
Ось інший підхід:
digits = sprintf(numArr, "%d", num); // where numArr is a char array
if (num < 0)
digits--;
Це може бути не ефективно, просто щось інше, ніж те, що пропонували інші.