Finding the number of digits of an integer

前端 未结 17 2039
难免孤独
难免孤独 2020-12-07 16:32

What is the best method to find the number of digits of a positive integer?

I have found this 3 basic methods:

  • conversion to string

             
    
    
            
相关标签:
17条回答
  • 2020-12-07 16:52

    Here is the measurement in Swift 4.

    Algorithms code:

    extension Int {
        var numberOfDigits0: Int {
            var currentNumber = self
            var n = 1
            if (currentNumber >= 100000000) {
                n += 8
                currentNumber /= 100000000
            }
            if (currentNumber >= 10000) {
                n += 4
                currentNumber /= 10000
            }
            if (currentNumber >= 100) {
                n += 2
                currentNumber /= 100
            }
            if (currentNumber >= 10) {
                n += 1
            }
            return n
        }
    
        var numberOfDigits1: Int {
            return String(self).count
        }
    
        var numberOfDigits2: Int {
            var n = 1
            var currentNumber = self
            while currentNumber > 9 {
                n += 1
                currentNumber /= 10
            }
            return n
        }
    
    }
    

    Measurement code:

    var timeInterval0 = Date()
    for i in 0...10000 {
        i.numberOfDigits0
    }
    print("timeInterval0: \(Date().timeIntervalSince(timeInterval0))")
    
    var timeInterval1 = Date()
    for i in 0...10000 {
        i.numberOfDigits1
    }
    print("timeInterval1: \(Date().timeIntervalSince(timeInterval1))")
    
    var timeInterval2 = Date()
    for i in 0...10000 {
        i.numberOfDigits2
    }
    print("timeInterval2: \(Date().timeIntervalSince(timeInterval2))")
    

    Output

    timeInterval0: 1.92149806022644

    timeInterval1: 0.557608008384705

    timeInterval2: 2.83262193202972

    On this measurement basis String conversion is the best option for the Swift language.

    0 讨论(0)
  • 2020-12-07 16:52
    let numDigits num =
        let num = abs(num)
        let rec numDigitsInner num =
            match num with
            | num when num < 10 -> 1
            | _ -> 1 + numDigitsInner (num / 10)
        numDigitsInner num
    

    F# Version, without casting to a string.

    0 讨论(0)
  • 2020-12-07 16:54

    There's always this method:

    n = 1;
    if ( i >= 100000000 ) { n += 8; i /= 100000000; }
    if ( i >= 10000     ) { n += 4; i /= 10000; }
    if ( i >= 100       ) { n += 2; i /= 100; }
    if ( i >= 10        ) { n += 1; }
    
    0 讨论(0)
  • 2020-12-07 16:54

    Regarding the three methods you propose for "determining the number of digits necessary to represent a given number in a given base", I don't like any of them, actually; I prefer the method I give below instead.

    Re your method #1 (strings): Anything involving converting back-and-forth between strings and numbers is usually very slow.

    Re your method #2 (temp/=10): This is fatally flawed because it assumes that x/10 always means "x divided by 10". But in many programming languages (eg: C, C++), if "x" is an integer type, then "x/10" means "integer division", which isn't the same thing as floating-point division, and it introduces round-off errors at every iteration, and they accumulate in a recursive formula such as your solution #2 uses.

    Re your method #3 (logs): it's buggy for large numbers (at least in C, and probably other languages as well), because floating-point data types tend not to be as precise as 64-bit integers.

    Hence I dislike all 3 of those methods: #1 works but is slow, #2 is broken, and #3 is buggy for large numbers. Instead, I prefer this, which works for numbers from 0 up to about 18.44 quintillion:

    unsigned NumberOfDigits (uint64_t Number, unsigned Base)
    {
       unsigned Digits = 1;
       uint64_t Power  = 1;
       while ( Number / Power >=  Base )
       {
          ++Digits;
          Power *= Base;
       }
       return Digits;
    }
    
    0 讨论(0)
  • 2020-12-07 16:55

    Well the correct answer would be to measure it - but you should be able to make a guess about the number of CPU steps involved in converting strings and going through them looking for an end marker

    Then think how many FPU operations/s your processor can do and how easy it is to calculate a single log.

    edit: wasting some more time on a monday morning :-)

    String s = new Integer(t).toString(); 
    int len = s.length();
    

    One of the problems with high level languages is guessing how much work the system is doing behind the scenes of an apparently simple statement. Mandatory Joel link

    This statement involves allocating memory for a string, and possibly a couple of temporary copies of a string. It must parse the integer and copy the digits of it into a string, possibly having to reallocate and move the existing memory if the number is large. It might have to check a bunch of locale settings to decide if your country uses "," or ".", it might have to do a bunch of unicode conversions.
    Then finding the length has to scan the entire string, again considering unicode and any local specific settings such as - are you in a right->left language?.

    Alternatively:

    digits = floor( log10( number ) ) + 1;
    

    Just because this would be harder for you to do on paper doesn't mean it's hard for a computer! In fact a good rule in high performance computing seems to have been - if something is hard for a human (fluid dynamics, 3d rendering) it's easy for a computer, and if it's easy for a human (face recognition, detecting a voice in a noisy room) it's hard for a computer!

    You can generally assume that the builtin maths functions log/sin/cos etc - have been an important part of computer design for 50years. So even if they don't map directly into a hardware function in the FPU you can bet that the alternative implementation is pretty efficient.

    0 讨论(0)
  • 2020-12-07 16:55

    I don't know, and the answer may well be different depending on how your individual language is implemented.

    So, stress test it! Implement all three solutions. Run them on 1 through 1,000,000 (or some other huge set of numbers that's representative of the numbers the solution will be running against) and time how long each of them takes.

    Pit your solutions against one another and let them fight it out. Like intellectual gladiators. Three algorithms enter! One algorithm leaves!

    0 讨论(0)
提交回复
热议问题