# Casting out nines.
import operator
def _residue(n: int) -> int:
"""
Return residue modulo 9 in 0..8.
In Python, n % 9 always yields a non-negative result, even for negative n.
"""
return n % 9
def _casting_out_nines(op, x: int, y: int) -> bool:
"""
General casting out nines check for a binary operation.
Compares the residue of the true operation with the residue of the
operation applied to the operands' residues.
"""
z = _residue(x)
w = _residue(y)
return _residue(op(x, y)) == _residue(op(z, w))
def casting_out_nines_add(x: int, y: int) -> bool:
"""Check addition using casting out nines."""
return _casting_out_nines(operator.add, x, y)
def casting_out_nines_sub(x: int, y: int) -> bool:
"""Check subtraction using casting out nines."""
return _casting_out_nines(operator.sub, x, y)
def casting_out_nines_mul(x: int, y: int) -> bool:
"""Check multiplication using casting out nines."""
return _casting_out_nines(operator.mul, x, y)
def casting_out_nines_pow(x: int, y: int) -> bool:
"""
Check exponentiation using casting out nines.
Uses modular exponentiation to respect cycles modulo 9.
"""
return pow(x, y, 9) == pow(_residue(x), y, 9)
import random
def randomized_tests(num_trials=5000):
"""
Run randomized tests for casting out nines utilities.
Validates congruence modulo 9 for add, sub, mul, pow.
"""
for _ in range(num_trials):
x = random.randint(-10**6, 10**6)
y = random.randint(-10**6, 10**6)
# Addition
assert casting_out_nines_add(x, y), f"Addition failed for {x}, {y}"
# Subtraction
assert casting_out_nines_sub(x, y), f"Subtraction failed for {x}, {y}"
# Multiplication
assert casting_out_nines_mul(x, y), f"Multiplication failed for {x}, {y}"
for _ in range(num_trials):
x = random.randint(-10**6, 10**6)
y = random.randint(0, 19)
# Exponentiation: restrict y to small non-negative values
assert casting_out_nines_pow(x, y), f"Exponentiation failed for {x}^{y}"
print(f"All {num_trials} randomized tests passed!")
# Example run
if __name__ == "__main__":
randomized_tests(5000)
IyBDYXN0aW5nIG91dCBuaW5lcy4KCmltcG9ydCBvcGVyYXRvcgoKZGVmIF9yZXNpZHVlKG46IGludCkgLT4gaW50OgogICAgIiIiCiAgICBSZXR1cm4gcmVzaWR1ZSBtb2R1bG8gOSBpbiAwLi44LgogICAgSW4gUHl0aG9uLCBuICUgOSBhbHdheXMgeWllbGRzIGEgbm9uLW5lZ2F0aXZlIHJlc3VsdCwgZXZlbiBmb3IgbmVnYXRpdmUgbi4KICAgICIiIgogICAgcmV0dXJuIG4gJSA5CgpkZWYgX2Nhc3Rpbmdfb3V0X25pbmVzKG9wLCB4OiBpbnQsIHk6IGludCkgLT4gYm9vbDoKICAgICIiIgogICAgR2VuZXJhbCBjYXN0aW5nIG91dCBuaW5lcyBjaGVjayBmb3IgYSBiaW5hcnkgb3BlcmF0aW9uLgogICAgQ29tcGFyZXMgdGhlIHJlc2lkdWUgb2YgdGhlIHRydWUgb3BlcmF0aW9uIHdpdGggdGhlIHJlc2lkdWUgb2YgdGhlCiAgICBvcGVyYXRpb24gYXBwbGllZCB0byB0aGUgb3BlcmFuZHMnIHJlc2lkdWVzLgogICAgIiIiCiAgICB6ID0gX3Jlc2lkdWUoeCkKICAgIHcgPSBfcmVzaWR1ZSh5KQogICAgcmV0dXJuIF9yZXNpZHVlKG9wKHgsIHkpKSA9PSBfcmVzaWR1ZShvcCh6LCB3KSkKCmRlZiBjYXN0aW5nX291dF9uaW5lc19hZGQoeDogaW50LCB5OiBpbnQpIC0+IGJvb2w6CiAgICAiIiJDaGVjayBhZGRpdGlvbiB1c2luZyBjYXN0aW5nIG91dCBuaW5lcy4iIiIKICAgIHJldHVybiBfY2FzdGluZ19vdXRfbmluZXMob3BlcmF0b3IuYWRkLCB4LCB5KQoKZGVmIGNhc3Rpbmdfb3V0X25pbmVzX3N1Yih4OiBpbnQsIHk6IGludCkgLT4gYm9vbDoKICAgICIiIkNoZWNrIHN1YnRyYWN0aW9uIHVzaW5nIGNhc3Rpbmcgb3V0IG5pbmVzLiIiIgogICAgcmV0dXJuIF9jYXN0aW5nX291dF9uaW5lcyhvcGVyYXRvci5zdWIsIHgsIHkpCgpkZWYgY2FzdGluZ19vdXRfbmluZXNfbXVsKHg6IGludCwgeTogaW50KSAtPiBib29sOgogICAgIiIiQ2hlY2sgbXVsdGlwbGljYXRpb24gdXNpbmcgY2FzdGluZyBvdXQgbmluZXMuIiIiCiAgICByZXR1cm4gX2Nhc3Rpbmdfb3V0X25pbmVzKG9wZXJhdG9yLm11bCwgeCwgeSkKCmRlZiBjYXN0aW5nX291dF9uaW5lc19wb3coeDogaW50LCB5OiBpbnQpIC0+IGJvb2w6CiAgICAiIiIKICAgIENoZWNrIGV4cG9uZW50aWF0aW9uIHVzaW5nIGNhc3Rpbmcgb3V0IG5pbmVzLgogICAgVXNlcyBtb2R1bGFyIGV4cG9uZW50aWF0aW9uIHRvIHJlc3BlY3QgY3ljbGVzIG1vZHVsbyA5LgogICAgIiIiCiAgICByZXR1cm4gcG93KHgsIHksIDkpID09IHBvdyhfcmVzaWR1ZSh4KSwgeSwgOSkKCmltcG9ydCByYW5kb20KCmRlZiByYW5kb21pemVkX3Rlc3RzKG51bV90cmlhbHM9NTAwMCk6CiAgICAiIiIKICAgIFJ1biByYW5kb21pemVkIHRlc3RzIGZvciBjYXN0aW5nIG91dCBuaW5lcyB1dGlsaXRpZXMuCiAgICBWYWxpZGF0ZXMgY29uZ3J1ZW5jZSBtb2R1bG8gOSBmb3IgYWRkLCBzdWIsIG11bCwgcG93LgogICAgIiIiCiAgICBmb3IgXyBpbiByYW5nZShudW1fdHJpYWxzKToKICAgICAgICB4ID0gcmFuZG9tLnJhbmRpbnQoLTEwKio2LCAxMCoqNikKICAgICAgICB5ID0gcmFuZG9tLnJhbmRpbnQoLTEwKio2LCAxMCoqNikKCiAgICAgICAgIyBBZGRpdGlvbgogICAgICAgIGFzc2VydCBjYXN0aW5nX291dF9uaW5lc19hZGQoeCwgeSksIGYiQWRkaXRpb24gZmFpbGVkIGZvciB7eH0sIHt5fSIKCiAgICAgICAgIyBTdWJ0cmFjdGlvbgogICAgICAgIGFzc2VydCBjYXN0aW5nX291dF9uaW5lc19zdWIoeCwgeSksIGYiU3VidHJhY3Rpb24gZmFpbGVkIGZvciB7eH0sIHt5fSIKCiAgICAgICAgIyBNdWx0aXBsaWNhdGlvbgogICAgICAgIGFzc2VydCBjYXN0aW5nX291dF9uaW5lc19tdWwoeCwgeSksIGYiTXVsdGlwbGljYXRpb24gZmFpbGVkIGZvciB7eH0sIHt5fSIKCiAgICBmb3IgXyBpbiByYW5nZShudW1fdHJpYWxzKToKICAgICAgICB4ID0gcmFuZG9tLnJhbmRpbnQoLTEwKio2LCAxMCoqNikKICAgICAgICB5ID0gcmFuZG9tLnJhbmRpbnQoMCwgMTkpCgogICAgICAgICMgRXhwb25lbnRpYXRpb246IHJlc3RyaWN0IHkgdG8gc21hbGwgbm9uLW5lZ2F0aXZlIHZhbHVlcwogICAgICAgIGFzc2VydCBjYXN0aW5nX291dF9uaW5lc19wb3coeCwgeSksIGYiRXhwb25lbnRpYXRpb24gZmFpbGVkIGZvciB7eH1ee3l9IgoKICAgIHByaW50KGYiQWxsIHtudW1fdHJpYWxzfSByYW5kb21pemVkIHRlc3RzIHBhc3NlZCEiKQoKIyBFeGFtcGxlIHJ1bgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgcmFuZG9taXplZF90ZXN0cyg1MDAwKQ==