Skip to content

Commit 33e833a

Browse files
committed
refactor: complete refactoring of all math Python scripts to follow guidelines
1 parent 852726c commit 33e833a

17 files changed

Lines changed: 1429 additions & 1648 deletions

File tree

math/AP-GP-AGP-HP-Recognizer/AP-GP-AGP-HP-Recognizer.py

Lines changed: 119 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,154 @@
1+
import math
2+
13
print("=" * 58)
2-
print("AP / GP / AGP / HP RECOGNIZER")
4+
print("📊 AP / GP / AGP / HP RECOGNIZER 📊")
35
print("=" * 58)
4-
print("Enter at least 4 numbers separated by commas.")
5-
print("Example: 2, 4, 6, 8 or 3, 6, 12, 24")
6+
print("Enter at least 4 numbers separated by commas to recognize the progression.")
7+
print("Example: 2, 4, 6, 8 or 3, 6, 12, 24\n")
68

79
EPS = 1e-9
810

11+
while True:
12+
print("=" * 58)
13+
print("Choose an option:")
14+
print("1️⃣ Recognize sequence type")
15+
print("2️⃣ Exit")
16+
17+
choice = input("🎯 Enter your choice (1-2): ").strip()
918

10-
def is_close(a, b, eps=EPS):
11-
return abs(a - b) <= eps
19+
if choice == "2":
20+
print("\n👋 Thanks for using the recognizer. Keep practicing! ✨\n")
21+
break
1222

23+
if choice != "1":
24+
print("❌ Please choose 1 or 2.")
25+
continue
1326

14-
def parse_sequence(raw):
15-
parts = [item.strip() for item in raw.split(",") if item.strip()]
27+
user_input = input("\n📝 Enter sequence values separated by commas: ").strip()
28+
if not user_input:
29+
print("❌ Error: Input cannot be empty.")
30+
continue
31+
32+
# Parse sequence
33+
parts = [item.strip() for item in user_input.split(",") if item.strip()]
1634
if len(parts) < 4:
17-
return None, "Please enter at least 4 values."
35+
print("❌ Please enter at least 4 values.")
36+
continue
1837

1938
sequence = []
39+
parse_error = False
2040
for part in parts:
2141
try:
2242
sequence.append(float(part))
2343
except ValueError:
24-
return None, f"Invalid number: {part}"
25-
26-
return sequence, ""
27-
28-
29-
def check_ap(sequence):
30-
diff = sequence[1] - sequence[0]
31-
for i in range(2, len(sequence)):
32-
if not is_close(sequence[i] - sequence[i - 1], diff):
33-
return False, None
34-
return True, diff
35-
44+
print(f"❌ Invalid number: {part}")
45+
parse_error = True
46+
break
3647

37-
def check_gp(sequence):
38-
if all(is_close(value, 0.0) for value in sequence):
39-
return True, 0.0
48+
if parse_error:
49+
continue
4050

41-
if any(is_close(sequence[i - 1], 0.0) for i in range(1, len(sequence))):
42-
return False, None
51+
matched_types = []
4352

44-
ratio = sequence[1] / sequence[0]
53+
# 1. Check AP (Arithmetic Progression)
54+
is_ap = True
55+
ap_diff = sequence[1] - sequence[0]
4556
for i in range(2, len(sequence)):
46-
if not is_close(sequence[i] / sequence[i - 1], ratio):
47-
return False, None
48-
49-
return True, ratio
50-
51-
52-
def check_hp(sequence):
53-
if any(is_close(value, 0.0) for value in sequence):
54-
return False, None
57+
if abs((sequence[i] - sequence[i - 1]) - ap_diff) > EPS:
58+
is_ap = False
59+
break
60+
61+
if is_ap:
62+
# Format helper
63+
val = ap_diff
64+
ap_diff_str = str(int(round(val))) if abs(val - round(val)) < 1e-9 else f"{val:.6g}"
65+
matched_types.append(f"AP (common difference d = {ap_diff_str})")
66+
67+
# 2. Check GP (Geometric Progression)
68+
is_gp = True
69+
gp_ratio = 0.0
70+
if all(abs(x) <= EPS for x in sequence):
71+
gp_ratio = 0.0
72+
elif any(abs(sequence[i - 1]) <= EPS for i in range(1, len(sequence))):
73+
is_gp = False
74+
else:
75+
gp_ratio = sequence[1] / sequence[0]
76+
for i in range(2, len(sequence)):
77+
if abs((sequence[i] / sequence[i - 1]) - gp_ratio) > EPS:
78+
is_gp = False
79+
break
5580

56-
reciprocal = [1 / value for value in sequence]
57-
is_ap, reciprocal_diff = check_ap(reciprocal)
58-
if not is_ap:
59-
return False, None
81+
if is_gp:
82+
val = gp_ratio
83+
gp_ratio_str = str(int(round(val))) if abs(val - round(val)) < 1e-9 else f"{val:.6g}"
84+
matched_types.append(f"GP (common ratio r = {gp_ratio_str})")
6085

