Coverage for pycommons/math/int_math.py: 100%
205 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-03 06:24 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-03 06:24 +0000
1"""
2Mathematics routines combining integers and floats.
4These routines try to return results with the highest possible precision,
5ideally as integers.
6If floating point values need to be converted to integers, then we round
7towards the nearest integer numbers, whereas `0.5` is always rounded up and
8`-0.5` is always rounded down.
9Thus, `1.5` becomes `2` and `-1.5` becomes `-2`.
10"""
12from contextlib import suppress
13from math import gcd, isfinite, isqrt, sqrt
14from sys import float_info
15from typing import Final
17from pycommons.types import type_error
19#: The positive limit for doubles that can be represented exactly as ints.
20#: We cannot represent any number `z` with `|z| >= 2 ** 53` as float without
21#: losing some digits, because floats have only 52 bits.
22#: `float(9007199254740992) == 9007199254740992.0`
23#: `float(9007199254740991) == 9007199254740991.0`
24#: But:
25#: #: `float(9007199254740993) == 9007199254740992.0`.
26__DBL_INT_LIMIT_P_I: Final[int] = 2 ** float_info.mant_dig
27#: The positive limit for doubles that can be represented exactly as ints.
28__DBL_INT_LIMIT_P_F: Final[float] = float(__DBL_INT_LIMIT_P_I) # = 1 << 53
29#: The negative limit for doubles that can be represented exactly as ints.
30__DBL_INT_LIMIT_N_I: Final[int] = -__DBL_INT_LIMIT_P_I
31#: The negative limit for doubles that can be represented exactly as ints.
32__DBL_INT_LIMIT_N_F: Final[float] = __DBL_INT_LIMIT_N_I
35def __try_int(val: float) -> int | float:
36 """
37 Convert a float to an int without any fancy checks.
39 :param val: the flot
40 :returns: the float or int
42 >>> from math import inf, nan, nextafter
43 >>> type(__try_int(0.0))
44 <class 'int'>
45 >>> type(__try_int(0.5))
46 <class 'float'>
47 >>> type(__try_int(inf))
48 <class 'float'>
49 >>> type(__try_int(-inf))
50 <class 'float'>
51 >>> type(__try_int(nan))
52 <class 'float'>
53 >>> 1 << 53
54 9007199254740992
55 >>> type(__try_int(9007199254740992.0))
56 <class 'int'>
57 >>> __try_int(9007199254740992.0)
58 9007199254740992
59 >>> too_big = nextafter(9007199254740992.0, inf)
60 >>> print(too_big)
61 9007199254740994.0
62 >>> type(__try_int(too_big))
63 <class 'float'>
64 >>> type(__try_int(-9007199254740992.0))
65 <class 'int'>
66 >>> __try_int(-9007199254740992.0)
67 -9007199254740992
68 >>> type(__try_int(-too_big))
69 <class 'float'>
70 """
71 if __DBL_INT_LIMIT_N_F <= val <= __DBL_INT_LIMIT_P_F:
72 a = int(val)
73 if a == val:
74 return a
75 return val
78def try_int(value: int | float) -> int | float:
79 """
80 Attempt to convert a float to an integer.
82 This method will convert a floating point number to an integer if the
83 floating point number was representing an exact integer. This is the
84 case if it has a) no fractional part and b) is in the range
85 `-9007199254740992...9007199254740992`, i.e., the range where `+1` and
86 `-1` work without loss of precision.
88 :param value: the input value, which must either be `int` or `float`
89 :returns: an `int` if `value` can be represented as `int` without loss of
90 precision, `val` otherwise
91 :raises TypeError: if `value` is neither an instance of `int` nor of
92 `float`
93 :raises ValueError: if `value` is a `float`, but not finite
95 >>> print(type(try_int(10.5)))
96 <class 'float'>
97 >>> print(type(try_int(10)))
98 <class 'int'>
100 >>> from math import inf, nan, nextafter
101 >>> type(try_int(0.0))
102 <class 'int'>
103 >>> type(try_int(0.5))
104 <class 'float'>
106 >>> try:
107 ... try_int(inf)
108 ... except ValueError as ve:
109 ... print(ve)
110 Value must be finite, but is inf.
112 >>> try:
113 ... try_int(-inf)
114 ... except ValueError as ve:
115 ... print(ve)
116 Value must be finite, but is -inf.
118 >>> try:
119 ... try_int(nan)
120 ... except ValueError as ve:
121 ... print(ve)
122 Value must be finite, but is nan.
124 >>> try:
125 ... try_int("blab") # noqa # type: off
126 ... except TypeError as te:
127 ... print(te)
128 value should be an instance of any in {float, int} but is str, namely \
129'blab'.
131 >>> type(try_int(9007199254740992.0))
132 <class 'int'>
133 >>> try_int(9007199254740992.0)
134 9007199254740992
135 >>> too_big = nextafter(9007199254740992.0, inf)
136 >>> print(too_big)
137 9007199254740994.0
138 >>> type(try_int(too_big))
139 <class 'float'>
140 >>> type(try_int(-9007199254740992.0))
141 <class 'int'>
142 >>> try_int(-9007199254740992.0)
143 -9007199254740992
144 >>> type(try_int(-too_big))
145 <class 'float'>
146 """
147 if isinstance(value, int):
148 return value
149 if isinstance(value, float):
150 if not isfinite(value):
151 raise ValueError(f"Value must be finite, but is {value}.")
152 if __DBL_INT_LIMIT_N_F <= value <= __DBL_INT_LIMIT_P_F:
153 a = int(value)
154 if a == value:
155 return a
156 return value
157 raise type_error(value, "value", (int, float))
160def __choose_frac(num1: int, denom1: int, num2: int, denom2: int) \
161 -> tuple[int, int]:
162 """
163 Choose the more compact one of two fractions.
165 :param num1: the first numerator
166 :param denom1: the first denominator
167 :param num2: the second numerator
168 :param denom2: the second denominator
169 :return: the numerator, denominator
171 >>> __choose_frac(10, 100, 1, 10)
172 (1, 10)
173 >>> __choose_frac(1, 10, 10, 100)
174 (1, 10)
175 >>> __choose_frac(1, 10, 1, 11)
176 (1, 10)
177 >>> __choose_frac(1, 11, 1, 10)
178 (1, 10)
179 >>> __choose_frac(1, 11, 2, 10)
180 (2, 10)
181 >>> __choose_frac(2, 10, 1, 11)
182 (2, 10)
183 >>> __choose_frac(2, 10, 1, 10)
184 (1, 10)
185 >>> __choose_frac(1, 10, 2, 10)
186 (1, 10)
187 """
188 return (num1, denom1) if (denom1 < denom2) or (
189 (num1 + denom1) < (num2 + denom2)) else (num2, denom2)
192def __minimize_frac(value: float, num: int, denom: int) -> tuple[int, int]:
193 """
194 Try to find a more compact equivalent representation of a given fraction.
196 If you convert `1/7` directly from the `float` format to an integer
197 fraction via `(1/7).as_integer_ratio()`, you get
198 `(2573485501354569, 18014398509481984)`. This is a precise conversion,
199 as `2573485501354569/18014398509481984 - 1/7 == 0`
200 However, `2573485501354569 * 7 = 18014398509481983`. Thus, the chosen
201 denominator is just 1 off the perfect one, because
202 `18014398509481983` divided by `2573485501354569` would give us exactly
203 `7`. Therefore, in this function, we try to check some adjacent
204 denominators for a given fraction. If they have a :func:`gcd` greater than
205 `1` with the numerator, then we choose them instead.
207 :param value: the floating point value
208 :param num: the numerator
209 :param denom: the denominator
210 :return: the fraction
212 >>> (1/7).as_integer_ratio()
213 (2573485501354569, 18014398509481984)
214 >>> 2573485501354569/18014398509481984 - 1/7
215 0.0
217 >>> __minimize_frac(1/7, 2573485501354569, 18014398509481984)
218 (1, 7)
220 >>> __minimize_frac(1/3, 6004799503160661, 18014398509481984)
221 (1, 3)
223 >>> __minimize_frac(1/3, 1, 3)
224 (1, 3)
226 >>> __minimize_frac(1/7, 1, 7)
227 (1, 7)
229 >>> __minimize_frac(1/7, 10, 70)
230 (1, 7)
232 >>> __minimize_frac(1e-20, 1, 1_0000_0000_0000_0000_0000)
233 (1, 100000000000000000000)
234 >>> __minimize_frac(1e-20, 1, 1_0000_0000_0000_0000_0001)
235 (1, 100000000000000000001)
236 >>> __minimize_frac(1e-20, 12, 12_0000_0000_0000_0000_0001)
237 (1, 100000000000000000000)
238 """
239 # First, we reduce with the GCD to simplify the fraction
240 g: int = gcd(num, denom) # the greatest common divisor
241 num //= g # simplify the fraction
242 denom //= g
243 best_num = num
244 best_denom = denom
245 min_gcd: int = 1
247 for num_add in range(-5, 5):
248 use_num = num + num_add
249 if use_num <= 0:
250 continue
251 for denom_add in range(-5, 5):
252 use_denom = denom + denom_add
253 if use_denom <= 0:
254 continue
255 if (use_num / use_denom) != value:
256 continue
257 g = gcd(use_num, use_denom)
258 if g > min_gcd:
259 min_gcd = g
260 best_num, best_denom = __choose_frac(
261 best_num, best_denom, use_num // g, use_denom // g)
262 return best_num, best_denom
265def float_to_frac(value: int | float) -> tuple[int, int]:
266 """
267 Turn a floating point number into an integer fraction.
269 If we want to translate a floating point number to an integer fraction,
270 then we have several possible ways to go about this. The reason is that,
271 due to the loss in precision when representing fractions as floating point
272 numbers, several different integer fractions can produce the exactly same
273 floating point number.
275 One choice would be to use :meth:`float.as_integer_ratio`, which turns the
276 binary representation of the floating point number to an integer fraction.
277 This is the canonical way that, without losing any precision, will return
278 an integer fraction that fits exactly to the floating point value.
280 However, as said, there may be multiple such fractions. And some of them
281 may be more "compact" than others.
283 A second approach would be to first represent the floating point value as
284 a string. The string that this produces also represents exactly this
285 floating point value, obviously. Now we can translate the string to a
286 fraction - and this can give us a different result.
288 Which of the two is right?
290 Both of them are. Kind of. So I'd figure we test both and stick with the
291 :meth:`float.as_integer_ratio` default result - unless the string path
292 provides a more compact representation. As simple yard stick, in such
293 cases, we use the fraction with the smaller denominator. If the
294 demoninators are the same, then we use the one with the smaller absolute
295 numerator.
297 :param value: the floating point value
298 :returns: the integer fraction
299 :raises TypeError: if value is neither an integer nor a float
300 :raises ValueError: if value is not finite
302 >>> float_to_frac(0.1)
303 (1, 10)
305 >>> float_to_frac(1e-1)
306 (1, 10)
308 >>> float_to_frac(1e-20)
309 (1, 100000000000000000000)
311 >>> 1e-20.as_integer_ratio()
312 (6646139978924579, 664613997892457936451903530140172288)
314 >>> float_to_frac(1e-30)
315 (1, 1000000000000000000000000000000)
317 >>> float_to_frac(1e30)
318 (1000000000000000000000000000000, 1)
320 >>> float_to_frac(1000)
321 (1000, 1)
323 >>> float_to_frac(1000.567)
324 (1000567, 1000)
326 >>> float_to_frac(1.234e-5)
327 (617, 50000000)
329 >>> float_to_frac(1.234e5)
330 (123400, 1)
332 >>> float_to_frac(0)
333 (0, 1)
334 >>> 0 / 1
335 0.0
337 >>> float_to_frac(-5376935265607590)
338 (-5376935265607590, 1)
339 >>> -5376935265607590 / 1
340 -5376935265607590.0
342 >>> float_to_frac(4)
343 (4, 1)
344 >>> 4 / 1
345 4.0
347 >>> float_to_frac(1 / 7)
348 (1, 7)
350 >>> float_to_frac(1 / 11)
351 (1, 11)
353 >>> float_to_frac(1 / 10000)
354 (1, 10000)
356 >>> float_to_frac(-21844.45693689149)
357 (-2184445693689149, 100000000000)
358 >>> -2184445693689149 / 100000000000
359 -21844.45693689149
361 >>> float_to_frac(-3010907.436657168)
362 (-188181714791073, 62500000)
363 >>> -188181714791073 / 62500000
364 -3010907.436657168
366 >>> float_to_frac(13660.023207762431)
367 (26679732827661, 1953125000)
368 >>> 26679732827661 / 1953125000
369 13660.023207762431
371 >>> float_to_frac(438027.68586526066)
372 (58791080797933, 134217728)
373 >>> 58791080797933 / 134217728
374 438027.68586526066
376 >>> float_to_frac(-8338355882.478134)
377 (-546462491114087, 65536)
378 >>> -546462491114087 / 65536
379 -8338355882.478134
381 >>> float_to_frac(-32835294.95774138)
382 (-275442417964869, 8388608)
383 >>> -275442417964869 / 8388608
384 -32835294.95774138
386 >>> float_to_frac(-0.8436071305882418)
387 (-1054508913235303, 1250000000000001)
388 >>> -1054508913235303 / 1250000000000001
389 -0.8436071305882418
391 >>> float_to_frac(-971533.786640197)
392 (-32599264379521, 33554432)
393 >>> -32599264379521 / 33554432
394 -971533.786640197
396 >>> float_to_frac(187487280836.01147)
397 (767947902304303, 4096)
398 >>> 767947902304303 / 4096
399 187487280836.01147
401 >>> float_to_frac(24214223389953.125)
402 (193713787119625, 8)
403 >>> 193713787119625 / 8
404 24214223389953.125
406 >>> float_to_frac(2645.112807929305)
407 (363541536137187, 137438953472)
408 >>> 363541536137187 / 137438953472
409 2645.112807929305
411 >>> float_to_frac(92129361.64291245)
412 (1545674200225257, 16777216)
413 >>> 1545674200225257 / 16777216
414 92129361.64291245
416 >>> float_to_frac(7218177.564653773)
417 (1937614786056805, 268435456)
418 >>> 1937614786056805 / 268435456
419 7218177.564653773
421 >>> float_to_frac(-1.4589908563595052e+16)
422 (-14589908563595052, 1)
423 >>> -14589908563595052 / 1
424 -1.4589908563595052e+16
426 >>> float_to_frac(-1.607745417434216e+16)
427 (-16077454174342160, 1)
428 >>> -16077454174342160 / 1
429 -1.607745417434216e+16
431 >>> float_to_frac(-952261813.8291152)
432 (-595163633643197, 625000)
433 >>> -595163633643197 / 625000
434 -952261813.8291152
436 >>> float_to_frac(124.69515801820336)
437 (779344737613771, 6250000000000)
438 >>> 779344737613771 / 6250000000000
439 124.69515801820336
441 >>> float_to_frac(1.041491959175676e+16)
442 (10414919591756760, 1)
443 >>> 10414919591756760 / 1
444 1.041491959175676e+16
446 >>> float_to_frac(1.4933667846659504e+16)
447 (14933667846659504, 1)
448 >>> 14933667846659504 / 1
449 1.4933667846659504e+16
451 >>> float_to_frac(-6.034817133993009e-05)
452 (-271784001959, 4503599627370496)
453 >>> -271784001959 / 4503599627370496
454 -6.034817133993009e-05
456 >>> float_to_frac(-2.682658826813622e-05)
457 (-1887753327, 70368744177664)
458 >>> -1887753327 / 70368744177664
459 -2.682658826813622e-05
461 >>> float_to_frac(6.342974725370709e-05)
462 (17853886631, 281474976710656)
463 >>> 17853886631 / 281474976710656
464 6.342974725370709e-05
466 >>> float_to_frac(8.759559844406795e-05)
467 (3081996129, 35184372088832)
468 >>> 3081996129 / 35184372088832
469 8.759559844406795e-05
471 >>> float_to_frac(-9.6e-09)
472 (-3, 312500000)
473 >>> -3 / 312500000
474 -9.6e-09
476 >>> float_to_frac(-0.4)
477 (-2, 5)
478 >>> -2 / 5
479 -0.4
481 >>> float_to_frac(2e-10)
482 (1, 5000000000)
483 >>> 1 / 5000000000
484 2e-10
486 >>> float_to_frac(0.3)
487 (3, 10)
488 >>> 3 / 10
489 0.3
491 >>> float_to_frac(-3e-09)
492 (-3, 1000000000)
493 >>> -3 / 1000000000
494 -3e-09
496 >>> float_to_frac(1e-07)
497 (1, 10000000)
498 >>> 1 / 10000000
499 1e-07
501 >>> float_to_frac(-8e-08)
502 (-1, 12500000)
503 >>> -1 / 12500000
504 -8e-08
506 >>> float_to_frac(-0.01)
507 (-1, 100)
508 >>> -1 / 100
509 -0.01
511 >>> float_to_frac(1e-08)
512 (1, 100000000)
513 >>> 1 / 100000000
514 1e-08
516 >>> float_to_frac(0.01)
517 (1, 100)
518 >>> 1 / 100
519 0.01
521 >>> float_to_frac(-2e-06)
522 (-1, 500000)
523 >>> -1 / 500000
524 -2e-06
526 >>> float_to_frac(-6e-08)
527 (-3, 50000000)
528 >>> -3 / 50000000
529 -6e-08
531 >>> float_to_frac(7e-05)
532 (7, 100000)
533 >>> 7 / 100000
534 7e-05
536 >>> float_to_frac(-1e+40)
537 (-10000000000000000000000000000000000000000, 1)
538 >>> -10000000000000000000000000000000000000000 / 1
539 -1e+40
541 >>> float_to_frac(1e+40)
542 (10000000000000000000000000000000000000000, 1)
543 >>> 10000000000000000000000000000000000000000 / 1
544 1e+40
546 >>> float_to_frac(1.6152587208080178e+161)
547 (16152587208080177786162779887253130808505244217290853753086392891829620\
5481092892491941055809815064259587161746312711311289043311353137951968371237523\
549928335253504000, 1)
550 """
551 value = try_int(value)
552 if isinstance(value, int):
553 return value, 1
555 minus: Final[bool] = value < 0.0
556 if minus:
557 value = -value
559 # Get the minimized fraction.
560 num1, denom1 = __minimize_frac(value, *value.as_integer_ratio())
562 # First, we convert the floating point number to a string, which
563 # necessarily exactly represents the value. Then we will go and turn
564 # the string into a fraction.
565 value_str: Final[str] = float.__repr__(value)
567 end_idx: int = str.__len__(value_str)
568 dot_idx: Final[int] = str.find(value_str, ".")
569 exp_idx: Final[int] = str.find(value_str, "e")
571 denom2: int = 1
572 multiplier: int = 1
573 if exp_idx > 0:
574 int_exp = int(value_str[exp_idx + 1:end_idx])
575 if int_exp < 0:
576 denom2 = 10 ** (-int_exp)
577 else:
578 multiplier = 10 ** int_exp
579 end_idx = exp_idx
581 num2: int = 0
582 if dot_idx >= 0:
583 int_denom_2 = 10 ** (end_idx - dot_idx - 1)
584 num2 = ((int(value_str[:dot_idx]) * int_denom_2)
585 + int(value_str[dot_idx + 1:end_idx]))
586 denom2 *= int_denom_2
587 else:
588 num2 = int(value_str[:end_idx])
590 num2 *= multiplier
591 if num2 / denom2 == value:
592 num1, denom1 = __choose_frac(*__minimize_frac(
593 value, num2, denom2), num1, denom1)
594 return (-num1 if minus else num1), denom1
597def try_int_div(a: int, b: int) -> int | float:
598 """
599 Try to divide two integers at best precision.
601 Floating point divisions can incur some loss of precision. We try
602 to avoid this here as much as possible. First, we check if `a` is
603 divisible by `b` without any fractional part. If this is true, then
604 we can do a pure integer division without loss of any precision.
605 In other words, if `a % b == 0`, then `a / b` is itself an integer,
606 i.e., can be represented exactly.
608 Otherwise, it will have a fractional part, so it would ideally be a
609 `float`.
610 Well.
612 What if the integer `a` is really large? Converting it to floating
613 point number may then incur a loss of precision. And why do we convert
614 it to a `float` in the first place? To properly represent the fractional
615 part. Because the integer part is `a // b` is an integer. The fractional
616 part `f` is then by definition `f = (a % b) // b == (a - b*(a // b)) / b`.
617 Obviously, `0<f<1`. It may be entirely possible that we lose several full
618 integer *digits* by converting the integer `a` to a `float` ... just to
619 then be able to add a fraction `f`. So this loss of precision may be much
620 larger than the little fractional part that we would add (which will
621 always be in `(0, 1)`. In such a case, it may be much better to stay in
622 the realm of integers and instead lose the fractional part. Thus, we also
623 test whether multiplying the result of the floating point computation with
624 `b` is closer to `a` than integer results rounded in either direction.
626 During this procedure, we try to pick the result closest to the original
627 value. This, however, may only be possible if we can actually compute the
628 difference. If we deal with floating point numbers and integers, some
629 integers may simply be too large for being ever converted to a float. In
630 this case, we remain entirely in the integer realm and only round if need
631 be.
633 :param a: the first integer
634 :param b: the second integer
635 :returns: a/b, either as `int` or as `float` but always a finite value
636 :raises ZeroDivisionError: if `b==0`
637 :raises TypeError: if `a` or `b` are not integers
639 >>> print(try_int_div(10, 2))
640 5
641 >>> print(try_int_div(10, -2))
642 -5
643 >>> print(try_int_div(-10, 2))
644 -5
645 >>> print(try_int_div(-10, -2))
646 5
647 >>> print(type(try_int_div(10, 2)))
648 <class 'int'>
649 >>> print(try_int_div(10, 3))
650 3.3333333333333335
651 >>> print(try_int_div(-10, 3))
652 -3.3333333333333335
653 >>> print(try_int_div(10, -3))
654 -3.3333333333333335
655 >>> print(try_int_div(-10, -3))
656 3.3333333333333335
657 >>> print(type(try_int_div(10, 3)))
658 <class 'float'>
659 >>> print(try_int_div(9007199254740992, 1))
660 9007199254740992
661 >>> print(try_int_div(2109792310235001520128, 234234))
662 9007199254740992
663 >>> print(try_int_div(2109792310235001520128, 234235))
664 9007160801054503
665 >>> print(try_int_div(2109792310235001520128, 234233))
666 9007237708755818
667 >>> large = 123456789012345678901234567890123456789012345678901234567\
66889012345678901234567890123456789012345678901234567890123456789012345678901234\
66956789012345678901234567890123456789012345678901234567890123456789012345678901\
67023456789012345678901234567890123456789012345678901234567890123456789012345678\
67190123456789012345678901234567890123456789012345678901234567890123456789012345\
67267890123456789012345678901234567890123456789012345678901234567890123456789012\
6733456789012345678901234567890123456789012345678901234567890123456789012345678\
67490123456789012345678901234567890123456789012345678901234567890123456789012345\
675678901234567890123456789012345678901234567890
677 >>> try:
678 ... large / 1
679 ... except OverflowError as oe:
680 ... print(oe)
681 integer division result too large for a float
682 >>> try_int_div(large, 1)
683 123456789012345678901234567890123456789012345678901234567\
68489012345678901234567890123456789012345678901234567890123456789012345678901234\
68556789012345678901234567890123456789012345678901234567890123456789012345678901\
68623456789012345678901234567890123456789012345678901234567890123456789012345678\
68790123456789012345678901234567890123456789012345678901234567890123456789012345\
68867890123456789012345678901234567890123456789012345678901234567890123456789012\
6893456789012345678901234567890123456789012345678901234567890123456789012345678\
69090123456789012345678901234567890123456789012345678901234567890123456789012345\
691678901234567890123456789012345678901234567890
693 >>> try_int_div(large * 7, 1 * 7)
694 123456789012345678901234567890123456789012345678901234567\
69589012345678901234567890123456789012345678901234567890123456789012345678901234\
69656789012345678901234567890123456789012345678901234567890123456789012345678901\
69723456789012345678901234567890123456789012345678901234567890123456789012345678\
69890123456789012345678901234567890123456789012345678901234567890123456789012345\
69967890123456789012345678901234567890123456789012345678901234567890123456789012\
7003456789012345678901234567890123456789012345678901234567890123456789012345678\
70190123456789012345678901234567890123456789012345678901234567890123456789012345\
702678901234567890123456789012345678901234567890
704 >>> res = try_int_div(large, 7)
705 >>> print(res)
706 1763668414462081127160493827001763668414462081127160493827001763668414462\
70708112716049382700176366841446208112716049382700176366841446208112716049382700\
70817636684144620811271604938270017636684144620811271604938270017636684144620811\
70927160493827001763668414462081127160493827001763668414462081127160493827001763\
71066841446208112716049382700176366841446208112716049382700176366841446208112716\
71104938270017636684144620811271604938270017636684144620811271604938270017636684\
71214462081127160493827001763668414462081127160493827001763668414462081127160493\
71382700176366841446208112716049382700176366841446208112716049382700176366841446\
714208112716049382700176366841
715 >>> large - (res * 7)
716 3
718 >>> res = try_int_div(large - 1, 7)
719 >>> print(res)
720 1763668414462081127160493827001763668414462081127160493827001763668414462\
72108112716049382700176366841446208112716049382700176366841446208112716049382700\
72217636684144620811271604938270017636684144620811271604938270017636684144620811\
72327160493827001763668414462081127160493827001763668414462081127160493827001763\
72466841446208112716049382700176366841446208112716049382700176366841446208112716\
72504938270017636684144620811271604938270017636684144620811271604938270017636684\
72614462081127160493827001763668414462081127160493827001763668414462081127160493\
72782700176366841446208112716049382700176366841446208112716049382700176366841446\
728208112716049382700176366841
729 >>> (large - 1) - (res * 7)
730 2
732 >>> res = try_int_div(large + 1, 7)
733 >>> print(res)
734 1763668414462081127160493827001763668414462081127160493827001763668414462\
73508112716049382700176366841446208112716049382700176366841446208112716049382700\
73617636684144620811271604938270017636684144620811271604938270017636684144620811\
73727160493827001763668414462081127160493827001763668414462081127160493827001763\
73866841446208112716049382700176366841446208112716049382700176366841446208112716\
73904938270017636684144620811271604938270017636684144620811271604938270017636684\
74014462081127160493827001763668414462081127160493827001763668414462081127160493\
74182700176366841446208112716049382700176366841446208112716049382700176366841446\
742208112716049382700176366842
743 >>> (large + 1) - (res * 7)
744 -3
746 >>> try:
747 ... try_int_div(0, 0)
748 ... except ZeroDivisionError as zde:
749 ... print("by zero" in str(zde))
750 True
752 >>> try:
753 ... try_int_div(1, 0)
754 ... except ZeroDivisionError as zde:
755 ... print("by zero" in str(zde))
756 True
758 >>> try:
759 ... try_int_div(-1, 0)
760 ... except ZeroDivisionError as zde:
761 ... print("by zero" in str(zde))
762 True
764 >>> try_int_div(153, 17)
765 9
766 >>> try_int_div(-153, 17)
767 -9
768 >>> try_int_div(626240198453350272215815210991, 180)
769 3479112213629723734532306728
770 >>> try_int_div(-626240198453350272215815210991, 180)
771 -3479112213629723734532306728
772 >>> try_int_div(312641328808813509022862142116, 184)
773 1699137656569638635993815990
774 >>> try_int_div(-312641328808813509022862142116, 184)
775 -1699137656569638635993815990
776 >>> try_int_div(300228563787891776398328530521, 6)
777 50038093964648629399721421754
778 >>> try_int_div(300228563787891776398328530520, 6)
779 50038093964648629399721421753
780 >>> try_int_div(-300228563787891776398328530521, 6)
781 -50038093964648629399721421754
783 >>> try_int_div(153, -17)
784 -9
785 >>> try_int_div(-153, -17)
786 9
787 >>> try_int_div(626240198453350272215815210991, -180)
788 -3479112213629723734532306728
789 >>> try_int_div(-626240198453350272215815210991, -180)
790 3479112213629723734532306728
791 >>> try_int_div(312641328808813509022862142116, -184)
792 -1699137656569638635993815990
793 >>> try_int_div(-312641328808813509022862142116, -184)
794 1699137656569638635993815990
795 >>> try_int_div(300228563787891776398328530521, -6)
796 -50038093964648629399721421754
797 >>> try_int_div(-300228563787891776398328530521, -6)
798 50038093964648629399721421754
800 >>> try_int_div(471560594207063922064065980174, 160)
801 2947253713794149512900412376
803 >>> try_int_div(7995687632, 605623302520652727304862084393)
804 1.3202410803417417e-20
806 >>> try_int_div(308201705551808339041017943851, 23)
807 13400074154426449523522519298
809 >>> try_int_div(899348944156468188933109403939, 54)
810 16654610076971633128390914888
812 >>> try_int_div(494818043590514116668712249977, 42)
813 11781381990250336111159815476
815 >>> try_int_div(738070379515233920, 205)
816 3600343314708458
818 >>> try_int_div(3502315235185234554036893628, 2914324106703)
819 1201759003787480
821 >>> try_int_div(7410628973168661103, 3869)
822 1915386139356076.8
824 >>> try_int_div(1230161216449799063065724370370, 4689247521470)
825 262336592559346126
827 >>> try_int_div(1052870426843577701006624798274, 28)
828 37602515244413489321665171367
830 >>> try_int_div(218235816140080518429116, 65180391)
831 3348182065064330.5
833 >>> try_int_div(542681063252950460111634072, 1417)
834 382978873149576894927053
836 >>> try_int_div(6347580784084238615827, 9508617)
837 667560885466754.9
839 >>> try_int_div(25864142832167873073008, 8621014)
840 3000127691727199.5
842 >>> try_int_div(35377667634669293542601414338, 8678403583)
843 4076517909811212054
845 >>> try_int_div(1423204593957046760175, 6)
846 237200765659507793363
848 >>> try_int_div(1959151753859121847452742, 155502)
849 12598884605079817928
851 >>> try_int_div(153429321515534965993379305, 15165212220)
852 10117189215010864
854 >>> try_int_div(638685779810794590594721888599, 6355644831674)
855 100491106209686119
857 >>> try_int_div(14634805, 3163458943542033136)
858 4.626203551614245e-12
860 >>> try_int_div(2728490692514068837390, 1134)
861 2406076448425104795
863 >>> try_int_div(52133244, 2145832361321597595907)
864 2.4295115005112346e-14
866 >>> try_int_div(989732710522254024, 870)
867 1137623805197993.2
869 >>> try_int_div(1015, 4100715151904)
870 2.475178017494646e-10
872 >>> try_int_div(750731, 60649291746)
873 1.2378231936228884e-05
875 >>> try_int_div(7972413701754221571302566, 1660418690)
876 4801447821425222
878 >>> try_int_div(356135676699525125944, 46208)
879 7707229845471025
881 >>> try_int_div(10448177882855961291672, 1739414)
882 6006722886475538
884 >>> try_int_div(739391142068058031063862, 8456)
885 87439822855730609161
887 >>> try_int_div(316514845935646909034735039673, 32172)
888 9838208564455020173900753
890 >>> try_int_div(4158458869534984918534998087, 30)
891 138615295651166163951166603
893 >>> try_int_div(102306108211747181839762853503, 29118)
894 3513500522417308257427119
896 >>> all(try_int_div(1, y) == (1 / y) for y in range(2, 10))
897 True
899 >>> all(try_int_div(2, y) == (2 / y) for y in range(3, 10))
900 True
902 >>> try_int_div(820432337843942760, 85)
903 9652145151105209
905 >>> try_int_div(84050617, 3577089862)
906 0.023496926340286613
908 >>> try_int_div(812060021745358856, 996816531)
909 814653445.7356013
911 >>> try_int_div(38029336, 472982612237)
912 8.040324319775297e-05
914 >>> try_int_div(50229909719349513, 9)
915 5581101079927724
917 >>> try_int_div(61320503685013026, 2728161164469337)
918 22.476862614874392
920 >>> try_int_div(23134400382350491, 8)
921 2891800047793811.5
923 >>> try_int_div(12510965, 67561917605841203)
924 1.8517776645993746e-10
926 >>> try_int_div(27246707584980173, 4)
927 6811676896245043
929 >>> try_int_div(135385235231741420, 6)
930 22564205871956903
932 >>> try_int_div(90, 153429501803)
933 5.865886217603572e-10
935 >>> try_int_div(734553401849288248, 951111)
936 772310909924.5916
938 >>> try_int_div(9820998979656, 4239082999146)
939 2.3167744018304255
941 >>> try_int_div(133105116441194557, 17)
942 7829712731834974
944 >>> try_int_div(1004604250960040176, 14)
945 71757446497145727
947 >>> try_int_div(246148731190755584, 6)
948 41024788531792597
950 >>> try_int_div(991564, 72057594037927936)
951 1.3760714789867734e-11
953 >>> try_int_div(2623725286393384, 139634775865757)
954 18.789912972079378
956 >>> try_int_div(63010439554808723, 9)
957 7001159950534303
959 >>> try_int_div(2801452, 427673)
960 6.550453266865105
962 >>> try_int_div(14177411351567, 349688426689780)
963 0.04054298132132421
965 >>> try_int_div(126660394112336947, 368)
966 344185853566133
968 >>> try_int_div(1031427640916897886, 7)
969 147346805845271127
971 >>> try_int_div(33290935002573849, 2)
972 16645467501286925
974 >>> try_int_div(209062743096233332, 64)
975 3266605360878646
977 >>> try_int_div(253174817711179642, 57)
978 4441663468617186.5
980 >>> try_int_div(29462133006911895, 24943246)
981 1181166757.8033707
983 >>> try_int_div(93475849985676023, 60673699562)
984 1540632.1134276118
986 >>> try_int_div(-16, -16)
987 1
989 >>> try_int_div(242, 150)
990 1.6133333333333333
992 >>> try_int_div(-547, -698)
993 0.7836676217765043
995 >>> try_int_div(463, 105)
996 4.40952380952381
998 >>> try_int_div(-148, -203)
999 0.729064039408867
1001 >>> try_int_div(0, -25)
1002 0
1004 >>> try_int_div(24, -177)
1005 -0.13559322033898305
1007 >>> try_int_div(-166, 186)
1008 -0.8924731182795699
1010 >>> try_int_div(-608143760099358008316, 16)
1011 -38008985006209875520
1013 >>> try_int_div(-6917198296130591233, 2932)
1014 -2359208150112753
1016 >>> try_int_div(-40068404846647758412, 2431)
1017 -16482272664190769
1019 >>> try_int_div(809884532216820092, -80)
1020 -10123556652710251
1022 >>> try_int_div(-9428902965475478968, -1946)
1023 4845273877428304
1025 >>> try_int_div(94881103250893722164, 174)
1026 545293696844216794
1028 >>> try_int_div(558275776531402194, 196)
1029 2848345798629603
1031 >>> try_int_div(-5470954588630039684, -1425)
1032 3839266377985993
1034 >>> x = 52051907638184435686872083537997907834107397007408814104887055550\
103562651162584515572343506336421788506498764827396236326664325857298113627143047\
103651960058116028166468699987611855171916670918181477368243402962224866666859483\
103727106641344727853102203836313167806475289935694133683049416723665601922267867\
103843423073756386687744959209264639678418438341653942959851578625489694262628828\
103901502680997461128779292890987864647476268814586685317933377503211673153129336\
104003
1041 >>> y = -1390354761575126197823721816501267487365151253235077143453455350\
104242071715351921681111638693456863646113210365045493352
1043 >>> try_int_div(x, y)
1044 -374378605207314720094873468836285633819929467061778300817269205498029513\
104565402433513265745971266615921400317429877366670340545494622384105823993306348\
104652843139170606054848072439314573682429224161889047753873201343420620892557508\
104762700497112616274728625215898978448963212698759159253800300962780904741771804\
1048645167943738988195771748632862162
1050 >>> x = -2371099749665044990658141554075074237566818135879925492767658755\
105191466431785344954996723447284617738104563308335316636469414432945133872626562\
105247514537471872530515191642703803616012611248118482218872482697827387761273565\
105386825000794528611072492997052827719254891404531142028847153355973782623685875\
105455388033455119839506838214696423221276537787120528956164822252461892023157114\
105502799038227958323905920667727058869625829951896827916647011550854954614174228\
10560327582498733595995697631187168710055335569609973997123439124471957303314220
1057 >>> y = 23343578649740692313745114608806472033684574464287511781560680643\
105878701796266433578371331497
1059 >>> try_int_div(x, y)
1060 -101573961098350440775039372298606794268469908577045401233130406288914282\
106192918893248309802232281829255680862092165642164462698933290177430764947955661\
106287652857199541665161754173953190591131037518696771010612358486878465958542091\
106354914381056640460582835505879418330902968200425941036454902030259440742425865\
106493440206970165106076445287259870479244010983474198088053313334979762284802017\
10651153886834216445854191456742632611734684212485945595091
1067 >>> x = 40410061884642793201602670149115414017394734761323545080847020296\
106825252534757283636685784303675489231680221820894136736092474359799408796002401\
106987921742390653841150636438854369236710256224057607718115525186887758631639670\
107082468402380054839668544662058030344964306015945683011983835531538788295592437\
107165716882229369219075665520432950975969718863463181388344946182200519006147179\
107264461315530742161850062785306859778524746068148875909170944464910610460508750\
1073707051996751159775959805908309
1074 >>> try_int_div(x, 455824846955327759894405021890034373481341853483437732)
1075 8865260890133771894279961299939580714408739728863480476996077470796169955\
107643085620471927592765951912973058793385603301586629745150439814928912960267883\
107766400412702824502182496145839556516762964408587815797906905800899307550385283\
107859797468484699310297417864757571840405529641545438878013277855865542975695833\
107988146919245416237227940140677498927052487483630425657258239092995434299050034\
1080021769275549143357256693312576946435784210430
1082 >>> x = -6232936786190843094006005233017695847240511752635979691082519622\
108389671822451515008492890632740917254159586399372900046205300278719490624751881\
108476026655230475873682972201137642189143060727745274448518821915960488822897219\
108519105433159267999911968464110051361652323090653411336081715581855840751539611\
108644549510551090842769903146173949669899963195645511983189442245054559694895154\
108728690282113755080383328799009405959846487733552322199361433571441631699077621\
1088235779724223724145601506861527256455350316142
1089 >>> y = -672227780379448967615099076221459579351218967417588220
1090 >>> try_int_div(x, y)
1091 9272060703401113879042492429626067042706252670698636022710487050821126676\
109243853746484009770979124008642489211907343513622775392767108564692587266167738\
109393885766234994122772733590708011238049750176667082969644614903930265971589853\
109426674807243894898200722561326294551914700598739493395761954564220400052036328\
109558909594484124974270252599224045683880122299500249240856446063861849302671425\
109605617327729864850535306650812894643758024556770793387750201
1098 >>> try:
1099 ... try_int_div(1.0, 2)
1100 ... except TypeError as te:
1101 ... print(te)
1102 a should be an instance of int but is float, namely 1.0.
1104 >>> try:
1105 ... try_int_div(1, 2.0)
1106 ... except TypeError as te:
1107 ... print(te)
1108 b should be an instance of int but is float, namely 2.0.
1109 """
1110 if not isinstance(a, int):
1111 raise type_error(a, "a", int)
1112 if not isinstance(b, int):
1113 raise type_error(b, "b", int)
1114 minus: bool = False
1115 if a < 0:
1116 minus = True
1117 a = -a
1118 if b < 0:
1119 minus = not minus
1120 b = -b
1122 # Let's say a = 762 and b = 204.
1123 # We first compute the GCD to reduce both sides of the equation.
1124 the_gcd: Final[int] = gcd(a, b) # == 6 in the example
1125 a //= the_gcd # == 127 in the example
1126 b //= the_gcd # == 34 in the example
1128 # First, let's compute the result of the pure integer division.
1129 int_res_1: Final[int] = a // b # == 3 in our example
1130 int_mult_1: Final[int] = int_res_1 * b # == 102 in the example
1131 if int_mult_1 == a: # if there is no rest, then we can stop here
1132 return -int_res_1 if minus else int_res_1
1134 int_frac_1: Final[int] = a - int_mult_1 # == 25 in the example
1135 int_res_2: Final[int] = int_res_1 + 1 # rounding up, == 4 in the example
1136 # Compute int_frac_2 == (int_res_2 * b - a, but simplified:
1137 int_frac_2: Final[int] = b - int_frac_1 # == 9 in the example
1139 # OK, there may be a loss of precision if we do the floating point
1140 # computation. But we should try it now anyway.
1141 # if `a` and `b` can exactly be represented as floats (by being not more
1142 # than `__DBL_INT_LIMIT_P_I`, then we are OK and can directly use the
1143 # result. Otherwise, if the result is between the lower and the upper
1144 # limit, then we will also take it. This would mean to basically default
1145 # to the normal division in Python in cases where it falls into the
1146 # expected range of possible results.
1147 with suppress(ArithmeticError):
1148 float_res = __try_int(a / b) # == 3.5588235294117645 in the example
1149 if ((a <= __DBL_INT_LIMIT_P_I) and (b <= __DBL_INT_LIMIT_P_I)) or (
1150 int_res_1 < float_res < int_res_2):
1151 return -float_res if minus else float_res
1153 best_result: Final[int] = \
1154 int_res_2 if int_frac_2 <= int_frac_1 else int_res_1
1155 return -best_result if minus else best_result # fix sign of result
1158def try_float_int_div(a: int | float, b: int) -> int | float:
1159 """
1160 Try to divide a float by an int at best precision.
1162 :param a: the first number, which is either a float or an int
1163 :param b: the second number, which must be an int
1164 :returns: `a/b`, but always finite
1166 :raises ValueError: if either one of the arguments or the final result
1167 would not be finite
1168 :raises TypeError: if either one of `a` or `b` is neither an integer nor
1169 a float
1171 >>> try_float_int_div(10, 2)
1172 5
1174 >>> try_float_int_div(10.0, 2)
1175 5
1177 >>> try_float_int_div(10, 3)
1178 3.3333333333333335
1180 >>> try_float_int_div(-10, 2)
1181 -5
1183 >>> try_float_int_div(-10.2, 2)
1184 -5.1
1186 >>> try_float_int_div(-10.0, 2)
1187 -5
1189 >>> try_float_int_div(-10, 3)
1190 -3.3333333333333335
1192 >>> print(type(try_float_int_div(10.0, 2)))
1193 <class 'int'>
1195 >>> print(type(try_float_int_div(10.0, 3)))
1196 <class 'float'>
1198 >>> try:
1199 ... try_float_int_div(10, 0.5)
1200 ... except TypeError as te:
1201 ... print(te)
1202 b should be an instance of int but is float, namely 0.5.
1204 >>> from math import inf, nan
1205 >>> try:
1206 ... try_float_int_div(1.0, 0)
1207 ... except ZeroDivisionError as zde:
1208 ... print("by zero" in str(zde))
1209 True
1211 >>> try:
1212 ... try_float_int_div(inf, 0)
1213 ... except ValueError as ve:
1214 ... print(ve)
1215 Value must be finite, but is inf.
1217 >>> try:
1218 ... try_float_int_div(-inf, 0)
1219 ... except ValueError as ve:
1220 ... print(ve)
1221 Value must be finite, but is -inf.
1223 >>> try:
1224 ... try_float_int_div(nan, 0)
1225 ... except ValueError as ve:
1226 ... print(ve)
1227 Value must be finite, but is nan.
1229 >>> try:
1230 ... try_float_int_div(1, inf)
1231 ... except TypeError as te:
1232 ... print(te)
1233 b should be an instance of int but is float, namely inf.
1235 >>> try:
1236 ... try_float_int_div("y", 1)
1237 ... except TypeError as te:
1238 ... print(te)
1239 value should be an instance of any in {float, int} but is str, namely 'y'.
1241 >>> try:
1242 ... try_float_int_div(1, "x")
1243 ... except TypeError as te:
1244 ... print(te)
1245 b should be an instance of int but is str, namely 'x'.
1246 """
1247 if not isinstance(b, int):
1248 raise type_error(b, "b", int)
1249 a = try_int(a)
1250 if isinstance(a, int):
1251 return try_int_div(a, b)
1252 return __try_int(a / b)
1255def try_div(a: int | float, b: int | float) -> int | float:
1256 """
1257 Try to divide two numbers at best precision.
1259 First, we will check if we can convert the second number to a integer
1260 without loss of precision via :func:`try_int`. If yes, then
1261 we go for the maximum-precision integer division via
1262 :func:`try_float_int_div`.
1263 If no, then we do the normal floating point division and try to convert
1264 the result to an integer if that can be done without loss of precision.
1266 :param a: the first number
1267 :param b: the second number
1268 :return: `a/b`, but always finite
1270 :raises ValueError: if either one of the arguments or the final result
1271 would not be finite
1273 >>> try_div(1e180, 1e60)
1274 1.0000000000000001e+120
1275 >>> try_div(1e60, 1e-60)
1276 1e+120
1277 >>> try_div(1e14, 1e-1)
1278 1000000000000000
1279 >>> try_div(1e14, -1e-1)
1280 -1000000000000000
1281 >>> try_div(-1e14, 1e-1)
1282 -1000000000000000
1283 >>> try_div(-1e14, -1e-1)
1284 1000000000000000
1285 >>> try_div(1e15, 1e-1)
1286 1e+16
1287 >>> try_div(1e15, -1e-1)
1288 -1e+16
1289 >>> try_div(-1e15, 1e-1)
1290 -1e+16
1291 >>> try_div(-1e15, -1e-1)
1292 1e+16
1293 >>> try_div(1e15, 1e-15)
1294 9.999999999999999e+29
1296 >>> print(type(try_div(10, 2)))
1297 <class 'int'>
1298 >>> print(type(try_div(10, 3)))
1299 <class 'float'>
1300 >>> print(type(try_div(10, 0.5)))
1301 <class 'int'>
1303 >>> from math import inf, nan
1304 >>> try:
1305 ... try_div(1.0, 0)
1306 ... except ZeroDivisionError as zde:
1307 ... print("by zero" in str(zde))
1308 True
1310 >>> try:
1311 ... try_div(1.0, -0.0)
1312 ... except ZeroDivisionError as zde:
1313 ... print("by zero" in str(zde))
1314 True
1316 >>> try:
1317 ... try_div(inf, 0)
1318 ... except ValueError as ve:
1319 ... print(ve)
1320 Value must be finite, but is inf.
1322 >>> try:
1323 ... try_div(-inf, 0)
1324 ... except ValueError as ve:
1325 ... print(ve)
1326 Value must be finite, but is -inf.
1328 >>> try:
1329 ... try_div(nan, 0)
1330 ... except ValueError as ve:
1331 ... print(ve)
1332 Value must be finite, but is nan.
1334 >>> try:
1335 ... try_div(1, inf)
1336 ... except ValueError as ve:
1337 ... print(ve)
1338 Value must be finite, but is inf.
1340 >>> try:
1341 ... try_div(1, -inf)
1342 ... except ValueError as ve:
1343 ... print(ve)
1344 Value must be finite, but is -inf.
1346 >>> try:
1347 ... try_div(1, nan)
1348 ... except ValueError as ve:
1349 ... print(ve)
1350 Value must be finite, but is nan.
1352 >>> try:
1353 ... try_div(1e300, 1e-60)
1354 ... except ValueError as ve:
1355 ... print(ve)
1356 Result must be finite, but is 1e+300/1e-60=inf.
1357 """
1358 ib: Final[int | float] = try_int(b)
1359 if isinstance(ib, int):
1360 return try_float_int_div(a, ib)
1361 val: Final[float] = a / ib
1362 if not isfinite(val):
1363 raise ValueError(f"Result must be finite, but is {a}/{b}={val}.")
1364 return __try_int(val)
1367#: the maximum value of a root that can be computed with floats exactly
1368__MAX_I_ROOT: Final[int] = __DBL_INT_LIMIT_P_I * __DBL_INT_LIMIT_P_I
1371def try_int_sqrt(value: int) -> int | float:
1372 """
1373 Try to compute the square root of a potentially large integer.
1375 :param value: the value
1376 :returns: the square root
1377 :raises ValueError: if `value` is negative
1378 :raises TypeError: if `value` is not an integer
1380 >>> try_int_sqrt(0)
1381 0
1383 >>> try_int_sqrt(1)
1384 1
1386 >>> try_int_sqrt(2)
1387 1.4142135623730951
1389 >>> try_int_sqrt(3)
1390 1.7320508075688772
1392 >>> try_int_sqrt(4)
1393 2
1395 >>> try_int_sqrt(5)
1396 2.23606797749979
1398 >>> try_int_sqrt(6)
1399 2.449489742783178
1401 >>> try_int_sqrt(7)
1402 2.6457513110645907
1404 >>> try_int_sqrt(8)
1405 2.8284271247461903
1407 >>> try_int_sqrt(9)
1408 3
1410 # exact result: 67108864.0000000074505805969238277
1411 >>> try_int_sqrt(4503599627370497)
1412 67108864
1413 >>> 67108864 * 67108864
1414 4503599627370496
1415 >>> sqrt(4503599627370497)
1416 67108864.0
1417 >>> sqrt(4503599627370497) * sqrt(4503599627370497)
1418 4503599627370496.0
1420 # exact result: 1592262918131443.14115595358963
1421 >>> try_int_sqrt(2535301200456458802993406410753)
1422 1592262918131443.2
1423 >>> sqrt(2535301200456458802993406410753)
1424 1592262918131443.2
1426 # exact result: 6369051672525772.564623814
1427 >>> try_int_sqrt(40564819207303340847894502572033)
1428 6369051672525773
1429 >>> sqrt(40564819207303340847894502572033)
1430 6369051672525773.0
1432 # exact result: 50952413380206180.51699051486817387
1433 >>> try_int_sqrt(2596148429267413814265248164610049)
1434 50952413380206181
1435 >>> sqrt(2596148429267413814265248164610049)
1436 5.0952413380206184e+16
1438 # exact result: 47695509376267.99690952215843525
1439 >>> try_int_sqrt(2274861614661668407597778085)
1440 47695509376267.99
1441 >>> sqrt(2274861614661668407597778085)
1442 47695509376267.99
1444 # exact result: 9067560306493833.1123015448971368313360
1445 >>> try_int_sqrt(82220649911902536690031728766315)
1446 9067560306493833
1447 >>> sqrt(82220649911902536690031728766315)
1448 9067560306493832.0
1450 >>> try_int_sqrt(1156)
1451 34
1452 >>> 34 * 34
1453 1156
1454 >>> sqrt(1156)
1455 34.0
1456 >>> 34.0 * 34.0
1457 1156.0
1459 >>> try_int_sqrt(1005)
1460 31.701734968294716
1461 >>> 31.701734968294716 * 31.701734968294716
1462 1005.0
1463 >>> sqrt(1005)
1464 31.701734968294716
1465 >>> 31.701734968294716 * 31.701734968294716
1466 1005.0
1468 exact result: 1098367625620897554397104127853022914763109648022\
1469928865503114153469686909343624968339609542505832728796367409822636937\
147028593951807995466301001184452657840914432
1471 >>> try_int_sqrt(int("1206411441012088169768424908631547135410050\
1472450349701156359323012992324468898745458674194715627653148741645085002\
1473880167432962708099995812635821183919553390204438671018341579206970136\
1474807811815836079357669821219116858017489215282754293788095448310134150\
14756291035205862448784848059094859987648259778470316291228729945882624"))
1476 10983676256208975543971041278530229147631096480229288655031141534\
1477696869093436249683396095425058327287963674098226369372859395180799546\
14786301001184452657840914432
1480 # exact result: 112519976.73369080909552361
1481 >>> try_int_sqrt(12660745164150321)
1482 112519976.73369081
1483 >>> 112519976.73369081 * 112519976.73369081
1484 1.2660745164150322e+16
1485 >>> sqrt(12660745164150321)
1486 112519976.7336908
1487 >>> 112519976.7336908 * 112519976.7336908
1488 1.2660745164150318e+16
1490 >>> try_int_sqrt(12369445361672285)
1491 111218008.26157734
1492 >>> sqrt(12369445361672285)
1493 111218008.26157734
1495 # exact result: 94906265.624251558157461955425
1496 >>> try_int_sqrt(9007199254740993)
1497 94906265.62425156
1498 >>> 94906265.62425156 * 94906265.62425156
1499 9007199254740994.0
1500 >>> sqrt(9007199254740993)
1501 94906265.62425156
1502 >>> 94906265.62425156 * 94906265.62425156
1503 9007199254740994.0
1505 # exact result: 126969687.206733737782866
1506 >>> try_int_sqrt(16121301469375805)
1507 126969687.20673373
1508 >>> 126969687.20673373 * 126969687.20673373
1509 1.6121301469375804e+16
1510 >>> sqrt(16121301469375805)
1511 126969687.20673373
1512 >>> 126969687.20673373 * 126969687.20673373
1513 1.6121301469375804e+16
1515 # exact result: 94906265.6242515686941740831
1516 # here we are off a bit!
1517 >>> try_int_sqrt(9007199254740995)
1518 94906265.62425156
1519 >>> 94906265.62425156 * 94906265.62425156
1520 9007199254740994.0
1521 >>> sqrt(9007199254740995)
1522 94906265.62425157
1523 >>> 94906265.62425157 * 94906265.62425157
1524 9007199254740996.0
1526 # exact result: 102406758.28296330267545316
1527 >>> try_int_sqrt(10487144142025273)
1528 102406758.2829633
1529 >>> 102406758.2829633 * 102406758.2829633
1530 1.0487144142025274e+16
1531 >>> sqrt(10487144142025273)
1532 102406758.28296329
1533 >>> 102406758.28296329 * 102406758.28296329
1534 1.048714414202527e+16
1536 # exact result: 101168874.5492688823358
1537 >>> try_int_sqrt(10235141177565705)
1538 101168874.54926889
1539 >>> 101168874.54926889 * 101168874.54926889
1540 1.0235141177565706e+16
1541 >>> sqrt(10235141177565705)
1542 101168874.54926887
1543 >>> 101168874.54926887 * 101168874.54926887
1544 1.0235141177565702e+16
1546 # exact result: 123961449.976073299398431984
1547 >>> try_int_sqrt(15366441080170523)
1548 123961449.9760733
1549 >>> 123961449.9760733 * 123961449.9760733
1550 1.5366441080170522e+16
1551 >>> sqrt(15366441080170523)
1552 123961449.97607331
1553 >>> 123961449.97607331 * 123961449.97607331
1554 1.5366441080170526e+16
1556 # exact result: 4760418939079673.01527272985
1557 >>> try_int_sqrt(22661588475548439582669426672241)
1558 4760418939079673
1559 >>> 4760418939079673 * 4760418939079673
1560 22661588475548439437260241786929
1561 >>> sqrt(22661588475548439582669426672241)
1562 4760418939079673.0
1563 >>> 4760418939079673.0 * 4760418939079673.0
1564 2.266158847554844e+31
1566 # exact result: 5712179292532910.79362200453777547
1567 >>> try_int_sqrt(32628992270041785263905793906381)
1568 5712179292532911
1569 >>> 5712179292532911 * 5712179292532911
1570 32628992270041787621642018133921
1571 >>> sqrt(32628992270041785263905793906381)
1572 5712179292532911.0
1573 >>> 5712179292532911.0 * 5712179292532911.0
1574 3.2628992270041787e+31
1576 >>> try:
1577 ... try_int_sqrt(-1)
1578 ... except ValueError as ve:
1579 ... print(ve)
1580 Compute the root of -1 ... really?
1582 >>> try:
1583 ... try_int_sqrt(1.0)
1584 ... except TypeError as te:
1585 ... print(te)
1586 value should be an instance of int but is float, namely 1.0.
1587 """
1588 if not isinstance(value, int):
1589 raise type_error(value, "value", int)
1590 if value < 0:
1591 raise ValueError(f"Compute the root of {value} ... really?")
1593 # First, let's compute the integer root. This is basically the
1594 # rounded-down version of the actual root. The integer root (isqrt) is the
1595 # lower limit for the result.
1596 # In the odd chance that this is already the correct result, we can
1597 # directly stop and return it.
1598 result_low: Final[int] = isqrt(value)
1599 diff_low: Final[int] = value - (result_low * result_low)
1600 if diff_low <= 0:
1601 # Notice: If we get here, then seemingly `isqrt(value) == sqrt(value)`
1602 # in Python's implementation if `value` the result fits into the
1603 # float range (I think).
1604 return result_low
1606 # First, we use the floating point sqrt for all numbers that can exactly
1607 # be represented as floating point numbers. Of course we try to convert
1608 # the result to integers.
1609 if value <= __DBL_INT_LIMIT_P_I: # default to the normal Python sqrt.
1610 return __try_int(sqrt(value)) # we can compute the exact square root
1612 # `value` is bigger than 2 ** 53 and definitely does not fit into a float
1613 # without losing precision.
1614 # We cannot accurately compute the root of value, because transforming
1615 # value to an int will already lead to a loss of precision.
1616 # However, what if sqrt(value) < 2 ** 53?
1617 # In this case, we *could* represent some fractional digits in the
1618 # result. But we cannot get them using `sqrt`. So we do a trick:
1619 # `root(a) = root(a * mul * mul) / mul`.
1620 # We compute the integer square root of `value` times some value `mul`.
1621 # We pick `mul` just large enough so that the result of
1622 # `isqrt(mul * mul * value)` will still be `<= __DBL_INT_LIMIT_P_I` and
1623 # thus fits into a `float` nicely. We then get the approximate fractional
1624 # part by dividing by `mul`.
1625 if result_low < __DBL_INT_LIMIT_P_I:
1626 mul: int = __DBL_INT_LIMIT_P_I // result_low
1627 if mul > 1:
1628 # We can proceed like before, just do the integer root at a higher
1629 # resolution. In this high resolution, we compute both the upper
1630 # and the lower bound for the root. We then pick the one closer to
1631 # the actual value, rounding up on draw situations. This value is
1632 # then divided by the multiplier to give us the maximum precision.
1633 new_value: Final[int] = value * mul * mul
1634 new_low: Final[int] = isqrt(new_value)
1635 new_diff_low: Final[int] = new_value - (new_low * new_low)
1636 new_high: Final[int] = new_low + 1
1637 new_diff_high: Final[int] = (new_high * new_high) - new_value
1638 return try_int_div(
1639 new_high if new_diff_high <= new_diff_low else new_low, mul)
1641 #: If we get here, then there is just no way to get useful fractional
1642 #: parts. We then just check if we should round up the result or return
1643 #: the rounded-down result.
1644 result_up: Final[int] = result_low + 1
1645 diff_up: int = (result_up * result_up) - value
1646 return result_up if diff_up <= diff_low else result_low
1649def try_int_add(a: int, b: int | float) -> int | float:
1650 """
1651 Try to add a floating point number to an integer.
1653 :param a: the integer
1654 :param b: the floating point number
1655 :returns: `a + b` or the best possible approximation thereof
1656 :raises TypeError: if `a` is not an integer or if `b` is neither a
1657 float nor an integer
1658 :raises ValueError: if `b` or the result is not finite
1660 >>> try_int_add(5, 7)
1661 12
1663 >>> try_int_add(5, 7.0)
1664 12
1666 >>> try_int_add(0, -8670.320148166094)
1667 -8670.320148166094
1668 >>> 0 + -8670.320148166094
1669 -8670.320148166094
1671 >>> try_int_add(-63710, 100.96227261264141)
1672 -63609.03772738736
1673 >>> -63710 + 100.96227261264141
1674 -63609.03772738736
1676 >>> try_int_add(77, 12975.955050422272)
1677 13052.955050422272
1678 >>> 77 + 12975.955050422272
1679 13052.955050422272
1681 >>> try_int_add(-308129344193738, 62995516.01169562)
1682 -308129281198222
1683 >>> -308129344193738 + 62995516.01169562
1684 -308129281198222.0
1686 >>> try_int_add(-2158504468760619, -1.3773316665252534e+16)
1687 -1.5931821134013152e+16
1688 >>> -2158504468760619 + -1.3773316665252534e+16
1689 -1.5931821134013152e+16
1691 >>> try_int_add(-960433622582960, 1.491132239895968e+16)
1692 1.395088877637672e+16
1693 >>> -960433622582960 + 1.491132239895968e+16
1694 1.395088877637672e+16
1696 >>> # exact result: 10796862382206072.70684135
1697 >>> try_int_add(10796862236149287, 146056785.70684135)
1698 10796862382206073
1699 >>> 10796862236149287 + 146056785.70684135
1700 1.0796862382206074e+16
1702 >>> # exact result: -11909678744561796.5206623
1703 ... try_int_add(-11909677351933537, -1392628259.5206623)
1704 -11909678744561797
1705 >>> -11909677351933537 + -1392628259.5206623
1706 -1.1909678744561796e+16
1708 >>> # exact result: 8991519996993845.25
1709 ... try_int_add(9257476766666634, -265956769672788.75)
1710 8991519996993845
1711 >>> 9257476766666634 + -265956769672788.75
1712 8991519996993845.0
1714 >>> v = int("-9166650131241408540833319855375552663116961087945581\
17156489173691561634548053405237489064")
1716 >>> try_int_add(v, 6.147962494740932e+217)
1717 6.147962494740932e+217
1718 >>> v + 6.147962494740932e+217
1719 6.147962494740932e+217
1721 >>> # exact result: 2060196266381720280000783609573994641953401509142\
17220431778715465940577471030.192914550695235
1723 ... v = int("2060196266381720280000783609573994641953401509142043\
17241778715465940577470980")
1725 >>> try_int_add(v, 50.192914550695235)
1726 20601962663817202800007836095739946419534015091420431778715465940\
1727577471030
1728 >>> v + 50.192914550695235
1729 2.0601962663817203e+73
1731 >>> try:
1732 ... try_int_add(2.0, 1)
1733 ... except TypeError as te:
1734 ... print(te)
1735 a should be an instance of int but is float, namely 2.0.
1737 >>> try:
1738 ... try_int_add(2, "1")
1739 ... except TypeError as te:
1740 ... print(te)
1741 b should be an instance of any in {float, int} but is str, namely '1'.
1743 >>> from math import inf
1744 >>> try:
1745 ... try_int_add(2, inf)
1746 ... except ValueError as ve:
1747 ... print(ve)
1748 b=inf is not finite
1749 """
1750 if not isinstance(a, int):
1751 raise type_error(a, "a", int)
1752 if isinstance(b, int):
1753 return a + b
1754 if not isinstance(b, float):
1755 raise type_error(b, "b", (int, float))
1756 if not isfinite(b):
1757 raise ValueError(f"{b=} is not finite")
1759 # First we attempt to turn b into an integer, because that would solve all
1760 # of our problems.
1761 b = __try_int(b)
1762 if isinstance(b, int):
1763 return a + b # We are lucky, the result is an integer
1765 b_num, b_denom = float_to_frac(b)
1766 int_num: Final[int] = b_num // b_denom
1767 int_res: Final[int] = a + int_num
1769 a_exact: Final[bool] = __DBL_INT_LIMIT_N_I < a < __DBL_INT_LIMIT_P_I
1770 b_exact: Final[bool] = __DBL_INT_LIMIT_N_I < b < __DBL_INT_LIMIT_P_I
1771 res_exact: Final[bool] = \
1772 __DBL_INT_LIMIT_N_I < int_res < __DBL_INT_LIMIT_P_I
1773 if a_exact and b_exact and res_exact:
1774 # We know that the result should fit well into the float range.
1775 # So we can just compute it normally
1776 return __try_int(a + b)
1778 if not b_exact:
1779 # Now if we get here, we are in a strange territory.
1780 # The floating point character of `b` will definitely pollute the
1781 # result. Regardless of what we do, we will not just have a rounding
1782 # error that costs us a fractional part, but it will cost decimals.
1783 # The right thing to do may be to return a float here, because we do
1784 # know that floats have a limited resolution and the returned value
1785 # may be biased.
1786 float_res: Final[float] = a + b
1787 if isfinite(float_res):
1788 return __try_int(float_res)
1790 # If we get here, then b is either an exactly representable float or the
1791 # result of adding a to b would no longer be finite.
1792 # If `b` is an exactly represented float, this means that the result does
1793 # not fit into a float. So we just try to round the result.
1794 # We will lose a fractional part, but the integer part will be exact.
1795 # `a` is an integer, so it is exact anyway. The integer part of `b`
1796 # can be represented as exact integer as well. So this means that we
1797 # will lose the fractional part only.
1798 # We can do the same thing if the result of the computation would not be
1799 # finite. Although it would be a bit pretentious to round in such a
1800 # situation ... well ... why not.
1801 b_num -= int_num * b_denom
1802 round_up: Final[bool] = abs(b_num + b_num) >= b_denom
1803 return (int_res - 1) if (round_up and (b_num < 0)) else (
1804 (int_res + 1) if round_up and (b_num > 0) else int_res)
1807def try_int_mul(a: int, b: int | float) -> int | float:
1808 """
1809 Try to multiply an integer with an int or float as exactly as possible.
1811 :param a: the integer
1812 :param b: the int or float to multiply `a` with
1813 :returns: `a * b`
1814 :raises ValueError: if `b` or the result is not finite
1815 :raises TypeError: if `a` is not an integer or if `b` is neither an
1816 integer nor a float
1818 >>> try_int_mul(6, 5)
1819 30
1821 # exact result: -111038109230780524.216538356
1822 >>> try_int_mul(197262324754, -562895.673916714)
1823 -111038109230780524
1824 >>> 197262324754 * -562895.673916714
1825 -1.1103810923078053e+17
1827 >>> try_int_mul(4, -2493374.0)
1828 -9973496
1829 >>> 4 * -2493374.0
1830 -9973496.0
1832 # exact result: -805144077682.7549712841791
1833 >>> try_int_mul(609329061, -1321.3616897926931)
1834 -805144077682.755
1835 >>> 609329061 * -1321.3616897926931
1836 -805144077682.755
1838 # exact result: -88939650274621002534.99
1839 >>> try_int_mul(-6548165, 13582377700412.406)
1840 -88939650274621004172
1841 >>> -6548165 * 13582377700412.406
1842 -8.8939650274621e+19
1844 >>> try_int_mul(4, 0.687279486538305)
1845 2.74911794615322
1846 >>> 4 * 0.687279486538305
1847 2.74911794615322
1849 # exact result: -2236563847561524626.733
1850 >>> try_int_mul(21396228, -104530754091.86725)
1851 -2236563847561524627
1852 >>> 21396228 * -104530754091.86725
1853 -2.2365638475615245e+18
1855 # exact result: -92649832027598387270282.5408
1856 >>> try_int_mul(29187432758, -3174305626527.0176)
1857 -92649832027598386631807
1858 >>> 29187432758 * -3174305626527.0176
1859 -9.264983202759838e+22
1861 # exact result: 47954872443652456553018463.12996
1862 >>> try_int_mul(-317420410641789, -151076839534.96564)
1863 47954872443652455666473176
1864 >>> -317420410641789 * -151076839534.96564
1865 4.795487244365246e+25
1867 # exact result: 369200712310299349798.80066193866
1868 >>> try_int_mul(8136505182920565, 45375.834465796564)
1869 369200712310299353646
1870 >>> 8136505182920565 * 45375.834465796564
1871 3.6920071231029936e+20
1873 # exact result: 431520767093145743090.73845486
1874 >>> try_int_mul(40196153594795, 10735374.619252708)
1875 431520767093145743091
1876 >>> 40196153594795 * 10735374.619252708
1877 4.315207670931457e+20
1879 # exact result: -250242005217172713.52783326
1880 >>> try_int_mul(27941562579, -8955905.90217194)
1881 -250242005217172703
1882 >>> 27941562579 * -8955905.90217194
1883 -2.502420052171727e+17
1885 # exact result: -6563728914129924.848948421
1886 >>> try_int_mul(-672426819, 9761253.906991959)
1887 -6563728914129925
1888 >>> -672426819 * 9761253.906991959
1889 -6563728914129925.0
1891 >>> try_int_mul(14059, 1.0673811010650016e+16)
1892 1.5006310899872858e+20
1893 >>> 14059 * 1.0673811010650016e+16
1894 1.5006310899872858e+20
1896 # exact result: 14493050353163113.126430160675
1897 >>> try_int_mul(240712887635, 60208.867483403505)
1898 14493050353163113
1899 >>> 240712887635 * 60208.867483403505
1900 1.4493050353163114e+16
1902 # exact result: 805460953505875910367.5205722154
1903 >>> try_int_mul(1812115257906061, 444486.6020479314)
1904 805460953505875915662
1905 >>> 1812115257906061 * 444486.6020479314
1906 8.054609535058759e+20
1908 # exact result: -1384354228892504466.5554728510606
1909 >>> try_int_mul(6815245310862468, -203.12610416033795)
1910 -1384354228892504435
1911 >>> 6815245310862468 * -203.12610416033795
1912 -1.3843542288925043e+18
1914 # exact result: -572028608656496.423924280629596728
1915 >>> try_int_mul(11587431214834713, -0.049366300265425656)
1916 -572028608656496.4
1917 >>> 11587431214834713 * -0.049366300265425656
1918 -572028608656496.4
1920 # exact result: 1128618866534760.28918431873755142
1921 >>> try_int_mul(16354919666787217, 0.06900791257487526)
1922 1128618866534760.2
1923 >>> 16354919666787217 * 0.06900791257487526
1924 1128618866534760.2
1926 # exact result: -2507326755278071.50624700782133248
1927 >>> try_int_mul(13217245192529664, -0.18970116077556032)
1928 -2507326755278071.5
1929 >>> 13217245192529664 * -0.18970116077556032
1930 -2507326755278071.5
1932 # exact result: 696151526057376.88027486041356184
1933 >>> try_int_mul(-10333677547666606, -0.06736725844658964)
1934 696151526057376.9
1935 >>> -10333677547666606 * -0.06736725844658964
1936 696151526057376.9
1938 # exact result: -958450150333374.5128889837837098
1939 >>> try_int_mul(12016909016999122, -0.0797584594322509)
1940 -958450150333374.6
1941 >>> 12016909016999122 * -0.0797584594322509
1942 -958450150333374.6
1944 >>> aa = int("1318537368301039863303586092319665276843530233302383387022\
19458761465225501763768872549741384158750496877681759291226540877199284501122993\
19460897105528797412214008383330709731057075605034370259681835287681493225337651\
19473905721656778533145739528500419884652958325779506781860934858448618309985340\
19482653730863759125601710698375950989559971436924737005754922330642277477754688\
19494919382044527420457991975491785609852030831998308070776211565814942350933642\
1950672902063132158594646597242361650005228312919254855")
1951 >>> try_int_mul(aa, -2.6624992899981142e+135)
1952 -351060480693750064453835292428076534998065626248205859394224131928297807\
195337557248636560809666436142921728329271829636053027677161961750893317035607449\
195488120284425121093171262696954695038088240282639132134536157970777415620680544\
195577787260819949647198753734696904695444416894546646340086090596255528370630342\
195639912680252313956743223994856279867123453950294756395973723697089090287742438\
195742755397630769057958666859505455598999506335122025009809406354300546655548757\
195803308334026066509069233835834019214049819194441000000000000000000000000000000\
195900000000000000000000000000000000000000000000000000000000000000000000000000000\
19600000000000000
1962 # exact result: 5115993211447460900.43715653698
1963 >>> try_int_mul(45247701671134, 113066.36630145647)
1964 5115993211447460734
1965 >>> 45247701671134 * 113066.36630145647
1966 5.115993211447461e+18
1968 # exact result: -125197981872321984234
1969 >>> try_int_mul(-15606149727, 8022349142.0)
1970 -125197981872321984234
1971 >>> -15606149727 * 8022349142.0
1972 -1.2519798187232199e+20
1974 # exact result: -348481045.61578014504
1975 >>> try_int_mul(6636, -52513.71995415614)
1976 -348481045.6157802
1977 >>> 6636 * -52513.71995415614
1978 -348481045.6157802
1980 # exact result: -339789407482572717.3787168852228
1981 >>> try_int_mul(6921658507965838, -49.0907500119406)
1982 -339789407482572714
1983 >>> 6921658507965838 * -49.0907500119406
1984 -3.3978940748257274e+17
1986 >>> try_int_mul(2366231432701, 9061910680864392.0)
1987 2.1442577893390244e+28
1988 >>> 2366231432701 * 9061910680864392.0
1989 2.1442577893390244e+28
1991 >>> try_int_mul(11382697409900285, 7338977711.446167)
1992 8.35373625873942e+25
1993 >>> 11382697409900285 * 7338977711.446167
1994 8.35373625873942e+25
1996 >>> try_int_mul(34207518885, -6554.28955920917)
1997 -224205983874406
1998 >>> 34207518885 * -6554.28955920917
1999 -224205983874406.0
2001 >>> try_int_mul(35107, -165228482913.08173)
2002 -5800676349629560
2003 >>> 35107 * -165228482913.08173
2004 -5800676349629560.0
2006 >>> try_int_mul(0, 2.4281702332336544e+16)
2007 0
2008 >>> 0 * 2.4281702332336544e+16
2009 0.0
2011 >>> try_int_mul(12299117359251193, 9482167930204820.0)
2012 1.1662229619371705e+32
2013 >>> 12299117359251193 * 9482167930204820.0
2014 1.1662229619371705e+32
2016 >>> try_int_mul(-11025104822925196, 0.20926918490209712)
2017 -2307214699753735.5
2018 >>> -11025104822925196 * 0.20926918490209712
2019 -2307214699753735.5
2021 >>> try_int_mul(9772540954912922, -0.46316069211643107)
2022 -4526256832413637
2023 >>> 9772540954912922 * -0.46316069211643107
2024 -4526256832413637.0
2026 >>> a = -5687274133508874816611305835797802819969961090128107452007652532\
202773368270677846755602944621609056451583453036433989268229052391280449456056415\
202835305434613932448168719851117464179317780697744165312772461358166814824851088\
202955666554914988361150741132171265507858468795070096289596042533878836544303330\
203051629205606376256678385083639086123757879299418359388159156263956657201968562\
203131234444965574888174813926197455099511160764637390234826490840919289969902451\
203219032766058028744
2033 >>> try_int_mul(a, 1.6152587208080178e+161)
2034 -91864191417760728566594708387860610684587465634907240089126522260899489\
20354868393273335550289848260675410562832758047321131061871920910825594187776263\
20363813438746416917351911213760538943029477664003307403545581300547688099127531\
20375980188627547208265662112980855054467534738906286741579697000621904552812416\
20389446067183418151530080010856381487158544646128107795979443668739119314808361\
20397661789396847122441264057280246286323595226375142154153566223973380730500186\
20400346809116255685129263413549101637215712126487779567515862772796494902477027\
20414283909310368263635531679756438464790102625606997105530169121933171318181638\
2042719123552835758718976000
2044 >>> a = 3765608478313035700785399638168771339557519363527174997097642640\
20456101495713891805694367423527904175961734525627539554843115375392781571623329\
20462447297269149929791925360073769054144096521088071580437368293552550840688369\
20472608265449974834262318405099511472680054858496169995743896513251354009716226\
20482514585220536136586004979988630733951340879593101821106230203914627052267837\
20491572821101974821796182780210158355368107881592427373376547394885537235348770\
2050037983728077456443610490231815763426207048140659081123096064113083255321
2051 >>> try_int_mul(a, 3.4397561272117625e+192)
2052 129527748359578257806492201438402698334484205908662618646067106845154998\
20532115342535199421721007878815369298874224123455721441548991298088516366970587\
20546954884520363675490158067710598514210872880348223211816340777337079830796450\
20551538806420032828931583145759690145309074737296451653410762104587461282286330\
20565613446806304563553562786109972723062095583351926917494446975708601932868972\
20578706300360490387733148782540598727225279861244661365412091714003810616131531\
20584481842956460108582107814498584521025354908493431977057047306288665587544613\
20596391274648488448957696316691763417067525251280127682030399365602278708061765\
20601082290234901228437827481292269177791129383042667337751797004896760132865057\
206119242926784445427888800399360
2063 >>> a = 129139500057625933922412781529753661193714022177289159193286727\
2064341869510538391068183373334814894358463049932698275602586001788553855337370\
2065614701810798567624656761308982494637834371899037091828942757328272879402878\
2066026516716840890321410558877108818475215456025987413249018189775618174448780\
2067086119164868545066265500186250891155310591180702358002
2068 >>> try_int_mul(a, 1107055232.6334295)
2069 14296455927845986412272147350433876910362542595277171600320805129204174\
2070701824227341993224688128568101787206140720134279287421051283535763162532066\
20711082072819079131257940844247255813910836282210665242651249270543058782206016\
20720195030665164058974557661094866963676618764040698636345181586979396240926480\
207338619836809751492028454165243512720617990761805723389
2075 >>> try_int_mul(1202489289292969, 2.1583639585424923e+306)
2076 259540954254332074038246669681477283939748496620440148998643367300751188\
20772740876153253237092741716795754997976766921219000512012754932543147420651232\
20785520218655906535605653525109031074378131051185629676951714011087271116671446\
20790899827404105545452888405653019460560445425746060708059494631661799648373661\
20805341276121474415984640
2082 # exact result: -7952338024951495584.4756757
2083 >>> try_int_mul(-131722798246, 60371766.54947795)
2084 -7952338024951495584
2085 >>> -131722798246 * 60371766.54947795
2086 -7.952338024951496e+18
2088 # exact result: 374987726685442496656857448.375
2089 >>> try_int_mul(-197846874313873, -1895343194002.375)
2090 374987726685442496656857448
2091 >>> -197846874313873 * -1895343194002.375
2092 3.749877266854425e+26
2094 # exact result: 10775411722410520324.9
2095 >>> try_int_mul(187295, 57531763914736.22)
2096 10775411722410520091
2097 >>> 187295 * 57531763914736.22
2098 1.077541172241052e+19
2100 >>> try:
2101 ... try_int_mul(5.0, 1)
2102 ... except TypeError as te:
2103 ... print(te)
2104 a should be an instance of int but is float, namely 5.0.
2106 >>> try:
2107 ... try_int_mul(5, "x")
2108 ... except TypeError as te:
2109 ... print(te)
2110 b should be an instance of any in {float, int} but is str, namely 'x'.
2112 >>> from math import inf
2113 >>> try:
2114 ... try_int_mul(5, inf)
2115 ... except ValueError as ve:
2116 ... print(ve)
2117 b=inf is not finite
2118 """
2119 if not isinstance(a, int):
2120 raise type_error(a, "a", int)
2121 if isinstance(b, int):
2122 return a * b
2123 if not isinstance(b, float):
2124 raise type_error(b, "b", (int, float))
2125 if not isfinite(b):
2126 raise ValueError(f"{b=} is not finite")
2128 # First we attempt to turn b into an integer, because that would solve all
2129 # of our problems.
2130 b = __try_int(b)
2131 if isinstance(b, int):
2132 return a * b # We are lucky, the result is an integer
2134 minus: bool = False
2135 if a < 0:
2136 a = -a
2137 minus = True
2138 if b < 0:
2139 b = -b
2140 minus = not minus
2142 # Try to get the result as floating point number
2143 float_res: int | float | None = None
2144 with suppress(ArithmeticError):
2145 float_res = a * b
2146 float_res = __try_int(float_res) if isfinite(float_res) else None
2148 # pylint: disable=R0916
2149 if (float_res is not None) and (isinstance(float_res, int) or (
2150 a >= __DBL_INT_LIMIT_P_I) or (b >= __DBL_INT_LIMIT_P_I) or (
2151 (a <= __DBL_INT_LIMIT_P_I) and (b <= __DBL_INT_LIMIT_P_I) and (
2152 float_res <= __DBL_INT_LIMIT_P_F))):
2153 # If float_res could be transformed to an int, then we are good.
2154 # If either a or b are outside of the range where we can represent
2155 # digits exactly, then there is nothing that we can do and we may
2156 # as well return the result of the floating point computation.
2157 # Trying to use integers would suggest a precision that we cannot
2158 # offer.
2159 # Alternatively, if everything falls into the range where we do not
2160 # have a loss of precision, then trying anything would be odd.
2161 # Using integer precision would be pretentious.
2162 return -float_res if minus else float_res # pylint: disable=E1130
2164 num, denom = float_to_frac(b)
2165 result = try_int_div(a * num, denom)
2166 return -result if minus else result
2169def ceil_div(a: int, b: int) -> int:
2170 """
2171 Compute a ceiling division of two integers.
2173 :param a: the number to be divided by `b`
2174 :param b: the number dividing `a`
2175 :returns: the rounded-up result of the division
2177 >>> ceil_div(1, 1)
2178 1
2179 >>> ceil_div(-1, 1)
2180 -1
2181 >>> ceil_div(-1, -1)
2182 1
2183 >>> ceil_div(1, -1)
2184 -1
2185 >>> ceil_div(98, 98)
2186 1
2187 >>> ceil_div(98, 99)
2188 1
2189 >>> ceil_div(98, 97)
2190 2
2191 >>> ceil_div(98, -97)
2192 -1
2193 >>> ceil_div(-98, -97)
2194 2
2195 >>> ceil_div(-98, 97)
2196 -1
2197 >>> ceil_div(3, 1)
2198 3
2199 >>> ceil_div(3, -1)
2200 -3
2201 >>> ceil_div(-3, 1)
2202 -3
2203 >>> ceil_div(-3, -1)
2204 3
2205 >>> ceil_div(3, 2)
2206 2
2207 >>> ceil_div(3, -2)
2208 -1
2209 >>> ceil_div(-3, 2)
2210 -1
2211 >>> ceil_div(-3, -2)
2212 2
2213 >>> ceil_div(3, 3)
2214 1
2215 >>> ceil_div(3, 4)
2216 1
2217 >>> ceil_div(3, -4)
2218 0
2219 >>> ceil_div(-3, 4)
2220 0
2221 >>> ceil_div(-3, -4)
2222 1
2223 >>> ceil_div(4, 1)
2224 4
2225 >>> ceil_div(4, 2)
2226 2
2227 >>> ceil_div(4, 3)
2228 2
2229 >>> ceil_div(4, 4)
2230 1
2231 >>> ceil_div(4, 5)
2232 1
2233 >>> ceil_div(4, 23242398)
2234 1
2235 >>> ceil_div(4, -23242398)
2236 0
2237 >>> ceil_div(-4, 23242398)
2238 0
2239 >>> ceil_div(-4, -23242398)
2240 1
2241 >>> ceil_div(0, 1)
2242 0
2243 >>> ceil_div(0, -1)
2244 0
2245 >>> ceil_div(-0, 1)
2246 0
2247 >>> ceil_div(-0, -1)
2248 0
2249 >>> try:
2250 ... ceil_div(1, 0)
2251 ... except ZeroDivisionError as zde:
2252 ... print("by zero" in str(zde))
2253 True
2254 >>> try:
2255 ... ceil_div(-1, 0)
2256 ... except ZeroDivisionError as zde:
2257 ... print("by zero" in str(zde))
2258 True
2259 >>> try:
2260 ... ceil_div(1, -0)
2261 ... except ZeroDivisionError as zde:
2262 ... print("by zero" in str(zde))
2263 True
2264 >>> try:
2265 ... ceil_div(-1, -0)
2266 ... except ZeroDivisionError as zde:
2267 ... print("by zero" in str(zde))
2268 True
2269 """
2270 return -((-a) // b)