diff --git a/jsonschema/_keywords.py b/jsonschema/_keywords.py index f30f9541..5c03e06d 100644 --- a/jsonschema/_keywords.py +++ b/jsonschema/_keywords.py @@ -169,21 +169,24 @@ def multipleOf(validator, dB, instance, schema): return if isinstance(dB, float): - quotient = instance / dB - try: - failed = int(quotient) != quotient - except OverflowError: - # When `instance` is large and `dB` is less than one, - # quotient can overflow to infinity; and then casting to int - # raises an error. - # - # In this case we fall back to Fraction logic, which is - # exact and cannot overflow. The performance is also - # acceptable: we try the fast all-float option first, and - # we know that fraction(dB) can have at most a few hundred - # digits in each part. The worst-case slowdown is therefore - # for already-slow enormous integers or Decimals. - failed = (Fraction(instance) / Fraction(dB)).denominator != 1 + if dB.is_integer(): + failed = instance % int(dB) + else: + quotient = instance / dB + try: + failed = int(quotient) != quotient + except OverflowError: + # When `instance` is large and `dB` is less than one, + # quotient can overflow to infinity; and then casting to int + # raises an error. + # + # In this case we fall back to Fraction logic, which is + # exact and cannot overflow. The performance is also + # acceptable: we try the fast all-float option first, and + # we know that fraction(dB) can have at most a few hundred + # digits in each part. The worst-case slowdown is therefore + # for already-slow enormous integers or Decimals. + failed = (Fraction(instance) / Fraction(dB)).denominator != 1 else: failed = instance % dB diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py index 7d8a4c5c..6ed9bdfc 100644 --- a/jsonschema/tests/test_validators.py +++ b/jsonschema/tests/test_validators.py @@ -1667,6 +1667,11 @@ def test_invalid_instances_are_not_valid(self): schema, instance = self.invalid self.assertFalse(self.Validator(schema).is_valid(instance)) + def test_large_integer_multiple_of_integer_valued_float(self): + schema = {"type": "integer", "multipleOf": 11.0} + instance = 9007199254740995 + self.assertTrue(self.Validator(schema).is_valid(instance)) + def test_non_existent_properties_are_ignored(self): self.Validator({object(): object()}).validate(instance=object())