Move files for special numbers to own directory (#10714)

This commit is contained in:
Tianyi Zheng 2023-10-20 02:17:31 -04:00 committed by GitHub
parent 197604898b
commit 6f2d6f72d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 310 additions and 310 deletions

View File

@ -1,98 +1,98 @@
"""
An Armstrong number is equal to the sum of its own digits each raised to the
power of the number of digits.
For example, 370 is an Armstrong number because 3*3*3 + 7*7*7 + 0*0*0 = 370.
Armstrong numbers are also called Narcissistic numbers and Pluperfect numbers.
On-Line Encyclopedia of Integer Sequences entry: https://oeis.org/A005188
"""
PASSING = (1, 153, 370, 371, 1634, 24678051, 115132219018763992565095597973971522401)
FAILING: tuple = (-153, -1, 0, 1.2, 200, "A", [], {}, None)
def armstrong_number(n: int) -> bool:
"""
Return True if n is an Armstrong number or False if it is not.
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
# Initialization of sum and number of digits.
total = 0
number_of_digits = 0
temp = n
# Calculation of digits of the number
number_of_digits = len(str(n))
# Dividing number into separate digits and find Armstrong number
temp = n
while temp > 0:
rem = temp % 10
total += rem**number_of_digits
temp //= 10
return n == total
def pluperfect_number(n: int) -> bool:
"""Return True if n is a pluperfect number or False if it is not
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
# Init a "histogram" of the digits
digit_histogram = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
digit_total = 0
total = 0
temp = n
while temp > 0:
temp, rem = divmod(temp, 10)
digit_histogram[rem] += 1
digit_total += 1
for cnt, i in zip(digit_histogram, range(len(digit_histogram))):
total += cnt * i**digit_total
return n == total
def narcissistic_number(n: int) -> bool:
"""Return True if n is a narcissistic number or False if it is not.
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
expo = len(str(n)) # the power that all digits will be raised to
# check if sum of each digit multiplied expo times is equal to number
return n == sum(int(i) ** expo for i in str(n))
def main():
"""
Request that user input an integer and tell them if it is Armstrong number.
"""
num = int(input("Enter an integer to see if it is an Armstrong number: ").strip())
print(f"{num} is {'' if armstrong_number(num) else 'not '}an Armstrong number.")
print(f"{num} is {'' if narcissistic_number(num) else 'not '}an Armstrong number.")
print(f"{num} is {'' if pluperfect_number(num) else 'not '}an Armstrong number.")
if __name__ == "__main__":
import doctest
doctest.testmod()
main()
"""
An Armstrong number is equal to the sum of its own digits each raised to the
power of the number of digits.
For example, 370 is an Armstrong number because 3*3*3 + 7*7*7 + 0*0*0 = 370.
Armstrong numbers are also called Narcissistic numbers and Pluperfect numbers.
On-Line Encyclopedia of Integer Sequences entry: https://oeis.org/A005188
"""
PASSING = (1, 153, 370, 371, 1634, 24678051, 115132219018763992565095597973971522401)
FAILING: tuple = (-153, -1, 0, 1.2, 200, "A", [], {}, None)
def armstrong_number(n: int) -> bool:
"""
Return True if n is an Armstrong number or False if it is not.
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
# Initialization of sum and number of digits.
total = 0
number_of_digits = 0
temp = n
# Calculation of digits of the number
number_of_digits = len(str(n))
# Dividing number into separate digits and find Armstrong number
temp = n
while temp > 0:
rem = temp % 10
total += rem**number_of_digits
temp //= 10
return n == total
def pluperfect_number(n: int) -> bool:
"""Return True if n is a pluperfect number or False if it is not
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
# Init a "histogram" of the digits
digit_histogram = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
digit_total = 0
total = 0
temp = n
while temp > 0:
temp, rem = divmod(temp, 10)
digit_histogram[rem] += 1
digit_total += 1
for cnt, i in zip(digit_histogram, range(len(digit_histogram))):
total += cnt * i**digit_total
return n == total
def narcissistic_number(n: int) -> bool:
"""Return True if n is a narcissistic number or False if it is not.
>>> all(armstrong_number(n) for n in PASSING)
True
>>> any(armstrong_number(n) for n in FAILING)
False
"""
if not isinstance(n, int) or n < 1:
return False
expo = len(str(n)) # the power that all digits will be raised to
# check if sum of each digit multiplied expo times is equal to number
return n == sum(int(i) ** expo for i in str(n))
def main():
"""
Request that user input an integer and tell them if it is Armstrong number.
"""
num = int(input("Enter an integer to see if it is an Armstrong number: ").strip())
print(f"{num} is {'' if armstrong_number(num) else 'not '}an Armstrong number.")
print(f"{num} is {'' if narcissistic_number(num) else 'not '}an Armstrong number.")
print(f"{num} is {'' if pluperfect_number(num) else 'not '}an Armstrong number.")
if __name__ == "__main__":
import doctest
doctest.testmod()
main()

View File

@ -1,158 +1,158 @@
"""
A harshad number (or more specifically an n-harshad number) is a number that's
divisible by the sum of its digits in some given base n.
Reference: https://en.wikipedia.org/wiki/Harshad_number
"""
def int_to_base(number: int, base: int) -> str:
"""
Convert a given positive decimal integer to base 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> int_to_base(23, 2)
'10111'
>>> int_to_base(58, 5)
'213'
>>> int_to_base(167, 16)
'A7'
>>> # bases below 2 and beyond 36 will error
>>> int_to_base(98, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> int_to_base(98, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = ""
if number < 0:
raise ValueError("number must be a positive integer")
while number > 0:
number, remainder = divmod(number, base)
result = digits[remainder] + result
if result == "":
result = "0"
return result
def sum_of_digits(num: int, base: int) -> str:
"""
Calculate the sum of digit values in a positive integer
converted to the given 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> sum_of_digits(103, 12)
'13'
>>> sum_of_digits(1275, 4)
'30'
>>> sum_of_digits(6645, 2)
'1001'
>>> # bases below 2 and beyond 36 will error
>>> sum_of_digits(543, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> sum_of_digits(543, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
num_str = int_to_base(num, base)
res = sum(int(char, base) for char in num_str)
res_str = int_to_base(res, base)
return res_str
def harshad_numbers_in_base(limit: int, base: int) -> list[str]:
"""
Finds all Harshad numbers smaller than num in base 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> harshad_numbers_in_base(15, 2)
['1', '10', '100', '110', '1000', '1010', '1100']
>>> harshad_numbers_in_base(12, 34)
['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B']
>>> harshad_numbers_in_base(12, 4)
['1', '2', '3', '10', '12', '20', '21']
>>> # bases below 2 and beyond 36 will error
>>> harshad_numbers_in_base(234, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> harshad_numbers_in_base(234, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
if limit < 0:
return []
numbers = [
int_to_base(i, base)
for i in range(1, limit)
if i % int(sum_of_digits(i, base), base) == 0
]
return numbers
def is_harshad_number_in_base(num: int, base: int) -> bool:
"""
Determines whether n in base 'base' is a harshad number.
Where 'base' ranges from 2 to 36.
Examples:
>>> is_harshad_number_in_base(18, 10)
True
>>> is_harshad_number_in_base(21, 10)
True
>>> is_harshad_number_in_base(-21, 5)
False
>>> # bases below 2 and beyond 36 will error
>>> is_harshad_number_in_base(45, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> is_harshad_number_in_base(45, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
if num < 0:
return False
n = int_to_base(num, base)
d = sum_of_digits(num, base)
return int(n, base) % int(d, base) == 0
if __name__ == "__main__":
import doctest
doctest.testmod()
"""
A harshad number (or more specifically an n-harshad number) is a number that's
divisible by the sum of its digits in some given base n.
Reference: https://en.wikipedia.org/wiki/Harshad_number
"""
def int_to_base(number: int, base: int) -> str:
"""
Convert a given positive decimal integer to base 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> int_to_base(23, 2)
'10111'
>>> int_to_base(58, 5)
'213'
>>> int_to_base(167, 16)
'A7'
>>> # bases below 2 and beyond 36 will error
>>> int_to_base(98, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> int_to_base(98, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = ""
if number < 0:
raise ValueError("number must be a positive integer")
while number > 0:
number, remainder = divmod(number, base)
result = digits[remainder] + result
if result == "":
result = "0"
return result
def sum_of_digits(num: int, base: int) -> str:
"""
Calculate the sum of digit values in a positive integer
converted to the given 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> sum_of_digits(103, 12)
'13'
>>> sum_of_digits(1275, 4)
'30'
>>> sum_of_digits(6645, 2)
'1001'
>>> # bases below 2 and beyond 36 will error
>>> sum_of_digits(543, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> sum_of_digits(543, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
num_str = int_to_base(num, base)
res = sum(int(char, base) for char in num_str)
res_str = int_to_base(res, base)
return res_str
def harshad_numbers_in_base(limit: int, base: int) -> list[str]:
"""
Finds all Harshad numbers smaller than num in base 'base'.
Where 'base' ranges from 2 to 36.
Examples:
>>> harshad_numbers_in_base(15, 2)
['1', '10', '100', '110', '1000', '1010', '1100']
>>> harshad_numbers_in_base(12, 34)
['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B']
>>> harshad_numbers_in_base(12, 4)
['1', '2', '3', '10', '12', '20', '21']
>>> # bases below 2 and beyond 36 will error
>>> harshad_numbers_in_base(234, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> harshad_numbers_in_base(234, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
if limit < 0:
return []
numbers = [
int_to_base(i, base)
for i in range(1, limit)
if i % int(sum_of_digits(i, base), base) == 0
]
return numbers
def is_harshad_number_in_base(num: int, base: int) -> bool:
"""
Determines whether n in base 'base' is a harshad number.
Where 'base' ranges from 2 to 36.
Examples:
>>> is_harshad_number_in_base(18, 10)
True
>>> is_harshad_number_in_base(21, 10)
True
>>> is_harshad_number_in_base(-21, 5)
False
>>> # bases below 2 and beyond 36 will error
>>> is_harshad_number_in_base(45, 37)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
>>> is_harshad_number_in_base(45, 1)
Traceback (most recent call last):
...
ValueError: 'base' must be between 2 and 36 inclusive
"""
if base < 2 or base > 36:
raise ValueError("'base' must be between 2 and 36 inclusive")
if num < 0:
return False
n = int_to_base(num, base)
d = sum_of_digits(num, base)
return int(n, base) % int(d, base) == 0
if __name__ == "__main__":
import doctest
doctest.testmod()

View File

@ -1,54 +1,54 @@
"""
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, shows the first 11 ugly numbers. By convention,
1 is included.
Given an integer n, we have to find the nth ugly number.
For more details, refer this article
https://www.geeksforgeeks.org/ugly-numbers/
"""
def ugly_numbers(n: int) -> int:
"""
Returns the nth ugly number.
>>> ugly_numbers(100)
1536
>>> ugly_numbers(0)
1
>>> ugly_numbers(20)
36
>>> ugly_numbers(-5)
1
>>> ugly_numbers(-5.5)
Traceback (most recent call last):
...
TypeError: 'float' object cannot be interpreted as an integer
"""
ugly_nums = [1]
i2, i3, i5 = 0, 0, 0
next_2 = ugly_nums[i2] * 2
next_3 = ugly_nums[i3] * 3
next_5 = ugly_nums[i5] * 5
for _ in range(1, n):
next_num = min(next_2, next_3, next_5)
ugly_nums.append(next_num)
if next_num == next_2:
i2 += 1
next_2 = ugly_nums[i2] * 2
if next_num == next_3:
i3 += 1
next_3 = ugly_nums[i3] * 3
if next_num == next_5:
i5 += 1
next_5 = ugly_nums[i5] * 5
return ugly_nums[-1]
if __name__ == "__main__":
from doctest import testmod
testmod(verbose=True)
print(f"{ugly_numbers(200) = }")
"""
Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, shows the first 11 ugly numbers. By convention,
1 is included.
Given an integer n, we have to find the nth ugly number.
For more details, refer this article
https://www.geeksforgeeks.org/ugly-numbers/
"""
def ugly_numbers(n: int) -> int:
"""
Returns the nth ugly number.
>>> ugly_numbers(100)
1536
>>> ugly_numbers(0)
1
>>> ugly_numbers(20)
36
>>> ugly_numbers(-5)
1
>>> ugly_numbers(-5.5)
Traceback (most recent call last):
...
TypeError: 'float' object cannot be interpreted as an integer
"""
ugly_nums = [1]
i2, i3, i5 = 0, 0, 0
next_2 = ugly_nums[i2] * 2
next_3 = ugly_nums[i3] * 3
next_5 = ugly_nums[i5] * 5
for _ in range(1, n):
next_num = min(next_2, next_3, next_5)
ugly_nums.append(next_num)
if next_num == next_2:
i2 += 1
next_2 = ugly_nums[i2] * 2
if next_num == next_3:
i3 += 1
next_3 = ugly_nums[i3] * 3
if next_num == next_5:
i5 += 1
next_5 = ugly_nums[i5] * 5
return ugly_nums[-1]
if __name__ == "__main__":
from doctest import testmod
testmod(verbose=True)
print(f"{ugly_numbers(200) = }")