61-
return True, reciprocal_diff
86+
# 3. Check HP (Harmonic Progression)
87+
is_hp = True
88+
hp_diff = 0.0
89+
if any(abs(x) <= EPS for x in sequence):
90+
is_hp = False
91+
else:
92+
reciprocal = [1.0 / x for x in sequence]
93+
hp_diff = reciprocal[1] - reciprocal[0]
94+
for i in range(2, len(reciprocal)):
95+
if abs((reciprocal[i] - reciprocal[i - 1]) - hp_diff) > EPS:
96+
is_hp = False
97+
break
6298

99+
if is_hp:
100+
val = hp_diff
101+
hp_diff_str = str(int(round(val))) if abs(val - round(val)) < 1e-9 else f"{val:.6g}"
102+
matched_types.append(f"HP (reciprocal AP difference = {hp_diff_str})")
63103

64-
def agp_candidates(sequence):
104+
# 4. Check AGP (Arithmetico-Geometric Progression)
105+
is_agp = False
106+
agp_ratio = 0.0
107+
108+
# Generate AGP ratio candidates
65109
s0, s1, s2 = sequence[0], sequence[1], sequence[2]
66-
67-
if is_close(s0, 0.0):
68-
if is_close(s1, 0.0):
69-
return []
70-
return [s2 / (2 * s1)]
71-
72-
a = s0
73-
b = -2 * s1
74-
c = s2
75-
disc = b * b - 4 * a * c
76-
77-
if disc < -EPS:
78-
return []
79-
80-
if is_close(disc, 0.0):
81-
return [-b / (2 * a)]
82-
83-
if disc < 0:
84-
return []
85-
86-
sqrt_disc = disc ** 0.5
87-
r1 = (-b + sqrt_disc) / (2 * a)
88-
r2 = (-b - sqrt_disc) / (2 * a)
89-
90-
if is_close(r1, r2):
91-
return [r1]
92-
93-
return [r1, r2]
94-
95-
96-
def check_agp(sequence):
97-
for ratio in agp_candidates(sequence):
110+
candidates = []
111+
if abs(s0) <= EPS:
112+
if abs(s1) > EPS:
113+
candidates.append(s2 / (2 * s1))
114+
else:
115+
a = s0
116+
b = -2 * s1
117+
c = s2
118+
disc = b * b - 4 * a * c
119+
if disc >= -EPS:
120+
if abs(disc) <= EPS:
121+
candidates.append(-b / (2 * a))
122+
else:
123+
sqrt_disc = math.sqrt(disc)
124+
candidates.append((-b + sqrt_disc) / (2 * a))
125+
candidates.append((-b - sqrt_disc) / (2 * a))
126+
127+
for r in candidates:
98128
valid = True
99129
for i in range(2, len(sequence)):
100-
expected = 2 * ratio * sequence[i - 1] - (ratio * ratio) * sequence[i - 2]
101-
if not is_close(sequence[i], expected, eps=1e-7):
130+
expected = 2 * r * sequence[i - 1] - (r * r) * sequence[i - 2]
131+
if abs(sequence[i] - expected) > 1e-7:
102132
valid = False
103133
break
104134
if valid:
105-
return True, ratio
106-
107-
return False, None
108-
109-
110-
def format_number(value):
111-
if is_close(value, round(value)):
112-
return str(int(round(value)))
113-
return f"{value:.6g}"
114-
115-
116-
while True:
117-
print("\nChoose an option:")
118-
print("1. Recognize sequence type")
119-
print("2. Exit")
120-
121-
choice = input("Enter your choice (1-2): ").strip()
122-
123-
if choice == "2":
124-
print("\nThanks for using the recognizer. Keep practicing! ✨")
125-
break
126-
127-
if choice != "1":
128-
print("Please choose 1 or 2.")
129-
continue
130-
131-
user_input = input("\nEnter sequence values separated by commas: ")
132-
sequence, error = parse_sequence(user_input)
133-
134-
if error:
135-
print(f"❌ {error}")
136-
continue
137-
138-
matched_types = []
139-
140-
ap_ok, ap_diff = check_ap(sequence)
141-
if ap_ok:
142-
matched_types.append(f"AP (common difference d = {format_number(ap_diff)})")
143-
144-
gp_ok, gp_ratio = check_gp(sequence)
145-
if gp_ok:
146-
matched_types.append(f"GP (common ratio r = {format_number(gp_ratio)})")
147-
148-
agp_ok, agp_ratio = check_agp(sequence)
149-
if agp_ok:
150-
matched_types.append(f"AGP (repetition ratio r = {format_number(agp_ratio)})")
135+
is_agp = True
136+
agp_ratio = r
137+
break
151138

