Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

นับจำนวนหลักของจำนวนเต็มใน C++: วิธีแบบคลาสสิกและลอการิทึม

การนับจำนวนหลัก (Digits) ของจำนวนเต็มใน C++ มีหลักวิธีหลัก 2 แบบ: Iterative Division และ Logarithm แต่ละวิธีมีข้อดีข้อเสียและ Corner Cases ที่ต้องระวัง

วิธีที่ 1: Iterative Division (วนลูปหาร 10)

เหมาะสำหรับทุก Integer Type รวมถึง 0 และค่าลบ

int count_digits_iterative(long long n) {
    if (n == 0) return 1; // Corner Case: 0 มี 1 หลัก
    int count = 0;
    n = std::llabs(n); // จัดการค่าลบ
    while (n != 0) {
        n /= 10;
        ++count;
    }
    return count;
}

วิธีที่ 2: Logarithm Base 10 (O(1))

สูตร: digits = floor(log10(|n|)) + 1

#include <cmath>

int count_digits_log(long long n) {
    if (n == 0) return 1; // log10(0) Undefined
    return static_cast<int>(std::log10(std::llabs(n))) + 1;
}

เปรียบเทียบและข้อระวัง

ด้านIterativeLogarithm
ComplexityO(d) digitsO(1)
Precisionแม่นยำ 100%อาจผิดจาก Floating-Point Error (เช่น 999...999)
Handle 0ง่าย (Check ก่อน)ต้อง Check ก่อน (log10(0) = -inf)
Negativeใช้ abs()ใช้ abs()
Performanceช้าสำหรับตัวเลขใหญ่มากเร็ว คงที่

วิธีที่ 3: String Conversion (Simple & Safe)

ทันสมัย ใช้ std::to_string (C++11) - อ่านง่าย ไม่ต้องกังวล Corner Cases

#include <string>

int count_digits_string(long long n) {
    std::string s = std::to_string(n);
    if (n < 0) return s.length() - 1; // ลบเครื่องหมาย -
    return s.length();
}

Benchmark แบบคร่าว (10M Iterations)

Iterative:  ~120 ms
Log10:      ~80 ms   (แต่ต้อง Validate Edge Cases)
String:     ~200 ms  (Allocation Overhead)

แนวทางเลือก

  • General Purpose: Iterative (ปลอดภัย, ไม่ต้อง Link -lm)
  • Performance Critical + Known Range: Log10 (กับการ Fix Edge Cases)
  • Code Clarity / Rapid Dev: to_string
  • Compile-time (constexpr): Iterative เท่านั้น (Log10 ไม่ใช่ constexpr ใน C++17)

สรุป

ไม่มี "Silver Bullet" วิธี Iterative ปลอดภัยที่สุด Log10 เร็วที่สุดแต่ต้องระวัง Precision String สะดวกที่สุด เลือกตาม Context ของโปรเจกต์