@@ -152,3 +152,83 @@ def test_array_operations():
152152 expected = np .array (
153153 [QuadPrecision ("2.0" ), QuadPrecision ("3.5" ), QuadPrecision ("5.0" )])
154154 assert all (x == y for x , y in zip (result , expected ))
155+
156+
157+ @pytest .mark .parametrize ("backend" , ["sleef" , "longdouble" ])
158+ @pytest .mark .parametrize ("op" , [np .mod , np .remainder ])
159+ @pytest .mark .parametrize ("a,b" , [
160+ # Basic cases - positive/negative combinations
161+ (7.0 , 3.0 ), (- 7.0 , 3.0 ), (7.0 , - 3.0 ), (- 7.0 , - 3.0 ),
162+
163+ # Zero dividend cases
164+ (0.0 , 3.0 ), (- 0.0 , 3.0 ), (0.0 , - 3.0 ), (- 0.0 , - 3.0 ),
165+
166+ # Cases that result in zero (sign testing)
167+ (6.0 , 3.0 ), (- 6.0 , 3.0 ), (6.0 , - 3.0 ), (- 6.0 , - 3.0 ),
168+ (1.0 , 1.0 ), (- 1.0 , 1.0 ), (1.0 , - 1.0 ), (- 1.0 , - 1.0 ),
169+
170+ # Fractional cases
171+ (7.5 , 2.5 ), (- 7.5 , 2.5 ), (7.5 , - 2.5 ), (- 7.5 , - 2.5 ),
172+ (0.75 , 0.25 ), (- 0.1 , 0.3 ), (0.9 , - 1.0 ), (- 1.1 , - 1.0 ),
173+
174+ # Large/small numbers
175+ (1e10 , 1e5 ), (- 1e10 , 1e5 ), (1e-10 , 1e-5 ), (- 1e-10 , 1e-5 ),
176+
177+ # Finite % infinity cases
178+ (5.0 , float ('inf' )), (- 5.0 , float ('inf' )),
179+ (5.0 , float ('-inf' )), (- 5.0 , float ('-inf' )),
180+ (0.0 , float ('inf' )), (- 0.0 , float ('-inf' )),
181+
182+ # NaN cases (should return NaN)
183+ (float ('nan' ), 3.0 ), (3.0 , float ('nan' )), (float ('nan' ), float ('nan' )),
184+
185+ # Division by zero cases (should return NaN)
186+ (5.0 , 0.0 ), (- 5.0 , 0.0 ), (0.0 , 0.0 ), (- 0.0 , 0.0 ),
187+
188+ # Infinity dividend cases (should return NaN)
189+ (float ('inf' ), 3.0 ), (float ('-inf' ), 3.0 ),
190+ (float ('inf' ), float ('inf' )), (float ('-inf' ), float ('-inf' )),
191+ ])
192+ def test_mod (a , b , backend , op ):
193+ """Comprehensive test for mod operation against NumPy behavior"""
194+ if backend == "sleef" :
195+ quad_a = QuadPrecision (str (a ))
196+ quad_b = QuadPrecision (str (b ))
197+ elif backend == "longdouble" :
198+ quad_a = QuadPrecision (a , backend = 'longdouble' )
199+ quad_b = QuadPrecision (b , backend = 'longdouble' )
200+ float_a = np .float64 (a )
201+ float_b = np .float64 (b )
202+
203+ quad_result = op (quad_a , quad_b )
204+ numpy_result = op (float_a , float_b )
205+
206+ # Handle NaN cases
207+ if np .isnan (numpy_result ):
208+ assert np .isnan (
209+ float (quad_result )), f"Expected NaN for { a } % { b } , got { float (quad_result )} "
210+ return
211+
212+ if np .isinf (numpy_result ):
213+ assert np .isinf (
214+ float (quad_result )), f"Expected inf for { a } % { b } , got { float (quad_result )} "
215+ assert np .sign (numpy_result ) == np .sign (
216+ float (quad_result )), f"Infinity sign mismatch for { a } % { b } "
217+ return
218+
219+ np .testing .assert_allclose (float (quad_result ), numpy_result , rtol = 1e-10 , atol = 1e-15 ,
220+ err_msg = f"Value mismatch for { a } % { b } " )
221+
222+ if numpy_result == 0.0 :
223+ numpy_sign = np .signbit (numpy_result )
224+ quad_sign = np .signbit (quad_result )
225+ assert numpy_sign == quad_sign , f"Zero sign mismatch for { a } % { b } : numpy={ numpy_sign } , quad={ quad_sign } "
226+
227+ # Check that non-zero results have correct sign relative to divisor
228+ if numpy_result != 0.0 and not np .isnan (b ) and not np .isinf (b ) and b != 0.0 :
229+ # In Python mod, non-zero result should have same sign as divisor (or be zero)
230+ result_negative = float (quad_result ) < 0
231+ divisor_negative = b < 0
232+ numpy_negative = numpy_result < 0
233+
234+ assert result_negative == numpy_negative , f"Sign mismatch for { a } % { b } : quad={ result_negative } , numpy={ numpy_negative } "
0 commit comments