Một cách rất hiệu quả để xác định có bao nhiêu chữ số trong một số nguyên trong C ++ là gì?
Một cách rất hiệu quả để xác định có bao nhiêu chữ số trong một số nguyên trong C ++ là gì?
Câu trả lời:
Chà, cách hiệu quả nhất, giả sử bạn biết kích thước của số nguyên, sẽ là một tra cứu. Nên nhanh hơn cách tiếp cận dựa trên logarit ngắn hơn nhiều. Nếu bạn không quan tâm đến việc đếm '-', hãy xóa +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];
}
Cách đơn giản nhất là làm:
unsigned GetNumberOfDigits (unsigned i)
{
return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}
log10 được định nghĩa trong <cmath>
hoặc <math.h>
. Bạn cần phải lập hồ sơ này để xem nó có nhanh hơn bất kỳ bài nào khác được đăng ở đây không. Tôi không chắc điều này mạnh đến mức nào về độ chính xác của điểm nổi. Ngoài ra, đối số không được ký là giá trị âm và nhật ký không thực sự trộn lẫn.
-fpfast
bạn có thể thấy việc sử dụng SSE Barsinsics thay vì x87, điều này mang lại ít đảm bảo hơn cho IIRC chính xác. nhưng theo mặc định không có vấn đề.
Có lẽ tôi đã hiểu nhầm câu hỏi nhưng điều này không làm được?
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++; }
Lưu ý: "0" sẽ có 0 chữ số! Nếu bạn cần 0 để xuất hiện để có 1 chữ số, hãy sử dụng:
int digits = 0; do { number /= 10; digits++; } while (number != 0);
(Cảm ơn Kevin Fegan)
Cuối cùng, hãy sử dụng một hồ sơ để biết câu trả lời nào trong số này sẽ nhanh hơn trên máy của bạn ...
Thực tiễn đùa: Đây là những cách hiệu quả nhất (số chữ số được tính tại thời gian biên dịch):
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 };
};
Có thể hữu ích để xác định độ rộng cần thiết cho trường số trong định dạng, thành phần đầu vào, v.v.
0
và cũng thất bại trên cơ sở 1
:) và phân chia cho các lỗi bằng 0 nếu cơ sở được đưa ra là 0
. Nó có thể được sửa chữa mặc dù. Dù sao, tôi đang viết về một bài viết rất cũ, rất xin lỗi, chỉ là tôi nghĩ rằng đây không phải là một trò đùa và thực sự có thể hữu ích.
Xem Bit Twiddling Hacks để biết phiên bản ngắn hơn của câu trả lời mà bạn đã chấp nhận. Nó cũng có lợi ích là tìm ra câu trả lời sớm hơn nếu đầu vào của bạn được phân phối bình thường, bằng cách kiểm tra các hằng số lớn trước. (v >= 1000000000)
nắm bắt 76% giá trị, do đó, việc kiểm tra đầu tiên sẽ trung bình nhanh hơn.
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;
Một poster trước đã đề xuất một vòng lặp chia cho 10. Vì bội số trên các máy hiện đại nhanh hơn rất nhiều, nên tôi khuyên bạn nên sử dụng mã sau:
int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }
Kiến trúc ppc có một hướng dẫn đếm bit. Cùng với đó, bạn có thể xác định cơ sở nhật ký 2 của một số nguyên dương trong một lệnh. Ví dụ: 32 bit sẽ là:
#define log_2_32_ppc(x) (31-__cntlzw(x))
Nếu bạn có thể xử lý một lỗi sai nhỏ trên các giá trị lớn, bạn có thể chuyển đổi nó thành nhật ký cơ sở 10 bằng một vài hướng dẫn khác:
#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))
Đây là nền tảng cụ thể và hơi không chính xác, nhưng cũng không liên quan đến chi nhánh, phân chia hoặc chuyển đổi thành điểm nổi. Tất cả phụ thuộc vào những gì bạn cần.
Tôi chỉ biết các hướng dẫn ppc ngoài tay, nhưng các kiến trúc khác nên có hướng dẫn tương tự.
#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;
}
Đây có lẽ là cách đơn giản nhất để giải quyết vấn đề của bạn, giả sử bạn chỉ quan tâm đến các chữ số trước số thập phân và giả sử mọi thứ nhỏ hơn 10 chỉ là 1 chữ số.
Tôi thích câu trả lời của Ira Baxter. Dưới đây là một biến thể mẫu xử lý các kích thước khác nhau và xử lý các giá trị số nguyên tối đa (được cập nhật để nâng thanh tra giới hạn trên của vòng lặp):
#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;
}
Để thực sự có được hiệu suất được cải thiện từ việc nâng thử nghiệm bổ sung ra khỏi vòng lặp, bạn cần phải chuyên biệt max_decimal () để trả về hằng số cho từng loại trên nền tảng của bạn. Một trình biên dịch ma thuật đủ có thể tối ưu hóa cuộc gọi thành max_decimal () thành một hằng số, nhưng chuyên môn hóa tốt hơn với hầu hết các trình biên dịch ngày nay. Như hiện tại, phiên bản này có thể chậm hơn vì chi phí tối đa nhiều hơn so với các thử nghiệm được loại bỏ khỏi vòng lặp.
Tôi sẽ để lại tất cả những điều đó như một bài tập cho người đọc.
#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
)
)
);
}
Một đoạn mã khác, về cơ bản giống như Vitali nhưng sử dụng tìm kiếm nhị phân. Mảng quyền hạn được lười biếng khởi tạo một lần cho mỗi thể hiện kiểu không dấu. Ký loại quá tải chăm sóc dấu trừ.
#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) );
}
Nếu bất cứ ai quan tâm đến việc tối ưu hóa hơn nữa, xin lưu ý rằng phần tử đầu tiên của mảng lũy thừa không bao giờ được sử dụng và l
xuất hiện với +1
2 lần.
trong trường hợp số chữ số VÀ giá trị của từng vị trí chữ số là cần thiết, hãy sử dụng:
int64_t = number, digitValue, digits = 0; // or "int" for 32bit
while (number != 0) {
digitValue = number % 10;
digits ++;
number /= 10;
}
digit
cung cấp cho bạn giá trị tại bài đăng số hiện đang được xử lý trong vòng lặp. ví dụ cho số 1776, giá trị chữ số là:
6 trong vòng 1
7 trong vòng 2 thứ
7 trong vòng 3 thứ
1 trong vòng 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
)
)
)
);
}
đối với số nguyên 'X' bạn muốn biết số chữ số, không cần sử dụng bất kỳ vòng lặp nào, giải pháp này chỉ hoạt động trong một công thức trong một dòng vì vậy đây là giải pháp tối ưu nhất tôi từng thấy cho vấn đề này.
int x = 1000 ;
cout<<numberOfDigits = 1+floor(log10(x))<<endl ;
double
? Hoặc bạn đang đề cập đến một số đầu vào số nguyên không thể có chữ số thập phân INT_MAX? Mà cũng sẽ thất bại mọi câu trả lời khác ở đây?
int numberOfDigits(int n){
if(n<=9){
return 1;
}
return 1 + numberOfDigits(n/10);
}
Đây là những gì tôi sẽ làm, nếu bạn muốn nó cho cơ sở 10. Tôi khá nhanh và bạn sẽ không nhận được một ngăn xếp quá mức mua số nguyên đếm
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";
Nếu nhanh hơn là hiệu quả hơn, đây là một cải tiến về cải tiến của andrei alexandrescu . Phiên bản của anh ta đã nhanh hơn cách ngây thơ (chia cho 10 ở mỗi chữ số). Phiên bản dưới đây là thời gian không đổi và nhanh hơn ít nhất là trên x86-64 và ARM cho tất cả các kích cỡ, nhưng chiếm gấp đôi số mã nhị phân, vì vậy nó không thân thiện với bộ đệm.
Điểm chuẩn cho phiên bản này so với phiên bản của alexandrescu trên PR của tôi trên facebook .
Hoạt động trên unsigned
, không 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);
}
Tôi đang làm việc trên một chương trình yêu cầu tôi kiểm tra xem người dùng có trả lời đúng có bao nhiêu chữ số trong một số không, vì vậy tôi phải phát triển một cách để kiểm tra số lượng chữ số trong một số nguyên. Nó đã trở thành một điều tương đối dễ dàng để giải quyết.
double check=0, exponent=1000;
while(check<=1)
{
check=number/pow(10, exponent);
exponent--;
}
exponent=exponent+2;
cout<<exponent<<endl;
Đây là câu trả lời của tôi hiện đang hoạt động với các số có ít hơn 10 ^ 1000 chữ số (có thể thay đổi bằng cách thay đổi giá trị của số mũ).
Tái bút Tôi biết câu trả lời này trễ mười năm nhưng tôi đã đến đây vào năm 2020 để những người khác có thể sử dụng nó.
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);
}
};
nơi mà trong powers_and_max
chúng ta có (10^n)-1
cho tất cả n
mà
(10^n) <
std::numeric_limits<type>::max()
và std::numeric_limits<type>::max()
trong một mảng:
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());
}
};
đây là một bài kiểm tra đơn giản:
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);
Tất nhiên, bất kỳ triển khai nào khác của một tập hợp có thể được sử dụng cho powers_and_max
và nếu có kiến thức rằng sẽ có cụm nhưng không có kiến thức về nơi cụm có thể là một thực thi cây tự điều chỉnh có thể là tốt nhất
cách hiệu quả
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ập nhật C ++ 11 của giải pháp ưa thích:
#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;
}
ngăn chặn việc khởi tạo mẫu với double, et. al.
Đây là cách của tôi để làm điều đó:
int digitcount(int n)
{
int count = 1;
int temp = n;
while (true)
{
temp /= 10;
if (temp != 0) ++count;
if (temp == 0) break;
}
return count;
}
Đây là một cách tiếp cận khác:
digits = sprintf(numArr, "%d", num); // where numArr is a char array
if (num < 0)
digits--;
Điều này có thể không hiệu quả, chỉ là một cái gì đó khác với những gì người khác đề xuất.