Return Real number x to exact (numerator, denominator) pair. >>> _exact_ratio(0.25) (1, 4) x is expected to be an int, Fraction, Decimal or float.
(x)
| 285 | |
| 286 | |
| 287 | def _exact_ratio(x): |
| 288 | """Return Real number x to exact (numerator, denominator) pair. |
| 289 | |
| 290 | >>> _exact_ratio(0.25) |
| 291 | (1, 4) |
| 292 | |
| 293 | x is expected to be an int, Fraction, Decimal or float. |
| 294 | """ |
| 295 | |
| 296 | # XXX We should revisit whether using fractions to accumulate exact |
| 297 | # ratios is the right way to go. |
| 298 | |
| 299 | # The integer ratios for binary floats can have numerators or |
| 300 | # denominators with over 300 decimal digits. The problem is more |
| 301 | # acute with decimal floats where the default decimal context |
| 302 | # supports a huge range of exponents from Emin=-999999 to |
| 303 | # Emax=999999. When expanded with as_integer_ratio(), numbers like |
| 304 | # Decimal('3.14E+5000') and Decimal('3.14E-5000') have large |
| 305 | # numerators or denominators that will slow computation. |
| 306 | |
| 307 | # When the integer ratios are accumulated as fractions, the size |
| 308 | # grows to cover the full range from the smallest magnitude to the |
| 309 | # largest. For example, Fraction(3.14E+300) + Fraction(3.14E-300), |
| 310 | # has a 616 digit numerator. Likewise, |
| 311 | # Fraction(Decimal('3.14E+5000')) + Fraction(Decimal('3.14E-5000')) |
| 312 | # has 10,003 digit numerator. |
| 313 | |
| 314 | # This doesn't seem to have been problem in practice, but it is a |
| 315 | # potential pitfall. |
| 316 | |
| 317 | try: |
| 318 | return x.as_integer_ratio() |
| 319 | except AttributeError: |
| 320 | pass |
| 321 | except (OverflowError, ValueError): |
| 322 | # float NAN or INF. |
| 323 | assert not _isfinite(x) |
| 324 | return (x, None) |
| 325 | try: |
| 326 | # x may be an Integral ABC. |
| 327 | return (x.numerator, x.denominator) |
| 328 | except AttributeError: |
| 329 | msg = f"can't convert type '{type(x).__name__}' to numerator/denominator" |
| 330 | raise TypeError(msg) |
| 331 | |
| 332 | |
| 333 | def _convert(value, T): |
nothing calls this directly
no test coverage detected