@@ -93,13 +93,15 @@ const MAX_SAFE_INTEGER: u64 = 1u64 << 53;
9393
9494pub ( crate ) fn is_multiple_of_integer ( value : & Number , multiple : f64 ) -> bool {
9595 // For large integer values beyond 2^53, as_f64() loses precision.
96- // Use integer arithmetic directly for these cases.
96+ // Use integer arithmetic directly for these cases, but only when the divisor
97+ // itself can be exactly represented in f64 (i.e., <= 2^53). Divisors > 2^53
98+ // may have already lost precision when converted to f64 during schema compilation.
9799 #[ cfg( feature = "arbitrary-precision" ) ]
98100 {
99101 if let Some ( v) = value. as_u64 ( ) {
100102 if v > MAX_SAFE_INTEGER
101103 && multiple > 0.0
102- && multiple <= u64 :: MAX as f64
104+ && multiple <= MAX_SAFE_INTEGER as f64
103105 && multiple. fract ( ) == 0.0
104106 {
105107 return ( v % ( multiple as u64 ) ) == 0 ;
@@ -108,7 +110,7 @@ pub(crate) fn is_multiple_of_integer(value: &Number, multiple: f64) -> bool {
108110 if let Some ( v) = value. as_i64 ( ) {
109111 if v. unsigned_abs ( ) > MAX_SAFE_INTEGER
110112 && multiple > 0.0
111- && multiple <= i64 :: MAX as f64
113+ && multiple <= MAX_SAFE_INTEGER as f64
112114 && multiple. fract ( ) == 0.0
113115 {
114116 return ( v % ( multiple as i64 ) ) == 0 ;
@@ -308,13 +310,18 @@ pub(crate) mod bignum {
308310 /// Try to parse a Number as `BigInt` if it's outside i64 range or for compile-time
309311 /// schema values that need exact representation
310312 pub ( crate ) fn try_parse_bigint ( num : & Number ) -> Option < BigInt > {
313+ use super :: MAX_SAFE_INTEGER ;
314+
311315 let num_str = num. as_str ( ) ;
312316
313- // Only parse as BigInt if it doesn't fit in i64
314- // We include u64 values beyond i64::MAX because they can't be accurately
315- // represented when cast to i64, which is needed for certain operations
316- if num. as_i64 ( ) . is_some ( ) {
317- return None ;
317+ // Parse as BigInt if it's beyond 2^53 (where f64 loses precision).
318+ // Values beyond 2^53 need BigInt for accurate arithmetic even if they fit in i64/u64.
319+ // Note: If as_i64() fails but as_u64() succeeds, the value is in [2^63, 2^64-1],
320+ // which is always > 2^53, so no additional check needed for u64.
321+ if let Some ( v) = num. as_i64 ( ) {
322+ if v. unsigned_abs ( ) <= MAX_SAFE_INTEGER {
323+ return None ;
324+ }
318325 }
319326
320327 let has_fraction_or_exponent = num_str. bytes ( ) . any ( |b| b == b'.' || b == b'e' || b == b'E' ) ;
0 commit comments