2020-07-26 10:42:18 +00:00
|
|
|
import math
|
|
|
|
from timeit import timeit
|
|
|
|
|
|
|
|
|
2020-06-01 15:23:15 +00:00
|
|
|
def num_digits(n: int) -> int:
|
|
|
|
"""
|
|
|
|
Find the number of digits in a number.
|
|
|
|
|
|
|
|
>>> num_digits(12345)
|
|
|
|
5
|
|
|
|
>>> num_digits(123)
|
|
|
|
3
|
2020-08-12 16:32:35 +00:00
|
|
|
>>> num_digits(0)
|
|
|
|
1
|
|
|
|
>>> num_digits(-1)
|
|
|
|
1
|
|
|
|
>>> num_digits(-123456)
|
|
|
|
6
|
2023-10-10 04:19:40 +00:00
|
|
|
>>> num_digits('123') # Raises a TypeError for non-integer input
|
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
TypeError: Input must be an integer
|
2020-06-01 15:23:15 +00:00
|
|
|
"""
|
2023-10-10 04:19:40 +00:00
|
|
|
|
|
|
|
if not isinstance(n, int):
|
|
|
|
raise TypeError("Input must be an integer")
|
|
|
|
|
2020-06-01 15:23:15 +00:00
|
|
|
digits = 0
|
2020-08-12 16:32:35 +00:00
|
|
|
n = abs(n)
|
|
|
|
while True:
|
2020-06-01 15:23:15 +00:00
|
|
|
n = n // 10
|
|
|
|
digits += 1
|
2020-08-12 16:32:35 +00:00
|
|
|
if n == 0:
|
|
|
|
break
|
2020-06-01 15:23:15 +00:00
|
|
|
return digits
|
|
|
|
|
|
|
|
|
2020-07-26 10:42:18 +00:00
|
|
|
def num_digits_fast(n: int) -> int:
|
|
|
|
"""
|
|
|
|
Find the number of digits in a number.
|
|
|
|
abs() is used as logarithm for negative numbers is not defined.
|
|
|
|
|
|
|
|
>>> num_digits_fast(12345)
|
|
|
|
5
|
|
|
|
>>> num_digits_fast(123)
|
|
|
|
3
|
2020-08-12 16:32:35 +00:00
|
|
|
>>> num_digits_fast(0)
|
|
|
|
1
|
|
|
|
>>> num_digits_fast(-1)
|
|
|
|
1
|
|
|
|
>>> num_digits_fast(-123456)
|
|
|
|
6
|
2023-10-10 04:19:40 +00:00
|
|
|
>>> num_digits('123') # Raises a TypeError for non-integer input
|
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
TypeError: Input must be an integer
|
2020-07-26 10:42:18 +00:00
|
|
|
"""
|
2023-10-10 04:19:40 +00:00
|
|
|
|
|
|
|
if not isinstance(n, int):
|
|
|
|
raise TypeError("Input must be an integer")
|
|
|
|
|
2020-08-12 16:32:35 +00:00
|
|
|
return 1 if n == 0 else math.floor(math.log(abs(n), 10) + 1)
|
2020-07-26 10:42:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
def num_digits_faster(n: int) -> int:
|
|
|
|
"""
|
|
|
|
Find the number of digits in a number.
|
|
|
|
abs() is used for negative numbers
|
|
|
|
|
|
|
|
>>> num_digits_faster(12345)
|
|
|
|
5
|
|
|
|
>>> num_digits_faster(123)
|
|
|
|
3
|
2020-08-12 16:32:35 +00:00
|
|
|
>>> num_digits_faster(0)
|
|
|
|
1
|
|
|
|
>>> num_digits_faster(-1)
|
|
|
|
1
|
|
|
|
>>> num_digits_faster(-123456)
|
|
|
|
6
|
2023-10-10 04:19:40 +00:00
|
|
|
>>> num_digits('123') # Raises a TypeError for non-integer input
|
|
|
|
Traceback (most recent call last):
|
|
|
|
...
|
|
|
|
TypeError: Input must be an integer
|
2020-07-26 10:42:18 +00:00
|
|
|
"""
|
2023-10-10 04:19:40 +00:00
|
|
|
|
|
|
|
if not isinstance(n, int):
|
|
|
|
raise TypeError("Input must be an integer")
|
|
|
|
|
2020-08-01 03:53:23 +00:00
|
|
|
return len(str(abs(n)))
|
2020-07-26 10:42:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
def benchmark() -> None:
|
|
|
|
"""
|
2022-11-08 11:49:47 +00:00
|
|
|
Benchmark multiple functions, with three different length int values.
|
2020-07-26 10:42:18 +00:00
|
|
|
"""
|
2022-11-08 11:49:47 +00:00
|
|
|
from collections.abc import Callable
|
|
|
|
|
|
|
|
def benchmark_a_function(func: Callable, value: int) -> None:
|
|
|
|
call = f"{func.__name__}({value})"
|
|
|
|
timing = timeit(f"__main__.{call}", setup="import __main__")
|
|
|
|
print(f"{call}: {func(value)} -- {timing} seconds")
|
|
|
|
|
|
|
|
for value in (262144, 1125899906842624, 1267650600228229401496703205376):
|
|
|
|
for func in (num_digits, num_digits_fast, num_digits_faster):
|
|
|
|
benchmark_a_function(func, value)
|
|
|
|
print()
|
2020-07-26 10:42:18 +00:00
|
|
|
|
|
|
|
|
2020-06-01 15:23:15 +00:00
|
|
|
if __name__ == "__main__":
|
2020-08-12 16:32:35 +00:00
|
|
|
import doctest
|
|
|
|
|
|
|
|
doctest.testmod()
|
2022-11-08 11:49:47 +00:00
|
|
|
benchmark()
|