algreduce 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- algreduce/__init__.py +0 -0
- algreduce/algreduce.py +839 -0
- algreduce/cubic_cli.py +36 -0
- algreduce/cubic_solver.py +784 -0
- algreduce/quadratic_cli.py +32 -0
- algreduce/quadratic_solver.py +48 -0
- algreduce-1.0.0.dist-info/METADATA +34 -0
- algreduce-1.0.0.dist-info/RECORD +11 -0
- algreduce-1.0.0.dist-info/WHEEL +5 -0
- algreduce-1.0.0.dist-info/licenses/LICENSE.txt +9 -0
- algreduce-1.0.0.dist-info/top_level.txt +1 -0
algreduce/algreduce.py
ADDED
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
# determine whether a radicand is a perfect square
|
|
4
|
+
def is_square(radicand: int) -> bool:
|
|
5
|
+
return round(math.sqrt(radicand)) ** 2 == radicand
|
|
6
|
+
|
|
7
|
+
# simplify squares: √r -> a√b
|
|
8
|
+
def square(radicand: int) -> tuple:
|
|
9
|
+
"""
|
|
10
|
+
return:
|
|
11
|
+
tuple (a, b)
|
|
12
|
+
|
|
13
|
+
examples:
|
|
14
|
+
>>>square(4)
|
|
15
|
+
(2, 1)
|
|
16
|
+
>>>square(8)
|
|
17
|
+
(2, 2)
|
|
18
|
+
>>>square(5)
|
|
19
|
+
(1, 5)
|
|
20
|
+
>>>square(48)
|
|
21
|
+
(4, 3)
|
|
22
|
+
"""
|
|
23
|
+
if is_square(radicand):
|
|
24
|
+
a = round(math.sqrt(radicand))
|
|
25
|
+
b = 1
|
|
26
|
+
|
|
27
|
+
else:
|
|
28
|
+
b = 2
|
|
29
|
+
|
|
30
|
+
while not is_square(radicand/b):
|
|
31
|
+
b += 1
|
|
32
|
+
|
|
33
|
+
a = round(math.sqrt(radicand/b))
|
|
34
|
+
|
|
35
|
+
return (a, b)
|
|
36
|
+
|
|
37
|
+
# calculate the cubic root of radicands
|
|
38
|
+
def cbrt(radicand: float) -> float:
|
|
39
|
+
if radicand >= 0:
|
|
40
|
+
return math.pow(radicand, 1/3)
|
|
41
|
+
|
|
42
|
+
elif radicand < 0:
|
|
43
|
+
return -math.pow(-radicand, 1/3)
|
|
44
|
+
|
|
45
|
+
# determine whether a radicand is a perfect cube
|
|
46
|
+
def is_cube(radicand: int) -> bool:
|
|
47
|
+
return round(cbrt(radicand)) ** 3 == radicand
|
|
48
|
+
|
|
49
|
+
# simplify cubes: ³√r -> a·³√b
|
|
50
|
+
def cube(radicand: int) -> tuple:
|
|
51
|
+
"""
|
|
52
|
+
return:
|
|
53
|
+
tuple (a, b)
|
|
54
|
+
|
|
55
|
+
examples:
|
|
56
|
+
>>>cube(8)
|
|
57
|
+
(2, 1)
|
|
58
|
+
>>>cube(18)
|
|
59
|
+
(1, 18)
|
|
60
|
+
>>>cube(-9)
|
|
61
|
+
(-1, 9)
|
|
62
|
+
>>>cube(24)
|
|
63
|
+
(2, 3)
|
|
64
|
+
"""
|
|
65
|
+
if is_cube(radicand):
|
|
66
|
+
a = round(cbrt(radicand))
|
|
67
|
+
b = 1
|
|
68
|
+
|
|
69
|
+
else:
|
|
70
|
+
b = 2
|
|
71
|
+
|
|
72
|
+
while not is_cube(radicand/b):
|
|
73
|
+
b += 1
|
|
74
|
+
|
|
75
|
+
a = round(cbrt(radicand/b))
|
|
76
|
+
|
|
77
|
+
return (a, b)
|
|
78
|
+
|
|
79
|
+
# simplify fractions
|
|
80
|
+
def fraction(numerator: int, denominator: int) -> str:
|
|
81
|
+
"""
|
|
82
|
+
simplify and format mathematical expressions as strings
|
|
83
|
+
|
|
84
|
+
parameters:
|
|
85
|
+
numerator: the numerator of the fraction
|
|
86
|
+
denominator: the denominator of the fraction
|
|
87
|
+
|
|
88
|
+
return:
|
|
89
|
+
formatted string of the mathematical expression
|
|
90
|
+
|
|
91
|
+
examples:
|
|
92
|
+
>>>fraction(5, 7)
|
|
93
|
+
'5/7'
|
|
94
|
+
>>>fraction(10, 4)
|
|
95
|
+
'5/2'
|
|
96
|
+
>>>fraction(3, 9)
|
|
97
|
+
'1/3'
|
|
98
|
+
>>>fraction(8, 2)
|
|
99
|
+
'4'
|
|
100
|
+
"""
|
|
101
|
+
# special cases for 0
|
|
102
|
+
if numerator == 0 and denominator != 0:
|
|
103
|
+
return '0'
|
|
104
|
+
|
|
105
|
+
elif numerator != 0 and denominator == 0:
|
|
106
|
+
return '∞'
|
|
107
|
+
|
|
108
|
+
elif numerator == 0 and denominator == 0:
|
|
109
|
+
return '0/0'
|
|
110
|
+
|
|
111
|
+
else:
|
|
112
|
+
# simplify the fraction into reduced fraction
|
|
113
|
+
gcd = math.gcd(numerator, denominator)
|
|
114
|
+
num = numerator // gcd
|
|
115
|
+
den = denominator // gcd
|
|
116
|
+
|
|
117
|
+
# n/1 -> n
|
|
118
|
+
if den == 1:
|
|
119
|
+
return f'{num}'
|
|
120
|
+
|
|
121
|
+
# n/-1 -> -n
|
|
122
|
+
elif den == -1:
|
|
123
|
+
return f'{-num}'
|
|
124
|
+
|
|
125
|
+
# n/d -> n/|d|
|
|
126
|
+
elif den > 0:
|
|
127
|
+
return f'{num}/{den}'
|
|
128
|
+
|
|
129
|
+
# n/d -> -n/|d|
|
|
130
|
+
elif den < 0:
|
|
131
|
+
return f'{-num}/{-den}'
|
|
132
|
+
|
|
133
|
+
# simplify fractions contain square root
|
|
134
|
+
def sqfrac(rational: int, radicand: int, denominator: int, is_minus: bool=False) -> str:
|
|
135
|
+
"""
|
|
136
|
+
simplify and format fractions with square root
|
|
137
|
+
|
|
138
|
+
parameters:
|
|
139
|
+
rational: the integer in numerator of the fraction
|
|
140
|
+
radicand: the radicand in numerator of the fraction
|
|
141
|
+
denominator: the denominator of the fraction
|
|
142
|
+
is_minus: change the '+' between rational and radicand into '-' (default as False)
|
|
143
|
+
|
|
144
|
+
return:
|
|
145
|
+
formatted string of the mathematical expression
|
|
146
|
+
|
|
147
|
+
examples:
|
|
148
|
+
>>>sqfrac(2, 3, 1)
|
|
149
|
+
'2+√3'
|
|
150
|
+
>>>sqfrac(1, 9, 1)
|
|
151
|
+
'4'
|
|
152
|
+
>>>sqfrac(3, 8, 3, True)
|
|
153
|
+
'(3-2√2)/3'
|
|
154
|
+
>>>sqfrac(1, 0, 2)
|
|
155
|
+
'1/2'
|
|
156
|
+
>>>sqfrac(0, -4, 2, True)
|
|
157
|
+
'-i'
|
|
158
|
+
"""
|
|
159
|
+
# format the reduced fraction
|
|
160
|
+
def formal(expression: str) -> str:
|
|
161
|
+
if cef == 1:
|
|
162
|
+
# 1√1/den -> 1/den
|
|
163
|
+
if rdc == 1:
|
|
164
|
+
if radicand < 0:
|
|
165
|
+
expression = expression.replace('1√1', '')
|
|
166
|
+
|
|
167
|
+
else:
|
|
168
|
+
expression = expression.replace('√1', '')
|
|
169
|
+
|
|
170
|
+
# 1√rdc/den -> √rdc/den
|
|
171
|
+
else:
|
|
172
|
+
expression = expression.replace('1√', '√')
|
|
173
|
+
|
|
174
|
+
else:
|
|
175
|
+
# cef√1/den -> cef/den
|
|
176
|
+
if rdc == 1:
|
|
177
|
+
expression = expression.replace('√1', '')
|
|
178
|
+
|
|
179
|
+
# cef√rdc/den
|
|
180
|
+
else:
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
return expression
|
|
184
|
+
|
|
185
|
+
# ± √radicand / denominator
|
|
186
|
+
if rational == 0:
|
|
187
|
+
# fraction is a real number
|
|
188
|
+
if radicand > 0:
|
|
189
|
+
rdc = square(radicand)[1]
|
|
190
|
+
gcd = math.gcd(square(radicand)[0], denominator)
|
|
191
|
+
cef = square(radicand)[0] // gcd
|
|
192
|
+
den = denominator // gcd
|
|
193
|
+
|
|
194
|
+
if den == 1:
|
|
195
|
+
if is_minus:
|
|
196
|
+
return formal(f'{-cef}√{rdc}')
|
|
197
|
+
|
|
198
|
+
else:
|
|
199
|
+
return formal(f'{cef}√{rdc}')
|
|
200
|
+
|
|
201
|
+
elif den == -1:
|
|
202
|
+
if is_minus:
|
|
203
|
+
return formal(f'{cef}√{rdc}')
|
|
204
|
+
|
|
205
|
+
else:
|
|
206
|
+
return formal(f'{-cef}√{rdc}')
|
|
207
|
+
|
|
208
|
+
elif den > 0:
|
|
209
|
+
if is_minus:
|
|
210
|
+
return formal(f'{-cef}√{rdc}/{den}')
|
|
211
|
+
|
|
212
|
+
else:
|
|
213
|
+
return formal(f'{cef}√{rdc}/{den}')
|
|
214
|
+
|
|
215
|
+
elif den < 0:
|
|
216
|
+
if is_minus:
|
|
217
|
+
return formal(f'{cef}√{rdc}/{-den}')
|
|
218
|
+
|
|
219
|
+
else:
|
|
220
|
+
return formal(f'{-cef}√{rdc}/{-den}')
|
|
221
|
+
|
|
222
|
+
# fraction is a complex number
|
|
223
|
+
elif radicand < 0:
|
|
224
|
+
rdc = square(-radicand)[1]
|
|
225
|
+
gcd = math.gcd(square(-radicand)[0], denominator)
|
|
226
|
+
cef = square(-radicand)[0] // gcd
|
|
227
|
+
den = denominator // gcd
|
|
228
|
+
|
|
229
|
+
if den == 1:
|
|
230
|
+
if is_minus:
|
|
231
|
+
return formal(f'{-cef}√{rdc}i')
|
|
232
|
+
|
|
233
|
+
else:
|
|
234
|
+
return formal(f'{cef}√{rdc}i')
|
|
235
|
+
|
|
236
|
+
elif den == -1:
|
|
237
|
+
if is_minus:
|
|
238
|
+
return formal(f'{cef}√{rdc}i')
|
|
239
|
+
|
|
240
|
+
else:
|
|
241
|
+
return formal(f'{-cef}√{rdc}i')
|
|
242
|
+
|
|
243
|
+
elif den > 0:
|
|
244
|
+
if is_minus:
|
|
245
|
+
return formal(f'{-cef}√{rdc}i/{den}')
|
|
246
|
+
|
|
247
|
+
else:
|
|
248
|
+
return formal(f'{cef}√{rdc}i/{den}')
|
|
249
|
+
|
|
250
|
+
elif den < 0:
|
|
251
|
+
if is_minus:
|
|
252
|
+
return formal(f'{cef}√{rdc}i/{-den}')
|
|
253
|
+
|
|
254
|
+
else:
|
|
255
|
+
return formal(f'{-cef}√{rdc}i/{-den}')
|
|
256
|
+
|
|
257
|
+
# case for 0
|
|
258
|
+
else:
|
|
259
|
+
return '0'
|
|
260
|
+
|
|
261
|
+
# (rational ± √radicand) / denominator
|
|
262
|
+
else:
|
|
263
|
+
# fraction is a real number
|
|
264
|
+
if radicand > 0:
|
|
265
|
+
# num / den
|
|
266
|
+
if is_square(radicand):
|
|
267
|
+
if is_minus:
|
|
268
|
+
numerator = rational - square(radicand)[0]
|
|
269
|
+
|
|
270
|
+
else:
|
|
271
|
+
numerator = rational + square(radicand)[0]
|
|
272
|
+
|
|
273
|
+
return fraction(numerator, denominator)
|
|
274
|
+
|
|
275
|
+
# (rtn ± √rdc) / den
|
|
276
|
+
else:
|
|
277
|
+
fct = math.gcd(rational, square(radicand)[0])
|
|
278
|
+
gcd = math.gcd(fct, denominator)
|
|
279
|
+
rtn = rational // gcd
|
|
280
|
+
cef = square(radicand)[0] // gcd
|
|
281
|
+
rdc = square(radicand)[1]
|
|
282
|
+
den = denominator // gcd
|
|
283
|
+
|
|
284
|
+
if den == 1:
|
|
285
|
+
if is_minus:
|
|
286
|
+
return formal(f'{rtn}-{cef}√{rdc}')
|
|
287
|
+
|
|
288
|
+
else:
|
|
289
|
+
return formal(f'{rtn}+{cef}√{rdc}')
|
|
290
|
+
|
|
291
|
+
elif den == -1:
|
|
292
|
+
if is_minus:
|
|
293
|
+
return formal(f'{-rtn}+{cef}√{rdc}')
|
|
294
|
+
|
|
295
|
+
else:
|
|
296
|
+
return formal(f'{-rtn}-{cef}√{rdc}')
|
|
297
|
+
|
|
298
|
+
elif den > 0:
|
|
299
|
+
if is_minus:
|
|
300
|
+
return formal(f'({rtn}-{cef}√{rdc})/{den}')
|
|
301
|
+
|
|
302
|
+
else:
|
|
303
|
+
return formal(f'({rtn}+{cef}√{rdc})/{den}')
|
|
304
|
+
|
|
305
|
+
elif den < 0:
|
|
306
|
+
if is_minus:
|
|
307
|
+
return formal(f'({-rtn}+{cef}√{rdc})/{-den}')
|
|
308
|
+
|
|
309
|
+
else:
|
|
310
|
+
return formal(f'({-rtn}-{cef}√{rdc})/{-den}')
|
|
311
|
+
|
|
312
|
+
# fraction is a complex number
|
|
313
|
+
elif radicand < 0:
|
|
314
|
+
fct = math.gcd(rational, square(-radicand)[0])
|
|
315
|
+
gcd = math.gcd(fct, denominator)
|
|
316
|
+
rtn = rational // gcd
|
|
317
|
+
cef = square(-radicand)[0] // gcd
|
|
318
|
+
rdc = square(-radicand)[1]
|
|
319
|
+
den = denominator // gcd
|
|
320
|
+
|
|
321
|
+
if den == 1:
|
|
322
|
+
if is_minus:
|
|
323
|
+
return formal(f'{rtn}-{cef}√{rdc}i')
|
|
324
|
+
|
|
325
|
+
else:
|
|
326
|
+
return formal(f'{rtn}+{cef}√{rdc}i')
|
|
327
|
+
|
|
328
|
+
elif den == -1:
|
|
329
|
+
if is_minus:
|
|
330
|
+
return formal(f'{-rtn}+{cef}√{rdc}i')
|
|
331
|
+
|
|
332
|
+
else:
|
|
333
|
+
return formal(f'{-rtn}-{cef}√{rdc}i')
|
|
334
|
+
|
|
335
|
+
elif den > 0:
|
|
336
|
+
if is_minus:
|
|
337
|
+
return formal(f'({rtn}-{cef}√{rdc}i)/{den}')
|
|
338
|
+
|
|
339
|
+
else:
|
|
340
|
+
return formal(f'({rtn}+{cef}√{rdc}i)/{den}')
|
|
341
|
+
|
|
342
|
+
elif den < 0:
|
|
343
|
+
if is_minus:
|
|
344
|
+
return formal(f'({-rtn}+{cef}√{rdc}i)/{-den}')
|
|
345
|
+
|
|
346
|
+
else:
|
|
347
|
+
return formal(f'({-rtn}-{cef}√{rdc}i)/{-den}')
|
|
348
|
+
|
|
349
|
+
# rational / denominator
|
|
350
|
+
else:
|
|
351
|
+
return fraction(rational, denominator)
|
|
352
|
+
|
|
353
|
+
# simplify fractions contain cubic root which contains square root
|
|
354
|
+
def cbfrac(rational: int, radicand: int, denominator: int, is_minus: bool=False) -> str:
|
|
355
|
+
"""
|
|
356
|
+
simplify fractions with cubic root
|
|
357
|
+
|
|
358
|
+
parameters:
|
|
359
|
+
rational: the integer in numerator of the fraction
|
|
360
|
+
radicand: the radicand in numerator of the fraction
|
|
361
|
+
denominator: the denominator of the fraction
|
|
362
|
+
is_minus: change the '+' between rational and radicand into '-' (default as False)
|
|
363
|
+
|
|
364
|
+
return:
|
|
365
|
+
formatted string of the mathematical expression
|
|
366
|
+
|
|
367
|
+
examples:
|
|
368
|
+
>>>cbfrac(3, 5, 1)
|
|
369
|
+
'³√(3+√5)'
|
|
370
|
+
>>>cbfrac(15, 1, 2)
|
|
371
|
+
'³√2'
|
|
372
|
+
>>>cbfrac(0, -3, 3)
|
|
373
|
+
'-⁶√3i/3'
|
|
374
|
+
>>>cbfrac(9, 1, 5, True)
|
|
375
|
+
'2/5'
|
|
376
|
+
>>>cbfrac(7, -4, 3, True)
|
|
377
|
+
'³√(7-2i)/3'
|
|
378
|
+
"""
|
|
379
|
+
# format the cubic root
|
|
380
|
+
def sformal(expression: str) -> str:
|
|
381
|
+
if num == 1 or num == -1:
|
|
382
|
+
# 1·³√1/den -> 1/den, 1·⁶√1/den -> 1/den
|
|
383
|
+
if rdc == 1:
|
|
384
|
+
if radicand < 0:
|
|
385
|
+
expression = expression.replace('1·³√1', '').replace('1·⁶√1', '')
|
|
386
|
+
|
|
387
|
+
else:
|
|
388
|
+
expression = expression.replace('·³√1', '').replace('·⁶√1', '')
|
|
389
|
+
|
|
390
|
+
# 1·³√rdc/den -> ³√rdc/den, 1·⁶√rdc/den -> ⁶√rdc/den
|
|
391
|
+
else:
|
|
392
|
+
expression = expression.replace('1·³√', '³√').replace('1·⁶√', '⁶√')
|
|
393
|
+
|
|
394
|
+
else:
|
|
395
|
+
# num·³√1/den -> num/den, num·⁶√1/den -> num/den
|
|
396
|
+
if rdc == 1:
|
|
397
|
+
expression = expression.replace('·³√1', '').replace('·⁶√1', '')
|
|
398
|
+
|
|
399
|
+
# num·³√rdc/den, num·⁶√rdc/den
|
|
400
|
+
else:
|
|
401
|
+
pass
|
|
402
|
+
|
|
403
|
+
return expression
|
|
404
|
+
|
|
405
|
+
# format the cubic root and square root
|
|
406
|
+
def cformal(expression: str) -> str:
|
|
407
|
+
# 1·³√rdc/den -> ³√rdc/den, 1·⁶√rdc/den -> ⁶√rdc/den
|
|
408
|
+
if num == 1 or num == -1:
|
|
409
|
+
expression = expression.replace('1·³√', '³√')
|
|
410
|
+
|
|
411
|
+
if cef == 1:
|
|
412
|
+
# rtn ± 1√1 -> rtn ± 1
|
|
413
|
+
if rdc == 1:
|
|
414
|
+
if radicand < 0:
|
|
415
|
+
expression = expression.replace('1√1', '')
|
|
416
|
+
|
|
417
|
+
else:
|
|
418
|
+
expression = expression.replace('1√1', '1')
|
|
419
|
+
|
|
420
|
+
# rtn ± 1√rdc -> rtn ± √rdc
|
|
421
|
+
else:
|
|
422
|
+
expression = expression.replace('1√', '√')
|
|
423
|
+
|
|
424
|
+
else:
|
|
425
|
+
# rtn ± cef√1 -> rtn ± cef
|
|
426
|
+
if rdc == 1:
|
|
427
|
+
expression = expression.replace(f'{cef}√1', f'{cef}')
|
|
428
|
+
|
|
429
|
+
# rtn ± cef√rdc
|
|
430
|
+
else:
|
|
431
|
+
pass
|
|
432
|
+
|
|
433
|
+
return expression
|
|
434
|
+
|
|
435
|
+
# ± ⁶√radicand / denominator
|
|
436
|
+
if rational == 0:
|
|
437
|
+
# fraction is a real number
|
|
438
|
+
if radicand > 0:
|
|
439
|
+
if is_minus:
|
|
440
|
+
fct = -square(radicand)[0]
|
|
441
|
+
|
|
442
|
+
else:
|
|
443
|
+
fct = square(radicand)[0]
|
|
444
|
+
|
|
445
|
+
# num·³√rdc / den
|
|
446
|
+
if is_square(radicand):
|
|
447
|
+
rdc = cube(fct)[1]
|
|
448
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
449
|
+
num = cube(fct)[0] // gcd
|
|
450
|
+
den = denominator // gcd
|
|
451
|
+
|
|
452
|
+
if den == 1:
|
|
453
|
+
return sformal(f'{num}·³√{rdc}')
|
|
454
|
+
|
|
455
|
+
elif den == -1:
|
|
456
|
+
return sformal(f'{-num}·³√{rdc}')
|
|
457
|
+
|
|
458
|
+
elif den > 0:
|
|
459
|
+
return sformal(f'{num}·³√{rdc}/{den}')
|
|
460
|
+
|
|
461
|
+
elif den < 0:
|
|
462
|
+
return sformal(f'{-num}·³√{rdc}/{-den}')
|
|
463
|
+
|
|
464
|
+
# num·⁶√rdc / den
|
|
465
|
+
else:
|
|
466
|
+
rdc = square(radicand)[1] * cube(fct)[1] ** 2
|
|
467
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
468
|
+
num = cube(fct)[0] // gcd
|
|
469
|
+
den = denominator // gcd
|
|
470
|
+
|
|
471
|
+
if den == 1:
|
|
472
|
+
return sformal(f'{num}·⁶√{rdc}')
|
|
473
|
+
|
|
474
|
+
elif den == -1:
|
|
475
|
+
return sformal(f'{-num}·⁶√{rdc}')
|
|
476
|
+
|
|
477
|
+
elif den > 0:
|
|
478
|
+
return sformal(f'{num}·⁶√{rdc}/{den}')
|
|
479
|
+
|
|
480
|
+
elif den < 0:
|
|
481
|
+
return sformal(f'{-num}·⁶√{rdc}/{-den}')
|
|
482
|
+
|
|
483
|
+
# fraction is a complex number
|
|
484
|
+
if radicand < 0:
|
|
485
|
+
if is_minus:
|
|
486
|
+
fct = square(-radicand)[0]
|
|
487
|
+
|
|
488
|
+
else:
|
|
489
|
+
fct = -square(-radicand)[0]
|
|
490
|
+
|
|
491
|
+
# num·³√rdc*i / den
|
|
492
|
+
if is_square(-radicand):
|
|
493
|
+
rdc = cube(fct)[1]
|
|
494
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
495
|
+
num = cube(fct)[0] // gcd
|
|
496
|
+
den = denominator // gcd
|
|
497
|
+
|
|
498
|
+
if den == 1:
|
|
499
|
+
return sformal(f'{num}·³√{rdc}i')
|
|
500
|
+
|
|
501
|
+
elif den == -1:
|
|
502
|
+
return sformal(f'{-num}·³√{rdc}i')
|
|
503
|
+
|
|
504
|
+
elif den > 0:
|
|
505
|
+
return sformal(f'{num}·³√{rdc}i/{den}')
|
|
506
|
+
|
|
507
|
+
elif den < 0:
|
|
508
|
+
return sformal(f'{-num}·³√{rdc}i/{-den}')
|
|
509
|
+
|
|
510
|
+
# num·⁶√rdc*i / den
|
|
511
|
+
else:
|
|
512
|
+
rdc = square(-radicand)[1] * cube(fct)[1] ** 2
|
|
513
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
514
|
+
num = cube(fct)[0] // gcd
|
|
515
|
+
den = denominator // gcd
|
|
516
|
+
|
|
517
|
+
if den == 1:
|
|
518
|
+
return sformal(f'{num}·⁶√{rdc}i')
|
|
519
|
+
|
|
520
|
+
elif den == -1:
|
|
521
|
+
return sformal(f'{-num}·⁶√{rdc}i')
|
|
522
|
+
|
|
523
|
+
elif den > 0:
|
|
524
|
+
return sformal(f'{num}·⁶√{rdc}i/{den}')
|
|
525
|
+
|
|
526
|
+
elif den < 0:
|
|
527
|
+
return sformal(f'{-num}·⁶√{rdc}i/{-den}')
|
|
528
|
+
|
|
529
|
+
# case for 0
|
|
530
|
+
else:
|
|
531
|
+
return '0'
|
|
532
|
+
|
|
533
|
+
# ³√(rational ± √radicand) / denominator
|
|
534
|
+
else:
|
|
535
|
+
# fraction is a real number
|
|
536
|
+
if radicand > 0:
|
|
537
|
+
# num·³√rdc / den
|
|
538
|
+
if is_square(radicand):
|
|
539
|
+
if is_minus:
|
|
540
|
+
rtn = rational - square(radicand)[0]
|
|
541
|
+
|
|
542
|
+
else:
|
|
543
|
+
rtn = rational + square(radicand)[0]
|
|
544
|
+
|
|
545
|
+
rdc = cube(rtn)[1]
|
|
546
|
+
gcd = math.gcd(cube(rtn)[0], denominator)
|
|
547
|
+
num = cube(rtn)[0] // gcd
|
|
548
|
+
den = denominator // gcd
|
|
549
|
+
|
|
550
|
+
if den == 1:
|
|
551
|
+
return sformal(f'{num}·³√{rdc}')
|
|
552
|
+
|
|
553
|
+
elif den == -1:
|
|
554
|
+
return sformal(f'{-num}·³√{rdc}')
|
|
555
|
+
|
|
556
|
+
elif den > 0:
|
|
557
|
+
return sformal(f'{num}·³√{rdc}/{den}')
|
|
558
|
+
|
|
559
|
+
elif den < 0:
|
|
560
|
+
return sformal(f'{-num}·³√{rdc}/{-den}')
|
|
561
|
+
|
|
562
|
+
# ³√(rtn ± cef√rdc) / den
|
|
563
|
+
else:
|
|
564
|
+
rdc = square(radicand)[1]
|
|
565
|
+
fct = math.gcd(rational, square(radicand)[0])
|
|
566
|
+
rtn = rational * cube(fct)[1] // fct
|
|
567
|
+
cef = square(radicand)[0] * cube(fct)[1] // fct
|
|
568
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
569
|
+
num = cube(fct)[0] // gcd
|
|
570
|
+
den = denominator // gcd
|
|
571
|
+
|
|
572
|
+
if den == 1:
|
|
573
|
+
if is_minus:
|
|
574
|
+
return cformal(f'{num}·³√({rtn}-{cef}√{rdc})')
|
|
575
|
+
|
|
576
|
+
else:
|
|
577
|
+
return cformal(f'{num}·³√({rtn}+{cef}√{rdc})')
|
|
578
|
+
|
|
579
|
+
elif den == -1:
|
|
580
|
+
if is_minus:
|
|
581
|
+
return cformal(f'{-num}·³√({rtn}-{cef}√{rdc})')
|
|
582
|
+
|
|
583
|
+
else:
|
|
584
|
+
return cformal(f'{-num}·³√({rtn}+{cef}√{rdc})')
|
|
585
|
+
|
|
586
|
+
elif den > 0:
|
|
587
|
+
if is_minus:
|
|
588
|
+
return cformal(f'{num}·³√({rtn}-{cef}√{rdc})/{den}')
|
|
589
|
+
|
|
590
|
+
else:
|
|
591
|
+
return cformal(f'{num}·³√({rtn}+{cef}√{rdc})/{den}')
|
|
592
|
+
|
|
593
|
+
elif den < 0:
|
|
594
|
+
if is_minus:
|
|
595
|
+
return cformal(f'{-num}·³√({-rtn}-{cef}√{rdc})/{-den}')
|
|
596
|
+
|
|
597
|
+
else:
|
|
598
|
+
return cformal(f'{-num}·³√({-rtn}+{cef}√{rdc})/{-den}')
|
|
599
|
+
|
|
600
|
+
# fraction is a complex number
|
|
601
|
+
elif radicand < 0:
|
|
602
|
+
# ³√(rtn ± cef√rdc*i) / den
|
|
603
|
+
rdc = square(-radicand)[1]
|
|
604
|
+
fct = math.gcd(rational, square(-radicand)[0])
|
|
605
|
+
rtn = rational * cube(fct)[1] // fct
|
|
606
|
+
cef = square(-radicand)[0] * cube(fct)[1] // fct
|
|
607
|
+
gcd = math.gcd(cube(fct)[0], denominator)
|
|
608
|
+
num = cube(fct)[0] // gcd
|
|
609
|
+
den = denominator // gcd
|
|
610
|
+
|
|
611
|
+
if den == 1:
|
|
612
|
+
if is_minus:
|
|
613
|
+
return cformal(f'{num}·³√({rtn}-{cef}√{rdc}i)')
|
|
614
|
+
|
|
615
|
+
else:
|
|
616
|
+
return cformal(f'{num}·³√({rtn}+{cef}√{rdc}i)')
|
|
617
|
+
|
|
618
|
+
elif den == -1:
|
|
619
|
+
if is_minus:
|
|
620
|
+
return cformal(f'{-num}·³√({rtn}-{cef}√{rdc}i)')
|
|
621
|
+
|
|
622
|
+
else:
|
|
623
|
+
return cformal(f'{-num}·³√({rtn}+{cef}√{rdc}i)')
|
|
624
|
+
|
|
625
|
+
elif den > 0:
|
|
626
|
+
if is_minus:
|
|
627
|
+
return cformal(f'{num}·³√({rtn}-{cef}√{rdc}i)/{den}')
|
|
628
|
+
|
|
629
|
+
else:
|
|
630
|
+
return cformal(f'{num}·³√({rtn}+{cef}√{rdc}i)/{den}')
|
|
631
|
+
|
|
632
|
+
elif den < 0:
|
|
633
|
+
if is_minus:
|
|
634
|
+
return cformal(f'{-num}·³√({-rtn}-{cef}√{rdc}i)/{-den}')
|
|
635
|
+
|
|
636
|
+
else:
|
|
637
|
+
return cformal(f'{-num}·³√({-rtn}+{cef}√{rdc}i)/{-den}')
|
|
638
|
+
|
|
639
|
+
# ³√rational / denominator
|
|
640
|
+
else:
|
|
641
|
+
rdc = cube(rational)[1]
|
|
642
|
+
gcd = math.gcd(cube(rational)[0], denominator)
|
|
643
|
+
num = cube(rational)[0] // gcd
|
|
644
|
+
den = denominator // gcd
|
|
645
|
+
|
|
646
|
+
if den == 1:
|
|
647
|
+
return sformal(f'{num}·³√{rdc}')
|
|
648
|
+
|
|
649
|
+
elif den == -1:
|
|
650
|
+
return sformal(f'{-num}·³√{rdc}')
|
|
651
|
+
|
|
652
|
+
elif den > 0:
|
|
653
|
+
return sformal(f'{num}·³√{rdc}/{den}')
|
|
654
|
+
|
|
655
|
+
elif den < 0:
|
|
656
|
+
return sformal(f'{-num}·³√{rdc}/{-den}')
|
|
657
|
+
|
|
658
|
+
# simplify cubic roots
|
|
659
|
+
def cubic_root(rational: int, radicand: int=0, denominator: int=1, is_minus: bool=False) -> str:
|
|
660
|
+
"""
|
|
661
|
+
automatically simplify and format cubic roots
|
|
662
|
+
|
|
663
|
+
parameters:
|
|
664
|
+
rational: the integer in numerator of the cubic root
|
|
665
|
+
radicand: the radicand in numerator of the cubic root (default as 0)
|
|
666
|
+
denominator: the denominator of the cubic root (default as 1)
|
|
667
|
+
is_minus: change the '+' between rational and radicand into '-' (default as False)
|
|
668
|
+
|
|
669
|
+
return:
|
|
670
|
+
formatted string of the mathematical expression
|
|
671
|
+
|
|
672
|
+
examples:
|
|
673
|
+
>>>cubic_root(5, 3, 8, True)
|
|
674
|
+
'³√(5-√3)/8'
|
|
675
|
+
>>>cubic_root(12)
|
|
676
|
+
'³√12'
|
|
677
|
+
>>>cubic_root(0, -5)
|
|
678
|
+
'-⁶√5i'
|
|
679
|
+
>>>cubic_root(-32, -704)
|
|
680
|
+
'1-√11i'
|
|
681
|
+
>>>cubic_root(-48, -64, 3, True)
|
|
682
|
+
'2·³√(-6-i)/3'
|
|
683
|
+
>>>cubic_root(-64800, 33139243584)
|
|
684
|
+
'-6+6√33·³√3'
|
|
685
|
+
"""
|
|
686
|
+
# ± ⁶√radicand / denominator
|
|
687
|
+
if rational == 0:
|
|
688
|
+
if is_minus:
|
|
689
|
+
return cbfrac(0, radicand, denominator, True)
|
|
690
|
+
|
|
691
|
+
else:
|
|
692
|
+
return cbfrac(0, radicand, denominator)
|
|
693
|
+
|
|
694
|
+
# ³√(rational ± √radicand) / denominator
|
|
695
|
+
else:
|
|
696
|
+
# case for real number
|
|
697
|
+
if radicand > 0:
|
|
698
|
+
fct = math.gcd(rational, square(radicand)[0])
|
|
699
|
+
rtn = rational // fct
|
|
700
|
+
rdc = radicand // fct ** 2
|
|
701
|
+
R1 = (rtn ** 2 - rdc) * (rtn + math.sqrt(rdc))
|
|
702
|
+
R2 = (rtn ** 2 - rdc) * (rtn - math.sqrt(rdc))
|
|
703
|
+
x = round(rtn/4+3*(cbrt(R1)+cbrt(R2))/8)
|
|
704
|
+
|
|
705
|
+
if is_cube(x):
|
|
706
|
+
pass
|
|
707
|
+
|
|
708
|
+
else:
|
|
709
|
+
x = 0
|
|
710
|
+
|
|
711
|
+
R1 = (rational ** 2 - radicand) * (rational + math.sqrt(radicand))
|
|
712
|
+
R2 = (rational ** 2 - radicand) * (rational - math.sqrt(radicand))
|
|
713
|
+
y = round(rational/4+3*(cbrt(R1)+cbrt(R2))/8)
|
|
714
|
+
|
|
715
|
+
if is_cube(y):
|
|
716
|
+
pass
|
|
717
|
+
|
|
718
|
+
else:
|
|
719
|
+
y = 0
|
|
720
|
+
|
|
721
|
+
if x != 0 and is_cube((rtn-x)**3//(27*x)):
|
|
722
|
+
a = cube(fct)[0] * cube(x)[0]
|
|
723
|
+
b = cube(fct)[0] ** 2 * (rtn - x) // (3 * cube(x)[0])
|
|
724
|
+
|
|
725
|
+
if is_cube(fct):
|
|
726
|
+
if is_minus:
|
|
727
|
+
return sqfrac(a, b, denominator, True)
|
|
728
|
+
|
|
729
|
+
else:
|
|
730
|
+
return sqfrac(a, b, denominator)
|
|
731
|
+
|
|
732
|
+
else:
|
|
733
|
+
if is_minus:
|
|
734
|
+
return f'{sqfrac(a, b, denominator, True)}·{cubic_root(cube(fct)[1])}'
|
|
735
|
+
|
|
736
|
+
else:
|
|
737
|
+
return f'{sqfrac(a, b, denominator)}·{cubic_root(cube(fct)[1])}'
|
|
738
|
+
|
|
739
|
+
elif y != 0 and is_cube((rational-y)**3//(27*y)):
|
|
740
|
+
a = cube(y)[0]
|
|
741
|
+
b = (rational - y) // (3 * cube(y)[0])
|
|
742
|
+
|
|
743
|
+
if is_minus:
|
|
744
|
+
return sqfrac(a, b, denominator, True)
|
|
745
|
+
|
|
746
|
+
else:
|
|
747
|
+
return sqfrac(a, b, denominator)
|
|
748
|
+
|
|
749
|
+
else:
|
|
750
|
+
if is_minus:
|
|
751
|
+
return cbfrac(rational, radicand, denominator, True)
|
|
752
|
+
|
|
753
|
+
else:
|
|
754
|
+
return cbfrac(rational, radicand, denominator)
|
|
755
|
+
|
|
756
|
+
# case for complex number
|
|
757
|
+
elif radicand < 0:
|
|
758
|
+
fct = math.gcd(rational, square(-radicand)[0])
|
|
759
|
+
rtn = rational // fct
|
|
760
|
+
rdc = radicand // fct ** 2
|
|
761
|
+
theta = math.atan(math.sqrt(-rdc)/abs(rtn))
|
|
762
|
+
z1 = round(abs(rtn)/4+3*math.sqrt(rtn**2-rdc)*math.cos(theta/3)/4)
|
|
763
|
+
z2 = round(abs(rtn)/4+3*math.sqrt(rtn**2-rdc)*math.cos(theta/3+2*math.pi/3)/4)
|
|
764
|
+
z3 = round(abs(rtn)/4+3*math.sqrt(rtn**2-rdc)*math.cos(theta/3+4*math.pi/3)/4)
|
|
765
|
+
|
|
766
|
+
if is_cube(z1):
|
|
767
|
+
x = z1
|
|
768
|
+
|
|
769
|
+
elif is_cube(z2):
|
|
770
|
+
x = z2
|
|
771
|
+
|
|
772
|
+
elif is_cube(z3):
|
|
773
|
+
x = z3
|
|
774
|
+
|
|
775
|
+
else:
|
|
776
|
+
x = 0
|
|
777
|
+
|
|
778
|
+
theta = math.atan(math.sqrt(-radicand)/abs(rational))
|
|
779
|
+
z1 = round(abs(rational)/4+3*math.sqrt(rational**2-radicand)*math.cos(theta/3)/4)
|
|
780
|
+
z2 = round(abs(rational)/4+3*math.sqrt(rational**2-radicand)*math.cos(theta/3+2*math.pi/3)/4)
|
|
781
|
+
z3 = round(abs(rational)/4+3*math.sqrt(rational**2-radicand)*math.cos(theta/3+4*math.pi/3)/4)
|
|
782
|
+
|
|
783
|
+
if is_cube(z1):
|
|
784
|
+
y = z1
|
|
785
|
+
|
|
786
|
+
elif is_cube(z2):
|
|
787
|
+
y = z2
|
|
788
|
+
|
|
789
|
+
elif is_cube(z3):
|
|
790
|
+
y = z3
|
|
791
|
+
|
|
792
|
+
else:
|
|
793
|
+
y = 0
|
|
794
|
+
|
|
795
|
+
if rational < 0:
|
|
796
|
+
x = -x
|
|
797
|
+
y = -y
|
|
798
|
+
|
|
799
|
+
else:
|
|
800
|
+
pass
|
|
801
|
+
|
|
802
|
+
if x != 0 and is_cube((rtn-x)**3//(27*x)):
|
|
803
|
+
a = cube(fct)[0] * cube(x)[0]
|
|
804
|
+
b = cube(fct)[0] ** 2 * (rtn - x) // (3 * cube(x)[0])
|
|
805
|
+
|
|
806
|
+
if is_cube(fct):
|
|
807
|
+
if is_minus and 3 * a ** 2 + b > 0 or not is_minus and 3 * a ** 2 + b < 0:
|
|
808
|
+
return sqfrac(a, b, denominator, True)
|
|
809
|
+
|
|
810
|
+
else:
|
|
811
|
+
return sqfrac(a, b, denominator)
|
|
812
|
+
|
|
813
|
+
else:
|
|
814
|
+
if is_minus and 3 * a ** 2 + b > 0 or not is_minus and 3 * a ** 2 + b < 0:
|
|
815
|
+
return f'{sqfrac(a, b, denominator, True)}·{cubic_root(cube(fct)[1])}'
|
|
816
|
+
|
|
817
|
+
else:
|
|
818
|
+
return f'{sqfrac(a, b, denominator)}·{cubic_root(cube(fct)[1])}'
|
|
819
|
+
|
|
820
|
+
elif y != 0 and is_cube((rational-y)**3//(27*y)):
|
|
821
|
+
a = cube(y)[0]
|
|
822
|
+
b = (rational - y) // (3 * cube(y)[0])
|
|
823
|
+
|
|
824
|
+
if is_minus and 3 * a ** 2 + b > 0 or not is_minus and 3 * a ** 2 + b < 0:
|
|
825
|
+
return sqfrac(a, b, denominator, True)
|
|
826
|
+
|
|
827
|
+
else:
|
|
828
|
+
return sqfrac(a, b, denominator)
|
|
829
|
+
|
|
830
|
+
else:
|
|
831
|
+
if is_minus:
|
|
832
|
+
return cbfrac(rational, radicand, denominator, True)
|
|
833
|
+
|
|
834
|
+
else:
|
|
835
|
+
return cbfrac(rational, radicand, denominator)
|
|
836
|
+
|
|
837
|
+
# case for radicand = 0
|
|
838
|
+
else:
|
|
839
|
+
return cbfrac(rational, 0, denominator)
|