152-
hp_ok, hp_diff = check_hp(sequence)
153-
if hp_ok:
154-
matched_types.append(
155-
f"HP (reciprocal AP difference = {format_number(hp_diff)})"
156-
)
139+
if is_agp:
140+
val = agp_ratio
141+
agp_ratio_str = str(int(round(val))) if abs(val - round(val)) < 1e-9 else f"{val:.6g}"
142+
matched_types.append(f"AGP (repetition ratio r = {agp_ratio_str})")
157143

158-
print("\nResult")
144+
# Display Results
145+
print("\n💡 Result")
159146
print("-" * 58)
160-
print("Sequence:", ", ".join(format_number(x) for x in sequence))
147+
formatted_seq = []
148+
for x in sequence:
149+
f_str = str(int(round(x))) if abs(x - round(x)) < 1e-9 else f"{x:.6g}"
150+
formatted_seq.append(f_str)
151+
print("Sequence:", ", ".join(formatted_seq))
161152

162153
if matched_types:
163154
print("✅ Recognized as:")
Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,56 @@
1-
class ArmstrongChecker:
2-
3-
def __init__(self, num):
4-
self.num = num
5-
self.original_num = num
6-
self.num_digits = len(str(num))
7-
self.total = 0
8-
9-
def calculate(self):
10-
temp = self.num
11-
12-
while temp > 0:
13-
digit = temp % 10
14-
self.total += digit ** self.num_digits
15-
temp //= 10
16-
17-
def show_calculation(self):
18-
temp = self.original_num
19-
digits = []
20-
21-
while temp > 0:
22-
digits.append(temp % 10)
23-
temp //= 10
24-
25-
digits.reverse()
1+
print("=" * 50)
2+
print("🔢 ARMSTRONG NUMBER CHECKER 🔢")
3+
print("=" * 50)
4+
print("An Armstrong number equals the sum of its digits raised to the power of number of digits.")
5+
print("Example: 153 = 1³ + 5³ + 3³ = 1 + 125 + 27 = 153\n")
266

27-
calculation_parts = [f"{d}^{self.num_digits}" for d in digits]
7+
while True:
8+
print("=" * 50)
9+
try:
10+
user_input = input("➡️ Enter a positive number to check: ").strip()
11+
if not user_input:
12+
print("❌ Error: Input cannot be empty.")
13+
continue
14+
15+
num = int(user_input)
16+
if num < 0:
17+
print("❌ Please enter a positive number!")
18+
continue
19+
20+
num_str = str(num)
21+
num_digits = len(num_str)
22+
total = 0
23+
24+
# Calculate sum of digits raised to power of num_digits
25+
for char in num_str:
26+
total += int(char) ** num_digits
27+
28+
print(f"\n📊 Number: {num}")
29+
print(f"📐 Number of digits: {num_digits}")
30+
print(f"\n🔍 Calculation:")
31+
32+
calculation_parts = [f"{char}^{num_digits}" for char in num_str]
2833
print(f" {' + '.join(calculation_parts)}")
29-
30-
values = [f"{d**self.num_digits}" for d in digits]
34+
35+
values = [f"{int(char)**num_digits}" for char in num_str]
3136
print(f" = {' + '.join(values)}")
32-
print(f" = {self.total}")
33-
34-
def check(self):
35-
self.calculate()
36-
37-
print(f"\n📊 Number: {self.original_num}")
38-
print(f"📐 Number of digits: {self.num_digits}")
39-
40-
print(f"\n🔍 Calculation:")
41-
self.show_calculation()
42-
43-
if self.total == self.original_num:
44-
print(f"\n{self.original_num} is an Armstrong Number! 🎉")
45-
else:
46-
print(f"\n{self.original_num} is NOT an Armstrong Number.")
37+
print(f" = {total}")
4738

39+
if total == num:
40+
print(f"\n{num} is an Armstrong Number! 🎉")
41+
else:
42+
print(f"\n{num} is NOT an Armstrong Number.")
43+
4844
print("\n💡 Some Armstrong Numbers:")
4945
print(" 1-digit: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9")
5046
print(" 3-digit: 153, 370, 371, 407")
5147
print(" 4-digit: 1634, 8208, 9474")
5248

53-
54-
print("🔢 Armstrong Number Checker 🔢")
55-
print("An Armstrong number equals the sum of its digits raised to the power of number of digits")
56-
print("Example: 153 = 1³ + 5³ + 3³ = 1 + 125 + 27 = 153\n")
57-
58-
while True:
59-
try:
60-
num = int(input("➡️ Enter a number to check: "))
61-
break
6249
except ValueError:
63-
print("⚠️ Oops! That doesn't look like a valid number. Please try again.\n")
50+
print("⚠️ Oops! That doesn't look like a valid integer. Please try again.\n")
51+
continue
6452

65-
if num < 0:
66-
print("❌ Please enter a positive number!")
67-
else:
68-
checker = ArmstrongChecker(num)
69-
checker.check()
53+
again = input("\n🔄 Do you want to check another number? (y/n): ").strip().lower()
54+
if again != 'y':
55+
print("\n👋 Thanks for using Armstrong Number Checker! Goodbye!\n")
56+
break

0 commit comments

Comments
 (0)