Skip to content
101 changes: 101 additions & 0 deletions maths/weird_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
https://en.wikipedia.org/wiki/Weird_number

Fun fact: The set of weird numbers has positive asymptotic density.
"""
from math import sqrt


def factors(number: int) -> list[int]:
"""
>>> factors(12)
[1, 2, 3, 4, 6]
>>> factors(1)
[1]
>>> factors(100)
[1, 2, 4, 5, 10, 20, 25, 50]

# >>> factors(-12)
# [1, 2, 3, 4, 6]
"""

values = [1]
for i in range(2, int(sqrt(number)) + 1, 1):

if number % i == 0:
values.append(i)
if int(number // i) != i:
values.append(int(number // i))
return sorted(values)


def abundant(n: int) -> bool:
"""
>>> abundant(0)
True
>>> abundant(1)
False
>>> abundant(12)
True
>>> abundant(13)
False
>>> abundant(20)
True

# >>> abundant(-12)
# True
"""
return sum(factors(n)) > n


def semi_perfect(number: int) -> bool:
"""
>>> semi_perfect(0)
True
>>> semi_perfect(1)
True
>>> semi_perfect(12)
True
>>> semi_perfect(13)
False

# >>> semi_perfect(-12)
# True
"""
values = factors(number)
r = len(values)
subset = [[0 for i in range(number + 1)] for j in range(r + 1)]
for i in range(r + 1):
subset[i][0] = True

for i in range(1, number + 1):
subset[0][i] = False

for i in range(1, r + 1):
for j in range(1, number + 1):
if j < values[i - 1]:
subset[i][j] = subset[i - 1][j]
else:
subset[i][j] = subset[i - 1][j] or subset[i - 1][j - values[i - 1]]

return subset[r][number] != 0


def weird(number: int) -> bool:
"""
>>> weird(0)
False
>>> weird(70)
True
>>> weird(77)
False
"""
return abundant(number) and not semi_perfect(number)


if __name__ == "__main__":
import doctest

doctest.testmod(verbose=True)
for number in (69, 70, 71):
print(f"{number} is {'' if weird(number) else 'not '}weird.")