# SPDX-License-Identifier: MIT
"""Explore exact integers, numeric conversions, rounding and modular inverses."""

# Integers stay exact as they grow.
large = int("123456789012345678901234567890")
print("An exact integer:", large)
print("Quotient and remainder:", divmod(large, 97))

# At a halfway point, round chooses the even multiple.
print("Nearest ten:", round(25, -1), round(35, -1), round(-25, -1))
print("Nearest hundred:", round(1450, -2), round(1550, -2))

# Floats have finite precision, so two nearby large integers can become equal.
print("Float defaults:", float(), float(False), float(True))
print("A fractional value:", float(1.25))
print("Two integers as floats:", float(2 ** 53), float(2 ** 53 + 1))
try:
    float(10 ** 400)
except OverflowError:
    print("That integer is too large for a float.")


class Count:
    def __init__(self, value):
        self.value = value

    def __int__(self):
        return self.value

    def __index__(self):
        return self.value


class Reading:
    def __init__(self, value):
        self.value = value

    def __float__(self):
        return self.value


# Classes can supply ordinary numeric conversion methods.
count = Count(7)
print("Count as an integer:", int(count))
print("Count as a float:", float(count))
print("Reading as a float:", float(Reading(1.25)))

# A modular inverse multiplies back to one under the chosen modulus.
inverse = pow(3, -1, 11)
print("Inverse of 3 modulo 11:", inverse)
print("Check the inverse:", (3 * inverse) % 11)
try:
    pow(6, -1, 9)
except ValueError:
    print("6 has no inverse modulo 9.")
