Coverage for pycommons / math / int_math.py: 100%
197 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 03:04 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-11 03:04 +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(zde)
750 integer division or modulo by zero
752 >>> try:
753 ... try_int_div(1, 0)
754 ... except ZeroDivisionError as zde:
755 ... print(zde)
756 integer division or modulo by zero
758 >>> try:
759 ... try_int_div(-1, 0)
760 ... except ZeroDivisionError as zde:
761 ... print(zde)
762 integer division or modulo by zero
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(zde)
1209 integer division or modulo by zero
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)
1255#: the maximum value of a root that can be computed with floats exactly
1256__MAX_I_ROOT: Final[int] = __DBL_INT_LIMIT_P_I * __DBL_INT_LIMIT_P_I
1259def try_int_sqrt(value: int) -> int | float:
1260 """
1261 Try to compute the square root of a potentially large integer.
1263 :param value: the value
1264 :returns: the square root
1265 :raises ValueError: if `value` is negative
1266 :raises TypeError: if `value` is not an integer
1268 >>> try_int_sqrt(0)
1269 0
1271 >>> try_int_sqrt(1)
1272 1
1274 >>> try_int_sqrt(2)
1275 1.4142135623730951
1277 >>> try_int_sqrt(3)
1278 1.7320508075688772
1280 >>> try_int_sqrt(4)
1281 2
1283 >>> try_int_sqrt(5)
1284 2.23606797749979
1286 >>> try_int_sqrt(6)
1287 2.449489742783178
1289 >>> try_int_sqrt(7)
1290 2.6457513110645907
1292 >>> try_int_sqrt(8)
1293 2.8284271247461903
1295 >>> try_int_sqrt(9)
1296 3
1298 # exact result: 67108864.0000000074505805969238277
1299 >>> try_int_sqrt(4503599627370497)
1300 67108864
1301 >>> 67108864 * 67108864
1302 4503599627370496
1303 >>> sqrt(4503599627370497)
1304 67108864.0
1305 >>> sqrt(4503599627370497) * sqrt(4503599627370497)
1306 4503599627370496.0
1308 # exact result: 1592262918131443.14115595358963
1309 >>> try_int_sqrt(2535301200456458802993406410753)
1310 1592262918131443.2
1311 >>> sqrt(2535301200456458802993406410753)
1312 1592262918131443.2
1314 # exact result: 6369051672525772.564623814
1315 >>> try_int_sqrt(40564819207303340847894502572033)
1316 6369051672525773
1317 >>> sqrt(40564819207303340847894502572033)
1318 6369051672525773.0
1320 # exact result: 50952413380206180.51699051486817387
1321 >>> try_int_sqrt(2596148429267413814265248164610049)
1322 50952413380206181
1323 >>> sqrt(2596148429267413814265248164610049)
1324 5.0952413380206184e+16
1326 # exact result: 47695509376267.99690952215843525
1327 >>> try_int_sqrt(2274861614661668407597778085)
1328 47695509376267.99
1329 >>> sqrt(2274861614661668407597778085)
1330 47695509376267.99
1332 # exact result: 9067560306493833.1123015448971368313360
1333 >>> try_int_sqrt(82220649911902536690031728766315)
1334 9067560306493833
1335 >>> sqrt(82220649911902536690031728766315)
1336 9067560306493832.0
1338 >>> try_int_sqrt(1156)
1339 34
1340 >>> 34 * 34
1341 1156
1342 >>> sqrt(1156)
1343 34.0
1344 >>> 34.0 * 34.0
1345 1156.0
1347 >>> try_int_sqrt(1005)
1348 31.701734968294716
1349 >>> 31.701734968294716 * 31.701734968294716
1350 1005.0
1351 >>> sqrt(1005)
1352 31.701734968294716
1353 >>> 31.701734968294716 * 31.701734968294716
1354 1005.0
1356 exact result: 1098367625620897554397104127853022914763109648022\
1357928865503114153469686909343624968339609542505832728796367409822636937\
135828593951807995466301001184452657840914432
1359 >>> try_int_sqrt(int("1206411441012088169768424908631547135410050\
1360450349701156359323012992324468898745458674194715627653148741645085002\
1361880167432962708099995812635821183919553390204438671018341579206970136\
1362807811815836079357669821219116858017489215282754293788095448310134150\
13636291035205862448784848059094859987648259778470316291228729945882624"))
1364 10983676256208975543971041278530229147631096480229288655031141534\
1365696869093436249683396095425058327287963674098226369372859395180799546\
13666301001184452657840914432
1368 # exact result: 112519976.73369080909552361
1369 >>> try_int_sqrt(12660745164150321)
1370 112519976.73369081
1371 >>> 112519976.73369081 * 112519976.73369081
1372 1.2660745164150322e+16
1373 >>> sqrt(12660745164150321)
1374 112519976.7336908
1375 >>> 112519976.7336908 * 112519976.7336908
1376 1.2660745164150318e+16
1378 >>> try_int_sqrt(12369445361672285)
1379 111218008.26157734
1380 >>> sqrt(12369445361672285)
1381 111218008.26157734
1383 # exact result: 94906265.624251558157461955425
1384 >>> try_int_sqrt(9007199254740993)
1385 94906265.62425156
1386 >>> 94906265.62425156 * 94906265.62425156
1387 9007199254740994.0
1388 >>> sqrt(9007199254740993)
1389 94906265.62425156
1390 >>> 94906265.62425156 * 94906265.62425156
1391 9007199254740994.0
1393 # exact result: 126969687.206733737782866
1394 >>> try_int_sqrt(16121301469375805)
1395 126969687.20673373
1396 >>> 126969687.20673373 * 126969687.20673373
1397 1.6121301469375804e+16
1398 >>> sqrt(16121301469375805)
1399 126969687.20673373
1400 >>> 126969687.20673373 * 126969687.20673373
1401 1.6121301469375804e+16
1403 # exact result: 94906265.6242515686941740831
1404 # here we are off a bit!
1405 >>> try_int_sqrt(9007199254740995)
1406 94906265.62425156
1407 >>> 94906265.62425156 * 94906265.62425156
1408 9007199254740994.0
1409 >>> sqrt(9007199254740995)
1410 94906265.62425157
1411 >>> 94906265.62425157 * 94906265.62425157
1412 9007199254740996.0
1414 # exact result: 102406758.28296330267545316
1415 >>> try_int_sqrt(10487144142025273)
1416 102406758.2829633
1417 >>> 102406758.2829633 * 102406758.2829633
1418 1.0487144142025274e+16
1419 >>> sqrt(10487144142025273)
1420 102406758.28296329
1421 >>> 102406758.28296329 * 102406758.28296329
1422 1.048714414202527e+16
1424 # exact result: 101168874.5492688823358
1425 >>> try_int_sqrt(10235141177565705)
1426 101168874.54926889
1427 >>> 101168874.54926889 * 101168874.54926889
1428 1.0235141177565706e+16
1429 >>> sqrt(10235141177565705)
1430 101168874.54926887
1431 >>> 101168874.54926887 * 101168874.54926887
1432 1.0235141177565702e+16
1434 # exact result: 123961449.976073299398431984
1435 >>> try_int_sqrt(15366441080170523)
1436 123961449.9760733
1437 >>> 123961449.9760733 * 123961449.9760733
1438 1.5366441080170522e+16
1439 >>> sqrt(15366441080170523)
1440 123961449.97607331
1441 >>> 123961449.97607331 * 123961449.97607331
1442 1.5366441080170526e+16
1444 # exact result: 4760418939079673.01527272985
1445 >>> try_int_sqrt(22661588475548439582669426672241)
1446 4760418939079673
1447 >>> 4760418939079673 * 4760418939079673
1448 22661588475548439437260241786929
1449 >>> sqrt(22661588475548439582669426672241)
1450 4760418939079673.0
1451 >>> 4760418939079673.0 * 4760418939079673.0
1452 2.266158847554844e+31
1454 # exact result: 5712179292532910.79362200453777547
1455 >>> try_int_sqrt(32628992270041785263905793906381)
1456 5712179292532911
1457 >>> 5712179292532911 * 5712179292532911
1458 32628992270041787621642018133921
1459 >>> sqrt(32628992270041785263905793906381)
1460 5712179292532911.0
1461 >>> 5712179292532911.0 * 5712179292532911.0
1462 3.2628992270041787e+31
1464 >>> try:
1465 ... try_int_sqrt(-1)
1466 ... except ValueError as ve:
1467 ... print(ve)
1468 Compute the root of -1 ... really?
1470 >>> try:
1471 ... try_int_sqrt(1.0)
1472 ... except TypeError as te:
1473 ... print(te)
1474 value should be an instance of int but is float, namely 1.0.
1475 """
1476 if not isinstance(value, int):
1477 raise type_error(value, "value", int)
1478 if value < 0:
1479 raise ValueError(f"Compute the root of {value} ... really?")
1481 # First, let's compute the integer root. This is basically the
1482 # rounded-down version of the actual root. The integer root (isqrt) is the
1483 # lower limit for the result.
1484 # In the odd chance that this is already the correct result, we can
1485 # directly stop and return it.
1486 result_low: Final[int] = isqrt(value)
1487 diff_low: Final[int] = value - (result_low * result_low)
1488 if diff_low <= 0:
1489 # Notice: If we get here, then seemingly `isqrt(value) == sqrt(value)`
1490 # in Python's implementation if `value` the result fits into the
1491 # float range (I think).
1492 return result_low
1494 # First, we use the floating point sqrt for all numbers that can exactly
1495 # be represented as floating point numbers. Of course we try to convert
1496 # the result to integers.
1497 if value <= __DBL_INT_LIMIT_P_I: # default to the normal Python sqrt.
1498 return __try_int(sqrt(value)) # we can compute the exact square root
1500 # `value` is bigger than 2 ** 53 and definitely does not fit into a float
1501 # without losing precision.
1502 # We cannot accurately compute the root of value, because transforming
1503 # value to an int will already lead to a loss of precision.
1504 # However, what if sqrt(value) < 2 ** 53?
1505 # In this case, we *could* represent some fractional digits in the
1506 # result. But we cannot get them using `sqrt`. So we do a trick:
1507 # `root(a) = root(a * mul * mul) / mul`.
1508 # We compute the integer square root of `value` times some value `mul`.
1509 # We pick `mul` just large enough so that the result of
1510 # `isqrt(mul * mul * value)` will still be `<= __DBL_INT_LIMIT_P_I` and
1511 # thus fits into a `float` nicely. We then get the approximate fractional
1512 # part by dividing by `mul`.
1513 if result_low < __DBL_INT_LIMIT_P_I:
1514 mul: int = __DBL_INT_LIMIT_P_I // result_low
1515 if mul > 1:
1516 # We can proceed like before, just do the integer root at a higher
1517 # resolution. In this high resolution, we compute both the upper
1518 # and the lower bound for the root. We then pick the one closer to
1519 # the actual value, rounding up on draw situations. This value is
1520 # then divided by the multiplier to give us the maximum precision.
1521 new_value: Final[int] = value * mul * mul
1522 new_low: Final[int] = isqrt(new_value)
1523 new_diff_low: Final[int] = new_value - (new_low * new_low)
1524 new_high: Final[int] = new_low + 1
1525 new_diff_high: Final[int] = (new_high * new_high) - new_value
1526 return try_int_div(
1527 new_high if new_diff_high <= new_diff_low else new_low, mul)
1529 #: If we get here, then there is just no way to get useful fractional
1530 #: parts. We then just check if we should round up the result or return
1531 #: the rounded-down result.
1532 result_up: Final[int] = result_low + 1
1533 diff_up: int = (result_up * result_up) - value
1534 return result_up if diff_up <= diff_low else result_low
1537def try_int_add(a: int, b: int | float) -> int | float:
1538 """
1539 Try to add a floating point number to an integer.
1541 :param a: the integer
1542 :param b: the floating point number
1543 :returns: `a + b` or the best possible approximation thereof
1544 :raises TypeError: if `a` is not an integer or if `b` is neither a
1545 float nor an integer
1546 :raises ValueError: if `b` or the result is not finite
1548 >>> try_int_add(5, 7)
1549 12
1551 >>> try_int_add(5, 7.0)
1552 12
1554 >>> try_int_add(0, -8670.320148166094)
1555 -8670.320148166094
1556 >>> 0 + -8670.320148166094
1557 -8670.320148166094
1559 >>> try_int_add(-63710, 100.96227261264141)
1560 -63609.03772738736
1561 >>> -63710 + 100.96227261264141
1562 -63609.03772738736
1564 >>> try_int_add(77, 12975.955050422272)
1565 13052.955050422272
1566 >>> 77 + 12975.955050422272
1567 13052.955050422272
1569 >>> try_int_add(-308129344193738, 62995516.01169562)
1570 -308129281198222
1571 >>> -308129344193738 + 62995516.01169562
1572 -308129281198222.0
1574 >>> try_int_add(-2158504468760619, -1.3773316665252534e+16)
1575 -1.5931821134013152e+16
1576 >>> -2158504468760619 + -1.3773316665252534e+16
1577 -1.5931821134013152e+16
1579 >>> try_int_add(-960433622582960, 1.491132239895968e+16)
1580 1.395088877637672e+16
1581 >>> -960433622582960 + 1.491132239895968e+16
1582 1.395088877637672e+16
1584 # exact result: 10796862382206072.70684135
1585 >>> try_int_add(10796862236149287, 146056785.70684135)
1586 10796862382206073
1587 >>> 10796862236149287 + 146056785.70684135
1588 1.0796862382206074e+16
1590 # exact result: -11909678744561796.5206623
1591 >>> try_int_add(-11909677351933537, -1392628259.5206623)
1592 -11909678744561797
1593 >>> -11909677351933537 + -1392628259.5206623
1594 -1.1909678744561796e+16
1596 # exact result: 8991519996993845.25
1597 >>> try_int_add(9257476766666634, -265956769672788.75)
1598 8991519996993845
1599 >>> 9257476766666634 + -265956769672788.75
1600 8991519996993845.0
1602 >>> v = int("-9166650131241408540833319855375552663116961087945581\
16036489173691561634548053405237489064")
1604 >>> try_int_add(v, 6.147962494740932e+217)
1605 6.147962494740932e+217
1606 >>> v + 6.147962494740932e+217
1607 6.147962494740932e+217
1609 exact result: 2060196266381720280000783609573994641953401509142\
16100431778715465940577471030.192914550695235
1611 >>> v = int("2060196266381720280000783609573994641953401509142043\
16121778715465940577470980")
1613 >>> try_int_add(v, 50.192914550695235)
1614 20601962663817202800007836095739946419534015091420431778715465940\
1615577471030
1616 >>> v + 50.192914550695235
1617 2.0601962663817203e+73
1619 >>> try:
1620 ... try_int_add(2.0, 1)
1621 ... except TypeError as te:
1622 ... print(te)
1623 a should be an instance of int but is float, namely 2.0.
1625 >>> try:
1626 ... try_int_add(2, "1")
1627 ... except TypeError as te:
1628 ... print(te)
1629 b should be an instance of any in {float, int} but is str, namely '1'.
1631 >>> from math import inf
1632 >>> try:
1633 ... try_int_add(2, inf)
1634 ... except ValueError as ve:
1635 ... print(ve)
1636 b=inf is not finite
1637 """
1638 if not isinstance(a, int):
1639 raise type_error(a, "a", int)
1640 if isinstance(b, int):
1641 return a + b
1642 if not isinstance(b, float):
1643 raise type_error(b, "b", (int, float))
1644 if not isfinite(b):
1645 raise ValueError(f"{b=} is not finite")
1647 # First we attempt to turn b into an integer, because that would solve all
1648 # of our problems.
1649 b = __try_int(b)
1650 if isinstance(b, int):
1651 return a + b # We are lucky, the result is an integer
1653 b_num, b_denom = float_to_frac(b)
1654 int_num: Final[int] = b_num // b_denom
1655 int_res: Final[int] = a + int_num
1657 a_exact: Final[bool] = __DBL_INT_LIMIT_N_I < a < __DBL_INT_LIMIT_P_I
1658 b_exact: Final[bool] = __DBL_INT_LIMIT_N_I < b < __DBL_INT_LIMIT_P_I
1659 res_exact: Final[bool] = \
1660 __DBL_INT_LIMIT_N_I < int_res < __DBL_INT_LIMIT_P_I
1661 if a_exact and b_exact and res_exact:
1662 # We know that the result should fit well into the float range.
1663 # So we can just compute it normally
1664 return __try_int(a + b)
1666 if not b_exact:
1667 # Now if we get here, we are in a strange territory.
1668 # The floating point character of `b` will definitely pollute the
1669 # result. Regardless of what we do, we will not just have a rounding
1670 # error that costs us a fractional part, but it will cost decimals.
1671 # The right thing to do may be to return a float here, because we do
1672 # know that floats have a limited resolution and the returned value
1673 # may be biased.
1674 float_res: Final[float] = a + b
1675 if isfinite(float_res):
1676 return __try_int(float_res)
1678 # If we get here, then b is either an exactly representable float or the
1679 # result of adding a to b would no longer be finite.
1680 # If `b` is an exactly represented float, this means that the result does
1681 # not fit into a float. So we just try to round the result.
1682 # We will lose a fractional part, but the integer part will be exact.
1683 # `a` is an integer, so it is exact anyway. The integer part of `b`
1684 # can be represented as exact integer as well. So this means that we
1685 # will lose the fractional part only.
1686 # We can do the same thing if the result of the computation would not be
1687 # finite. Although it would be a bit pretentious to round in such a
1688 # situation ... well ... why not.
1689 b_num -= int_num * b_denom
1690 round_up: Final[bool] = abs(b_num + b_num) >= b_denom
1691 return (int_res - 1) if (round_up and (b_num < 0)) else (
1692 (int_res + 1) if round_up and (b_num > 0) else int_res)
1695def try_int_mul(a: int, b: int | float) -> int | float:
1696 """
1697 Try to multiply an integer with an int or float as exactly as possible.
1699 :param a: the integer
1700 :param b: the int or float to multiply `a` with
1701 :returns: `a * b`
1702 :raises ValueError: if `b` or the result is not finite
1703 :raises TypeError: if `a` is not an integer or if `b` is neither an
1704 integer nor a float
1706 >>> try_int_mul(6, 5)
1707 30
1709 # exact result: -111038109230780524.216538356
1710 >>> try_int_mul(197262324754, -562895.673916714)
1711 -111038109230780524
1712 >>> 197262324754 * -562895.673916714
1713 -1.1103810923078053e+17
1715 >>> try_int_mul(4, -2493374.0)
1716 -9973496
1717 >>> 4 * -2493374.0
1718 -9973496.0
1720 # exact result: -805144077682.7549712841791
1721 >>> try_int_mul(609329061, -1321.3616897926931)
1722 -805144077682.755
1723 >>> 609329061 * -1321.3616897926931
1724 -805144077682.755
1726 # exact result: -88939650274621002534.99
1727 >>> try_int_mul(-6548165, 13582377700412.406)
1728 -88939650274621004172
1729 >>> -6548165 * 13582377700412.406
1730 -8.8939650274621e+19
1732 >>> try_int_mul(4, 0.687279486538305)
1733 2.74911794615322
1734 >>> 4 * 0.687279486538305
1735 2.74911794615322
1737 # exact result: -2236563847561524626.733
1738 >>> try_int_mul(21396228, -104530754091.86725)
1739 -2236563847561524627
1740 >>> 21396228 * -104530754091.86725
1741 -2.2365638475615245e+18
1743 # exact result: -92649832027598387270282.5408
1744 >>> try_int_mul(29187432758, -3174305626527.0176)
1745 -92649832027598386631807
1746 >>> 29187432758 * -3174305626527.0176
1747 -9.264983202759838e+22
1749 # exact result: 47954872443652456553018463.12996
1750 >>> try_int_mul(-317420410641789, -151076839534.96564)
1751 47954872443652455666473176
1752 >>> -317420410641789 * -151076839534.96564
1753 4.795487244365246e+25
1755 # exact result: 369200712310299349798.80066193866
1756 >>> try_int_mul(8136505182920565, 45375.834465796564)
1757 369200712310299353646
1758 >>> 8136505182920565 * 45375.834465796564
1759 3.6920071231029936e+20
1761 # exact result: 431520767093145743090.73845486
1762 >>> try_int_mul(40196153594795, 10735374.619252708)
1763 431520767093145743091
1764 >>> 40196153594795 * 10735374.619252708
1765 4.315207670931457e+20
1767 # exact result: -250242005217172713.52783326
1768 >>> try_int_mul(27941562579, -8955905.90217194)
1769 -250242005217172703
1770 >>> 27941562579 * -8955905.90217194
1771 -2.502420052171727e+17
1773 # exact result: -6563728914129924.848948421
1774 >>> try_int_mul(-672426819, 9761253.906991959)
1775 -6563728914129925
1776 >>> -672426819 * 9761253.906991959
1777 -6563728914129925.0
1779 >>> try_int_mul(14059, 1.0673811010650016e+16)
1780 1.5006310899872858e+20
1781 >>> 14059 * 1.0673811010650016e+16
1782 1.5006310899872858e+20
1784 # exact result: 14493050353163113.126430160675
1785 >>> try_int_mul(240712887635, 60208.867483403505)
1786 14493050353163113
1787 >>> 240712887635 * 60208.867483403505
1788 1.4493050353163114e+16
1790 # exact result: 805460953505875910367.5205722154
1791 >>> try_int_mul(1812115257906061, 444486.6020479314)
1792 805460953505875915662
1793 >>> 1812115257906061 * 444486.6020479314
1794 8.054609535058759e+20
1796 # exact result: -1384354228892504466.5554728510606
1797 >>> try_int_mul(6815245310862468, -203.12610416033795)
1798 -1384354228892504435
1799 >>> 6815245310862468 * -203.12610416033795
1800 -1.3843542288925043e+18
1802 # exact result: -572028608656496.423924280629596728
1803 >>> try_int_mul(11587431214834713, -0.049366300265425656)
1804 -572028608656496.4
1805 >>> 11587431214834713 * -0.049366300265425656
1806 -572028608656496.4
1808 # exact result: 1128618866534760.28918431873755142
1809 >>> try_int_mul(16354919666787217, 0.06900791257487526)
1810 1128618866534760.2
1811 >>> 16354919666787217 * 0.06900791257487526
1812 1128618866534760.2
1814 # exact result: -2507326755278071.50624700782133248
1815 >>> try_int_mul(13217245192529664, -0.18970116077556032)
1816 -2507326755278071.5
1817 >>> 13217245192529664 * -0.18970116077556032
1818 -2507326755278071.5
1820 # exact result: 696151526057376.88027486041356184
1821 >>> try_int_mul(-10333677547666606, -0.06736725844658964)
1822 696151526057376.9
1823 >>> -10333677547666606 * -0.06736725844658964
1824 696151526057376.9
1826 # exact result: -958450150333374.5128889837837098
1827 >>> try_int_mul(12016909016999122, -0.0797584594322509)
1828 -958450150333374.6
1829 >>> 12016909016999122 * -0.0797584594322509
1830 -958450150333374.6
1832 >>> aa = int("1318537368301039863303586092319665276843530233302383387022\
18338761465225501763768872549741384158750496877681759291226540877199284501122993\
18340897105528797412214008383330709731057075605034370259681835287681493225337651\
18353905721656778533145739528500419884652958325779506781860934858448618309985340\
18362653730863759125601710698375950989559971436924737005754922330642277477754688\
18374919382044527420457991975491785609852030831998308070776211565814942350933642\
1838672902063132158594646597242361650005228312919254855")
1839 >>> try_int_mul(aa, -2.6624992899981142e+135)
1840 -351060480693750064453835292428076534998065626248205859394224131928297807\
184137557248636560809666436142921728329271829636053027677161961750893317035607449\
184288120284425121093171262696954695038088240282639132134536157970777415620680544\
184377787260819949647198753734696904695444416894546646340086090596255528370630342\
184439912680252313956743223994856279867123453950294756395973723697089090287742438\
184542755397630769057958666859505455598999506335122025009809406354300546655548757\
184603308334026066509069233835834019214049819194441000000000000000000000000000000\
184700000000000000000000000000000000000000000000000000000000000000000000000000000\
18480000000000000
1850 # exact result: 5115993211447460900.43715653698
1851 >>> try_int_mul(45247701671134, 113066.36630145647)
1852 5115993211447460734
1853 >>> 45247701671134 * 113066.36630145647
1854 5.115993211447461e+18
1856 # exact result: -125197981872321984234
1857 >>> try_int_mul(-15606149727, 8022349142.0)
1858 -125197981872321984234
1859 >>> -15606149727 * 8022349142.0
1860 -1.2519798187232199e+20
1862 # exact result: -348481045.61578014504
1863 >>> try_int_mul(6636, -52513.71995415614)
1864 -348481045.6157802
1865 >>> 6636 * -52513.71995415614
1866 -348481045.6157802
1868 # exact result: -339789407482572717.3787168852228
1869 >>> try_int_mul(6921658507965838, -49.0907500119406)
1870 -339789407482572714
1871 >>> 6921658507965838 * -49.0907500119406
1872 -3.3978940748257274e+17
1874 >>> try_int_mul(2366231432701, 9061910680864392.0)
1875 2.1442577893390244e+28
1876 >>> 2366231432701 * 9061910680864392.0
1877 2.1442577893390244e+28
1879 >>> try_int_mul(11382697409900285, 7338977711.446167)
1880 8.35373625873942e+25
1881 >>> 11382697409900285 * 7338977711.446167
1882 8.35373625873942e+25
1884 >>> try_int_mul(34207518885, -6554.28955920917)
1885 -224205983874406
1886 >>> 34207518885 * -6554.28955920917
1887 -224205983874406.0
1889 >>> try_int_mul(35107, -165228482913.08173)
1890 -5800676349629560
1891 >>> 35107 * -165228482913.08173
1892 -5800676349629560.0
1894 >>> try_int_mul(0, 2.4281702332336544e+16)
1895 0
1896 >>> 0 * 2.4281702332336544e+16
1897 0.0
1899 >>> try_int_mul(12299117359251193, 9482167930204820.0)
1900 1.1662229619371705e+32
1901 >>> 12299117359251193 * 9482167930204820.0
1902 1.1662229619371705e+32
1904 >>> try_int_mul(-11025104822925196, 0.20926918490209712)
1905 -2307214699753735.5
1906 >>> -11025104822925196 * 0.20926918490209712
1907 -2307214699753735.5
1909 >>> try_int_mul(9772540954912922, -0.46316069211643107)
1910 -4526256832413637
1911 >>> 9772540954912922 * -0.46316069211643107
1912 -4526256832413637.0
1914 >>> a = -5687274133508874816611305835797802819969961090128107452007652532\
191573368270677846755602944621609056451583453036433989268229052391280449456056415\
191635305434613932448168719851117464179317780697744165312772461358166814824851088\
191755666554914988361150741132171265507858468795070096289596042533878836544303330\
191851629205606376256678385083639086123757879299418359388159156263956657201968562\
191931234444965574888174813926197455099511160764637390234826490840919289969902451\
192019032766058028744
1921 >>> try_int_mul(a, 1.6152587208080178e+161)
1922 -91864191417760728566594708387860610684587465634907240089126522260899489\
19234868393273335550289848260675410562832758047321131061871920910825594187776263\
19243813438746416917351911213760538943029477664003307403545581300547688099127531\
19255980188627547208265662112980855054467534738906286741579697000621904552812416\
19269446067183418151530080010856381487158544646128107795979443668739119314808361\
19277661789396847122441264057280246286323595226375142154153566223973380730500186\
19280346809116255685129263413549101637215712126487779567515862772796494902477027\
19294283909310368263635531679756438464790102625606997105530169121933171318181638\
1930719123552835758718976000
1932 >>> a = 3765608478313035700785399638168771339557519363527174997097642640\
19336101495713891805694367423527904175961734525627539554843115375392781571623329\
19342447297269149929791925360073769054144096521088071580437368293552550840688369\
19352608265449974834262318405099511472680054858496169995743896513251354009716226\
19362514585220536136586004979988630733951340879593101821106230203914627052267837\
19371572821101974821796182780210158355368107881592427373376547394885537235348770\
1938037983728077456443610490231815763426207048140659081123096064113083255321
1939 >>> try_int_mul(a, 3.4397561272117625e+192)
1940 129527748359578257806492201438402698334484205908662618646067106845154998\
19412115342535199421721007878815369298874224123455721441548991298088516366970587\
19426954884520363675490158067710598514210872880348223211816340777337079830796450\
19431538806420032828931583145759690145309074737296451653410762104587461282286330\
19445613446806304563553562786109972723062095583351926917494446975708601932868972\
19458706300360490387733148782540598727225279861244661365412091714003810616131531\
19464481842956460108582107814498584521025354908493431977057047306288665587544613\
19476391274648488448957696316691763417067525251280127682030399365602278708061765\
19481082290234901228437827481292269177791129383042667337751797004896760132865057\
194919242926784445427888800399360
1951 >>> a = 129139500057625933922412781529753661193714022177289159193286727\
1952341869510538391068183373334814894358463049932698275602586001788553855337370\
1953614701810798567624656761308982494637834371899037091828942757328272879402878\
1954026516716840890321410558877108818475215456025987413249018189775618174448780\
1955086119164868545066265500186250891155310591180702358002
1956 >>> try_int_mul(a, 1107055232.6334295)
1957 14296455927845986412272147350433876910362542595277171600320805129204174\
1958701824227341993224688128568101787206140720134279287421051283535763162532066\
19591082072819079131257940844247255813910836282210665242651249270543058782206016\
19600195030665164058974557661094866963676618764040698636345181586979396240926480\
196138619836809751492028454165243512720617990761805723389
1963 >>> try_int_mul(1202489289292969, 2.1583639585424923e+306)
1964 259540954254332074038246669681477283939748496620440148998643367300751188\
19652740876153253237092741716795754997976766921219000512012754932543147420651232\
19665520218655906535605653525109031074378131051185629676951714011087271116671446\
19670899827404105545452888405653019460560445425746060708059494631661799648373661\
19685341276121474415984640
1970 # exact result: -7952338024951495584.4756757
1971 >>> try_int_mul(-131722798246, 60371766.54947795)
1972 -7952338024951495584
1973 >>> -131722798246 * 60371766.54947795
1974 -7.952338024951496e+18
1976 # exact result: 374987726685442496656857448.375
1977 >>> try_int_mul(-197846874313873, -1895343194002.375)
1978 374987726685442496656857448
1979 >>> -197846874313873 * -1895343194002.375
1980 3.749877266854425e+26
1982 # exact result: 10775411722410520324.9
1983 >>> try_int_mul(187295, 57531763914736.22)
1984 10775411722410520091
1985 >>> 187295 * 57531763914736.22
1986 1.077541172241052e+19
1988 >>> try:
1989 ... try_int_mul(5.0, 1)
1990 ... except TypeError as te:
1991 ... print(te)
1992 a should be an instance of int but is float, namely 5.0.
1994 >>> try:
1995 ... try_int_mul(5, "x")
1996 ... except TypeError as te:
1997 ... print(te)
1998 b should be an instance of any in {float, int} but is str, namely 'x'.
2000 >>> from math import inf
2001 >>> try:
2002 ... try_int_mul(5, inf)
2003 ... except ValueError as ve:
2004 ... print(ve)
2005 b=inf is not finite
2006 """
2007 if not isinstance(a, int):
2008 raise type_error(a, "a", int)
2009 if isinstance(b, int):
2010 return a * b
2011 if not isinstance(b, float):
2012 raise type_error(b, "b", (int, float))
2013 if not isfinite(b):
2014 raise ValueError(f"{b=} is not finite")
2016 # First we attempt to turn b into an integer, because that would solve all
2017 # of our problems.
2018 b = __try_int(b)
2019 if isinstance(b, int):
2020 return a * b # We are lucky, the result is an integer
2022 minus: bool = False
2023 if a < 0:
2024 a = -a
2025 minus = True
2026 if b < 0:
2027 b = -b
2028 minus = not minus
2030 # Try to get the result as floating point number
2031 float_res: int | float | None = None
2032 with suppress(ArithmeticError):
2033 float_res = a * b
2034 float_res = __try_int(float_res) if isfinite(float_res) else None
2036 # pylint: disable=R0916
2037 if (float_res is not None) and (isinstance(float_res, int) or (
2038 a >= __DBL_INT_LIMIT_P_I) or (b >= __DBL_INT_LIMIT_P_I) or (
2039 (a <= __DBL_INT_LIMIT_P_I) and (b <= __DBL_INT_LIMIT_P_I) and (
2040 float_res <= __DBL_INT_LIMIT_P_F))):
2041 # If float_res could be transformed to an int, then we are good.
2042 # If either a or b are outside of the range where we can represent
2043 # digits exactly, then there is nothing that we can do and we may
2044 # as well return the result of the floating point computation.
2045 # Trying to use integers would suggest a precision that we cannot
2046 # offer.
2047 # Alternatively, if everything falls into the range where we do not
2048 # have a loss of precision, then trying anything would be odd.
2049 # Using integer precision would be pretentious.
2050 return -float_res if minus else float_res # pylint: disable=E1130
2052 num, denom = float_to_frac(b)
2053 result = try_int_div(a * num, denom)
2054 return -result if minus else result
2057def ceil_div(a: int, b: int) -> int:
2058 """
2059 Compute a ceiling division of two integers.
2061 :param a: the number to be divided by `b`
2062 :param b: the number dividing `a`
2063 :returns: the rounded-up result of the division
2065 >>> ceil_div(1, 1)
2066 1
2067 >>> ceil_div(-1, 1)
2068 -1
2069 >>> ceil_div(-1, -1)
2070 1
2071 >>> ceil_div(1, -1)
2072 -1
2073 >>> ceil_div(98, 98)
2074 1
2075 >>> ceil_div(98, 99)
2076 1
2077 >>> ceil_div(98, 97)
2078 2
2079 >>> ceil_div(98, -97)
2080 -1
2081 >>> ceil_div(-98, -97)
2082 2
2083 >>> ceil_div(-98, 97)
2084 -1
2085 >>> ceil_div(3, 1)
2086 3
2087 >>> ceil_div(3, -1)
2088 -3
2089 >>> ceil_div(-3, 1)
2090 -3
2091 >>> ceil_div(-3, -1)
2092 3
2093 >>> ceil_div(3, 2)
2094 2
2095 >>> ceil_div(3, -2)
2096 -1
2097 >>> ceil_div(-3, 2)
2098 -1
2099 >>> ceil_div(-3, -2)
2100 2
2101 >>> ceil_div(3, 3)
2102 1
2103 >>> ceil_div(3, 4)
2104 1
2105 >>> ceil_div(3, -4)
2106 0
2107 >>> ceil_div(-3, 4)
2108 0
2109 >>> ceil_div(-3, -4)
2110 1
2111 >>> ceil_div(4, 1)
2112 4
2113 >>> ceil_div(4, 2)
2114 2
2115 >>> ceil_div(4, 3)
2116 2
2117 >>> ceil_div(4, 4)
2118 1
2119 >>> ceil_div(4, 5)
2120 1
2121 >>> ceil_div(4, 23242398)
2122 1
2123 >>> ceil_div(4, -23242398)
2124 0
2125 >>> ceil_div(-4, 23242398)
2126 0
2127 >>> ceil_div(-4, -23242398)
2128 1
2129 >>> ceil_div(0, 1)
2130 0
2131 >>> ceil_div(0, -1)
2132 0
2133 >>> ceil_div(-0, 1)
2134 0
2135 >>> ceil_div(-0, -1)
2136 0
2137 >>> try:
2138 ... ceil_div(1, 0)
2139 ... except ZeroDivisionError as ze:
2140 ... print(ze)
2141 integer division or modulo by zero
2142 >>> try:
2143 ... ceil_div(-1, 0)
2144 ... except ZeroDivisionError as ze:
2145 ... print(ze)
2146 integer division or modulo by zero
2147 >>> try:
2148 ... ceil_div(1, -0)
2149 ... except ZeroDivisionError as ze:
2150 ... print(ze)
2151 integer division or modulo by zero
2152 >>> try:
2153 ... ceil_div(-1, -0)
2154 ... except ZeroDivisionError as ze:
2155 ... print(ze)
2156 integer division or modulo by zero
2157 """
2158 return -((-a) // b)