วิธีที่มีประสิทธิภาพมากในการกำหนดจำนวนหลักที่มีในจำนวนเต็มใน 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 instrinsics มากกว่า 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);
(ขอบคุณ Kevin Fegan)
ในที่สุดใช้ profiler เพื่อทราบว่าคำตอบทั้งหมดของที่นี่จะเร็วกว่าบนเครื่องของคุณ ...
เล่นตลก: นี่คือวิธีที่มีประสิทธิภาพมากที่สุด (จำนวนของตัวเลขที่มีการคำนวณที่รวบรวมเวลา):
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% ของค่าดังนั้นการตรวจสอบว่าโดยเฉลี่ยก่อนจะเร็วกว่า
แปลงเป็นสตริงแล้วใช้ฟังก์ชันในตัว
unsigned int i;
cout<< to_string(i).length()<<endl;
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 มีคำสั่งการนับเล็กน้อย ด้วยสิ่งนี้คุณสามารถกำหนด log ฐาน 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 เป็นเพียง 1 หลัก
ฉันชอบคำตอบของ Ira Baxter นี่คือตัวแปรเท็มเพลตที่จัดการกับขนาดและข้อตกลงต่าง ๆ ด้วยค่าจำนวนเต็มสูงสุด (อัปเดตเพื่อยกการตรวจสอบขอบเขตบน)
#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
)
)
);
}
ยังเป็นข้อมูลโค้ดอีกอันโดยทั่วไปจะทำเหมือนกับ Vitali แต่ใช้การค้นหาแบบไบนารี่ อาเรย์กำลังเริ่มต้นขี้เกียจหนึ่งครั้งต่อหนึ่งอินสแตนซ์ของประเภทที่ไม่ได้ลงชื่อ โอเวอร์โหลดประเภทที่เซ็นชื่อจะดูแลเครื่องหมายลบ
#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. มันค่อนข้างเร็วและคุณจะไม่ได้สแต็ค overflock ซื้อจำนวนเต็มนับ
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";
หากเร็วขึ้นมีประสิทธิภาพมากขึ้นนี่คือการปรับปรุงในการปรับปรุงandrei alexandrescuการปรับปรุงของเวอร์ชันของเขาเร็วกว่าวิธีที่ไร้เดียงสา (หารด้วย 10 ทุกหลัก) เวอร์ชันด้านล่างเป็นเวลาที่แน่นอนและเร็วกว่าอย่างน้อยใน x86-64 และ ARM สำหรับทุกขนาด แต่ใช้รหัสไบนารี่สองเท่าดังนั้นจึงไม่เป็นมิตรกับแคช
มาตรฐานสำหรับรุ่นนี้เทียบกับรุ่นของ alexandrescu ในการประชาสัมพันธ์ของฉันบน 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 ^ 1,000 หลัก (สามารถเปลี่ยนแปลงได้โดยการเปลี่ยนค่าเลขชี้กำลัง)
ป.ล. ฉันรู้ว่าคำตอบนี้เป็นเวลาสิบปีที่ผ่านมา แต่ฉันมาที่นี่ในปี 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;
}
ป้องกันการเริ่มต้นแม่แบบด้วย double, et อัล
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;
}
นี่คือวิธีที่จะทำ:
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--;
สิ่งนี้อาจไม่มีประสิทธิภาพ แต่เป็นสิ่งที่แตกต่างจากที่คนอื่นแนะนำ