Skip to content

Commit 08a8c22

Browse files
committed
Fix multipleOf with integer-valued float failing for large integers
When multipleOf is a float with an integer value (e.g. 11.0), convert it to int before performing the check. This avoids floating-point precision loss for instances beyond 2**53, where float division produces incorrect results. Per JSON Schema spec, numbers with zero fractional parts are integers. Fixes #1159
1 parent 5a5fa97 commit 08a8c22

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

jsonschema/_keywords.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ def multipleOf(validator, dB, instance, schema):
168168
if not validator.is_type(instance, "number"):
169169
return
170170

171+
# JSON Schema: numbers with zero fractional parts are integers.
172+
# Convert integer-valued floats (e.g. 11.0) to int to avoid
173+
# floating-point precision loss with large instances.
174+
if isinstance(dB, float) and dB.is_integer():
175+
dB = int(dB)
176+
171177
if isinstance(dB, float):
172178
quotient = instance / dB
173179
try:

jsonschema/tests/test_validators.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,23 @@ def test_multipleOf(self):
501501
)
502502
self.assertEqual(message, "3 is not a multiple of 2")
503503

504+
def test_multipleOf_integer_valued_float(self):
505+
"""Integer-valued floats like 11.0 should behave like integers (#1159).
506+
507+
Large integers beyond 2**53 lose precision in float division,
508+
so multipleOf with an integer-valued float must use integer
509+
arithmetic to avoid false negatives.
510+
"""
511+
instance = 9007199254740995 # 2**53 + 3, a multiple of 11
512+
# With integer divisor this passes
513+
validators.Draft202012Validator(
514+
{"type": "integer", "multipleOf": 11},
515+
).validate(instance)
516+
# With integer-valued float divisor this should also pass
517+
validators.Draft202012Validator(
518+
{"type": "integer", "multipleOf": 11.0},
519+
).validate(instance)
520+
504521
def test_minItems(self):
505522
message = self.message_for(instance=[], schema={"minItems": 2})
506523
self.assertEqual(message, "[] is too short")

0 commit comments

Comments
 (0)