@@ -309,12 +309,26 @@ func testCasesWithinTolerance[N Int[N]](t *testing.T) {
309309 },
310310 }
311311
312+ // Create a zero coefficient to test the error case.
313+ zeroCoefficient := NewInt [N ]().FromUint64 (0 )
314+
312315 // Run the test cases.
313316 for idx , tc := range testCases {
314- result := tc .firstFp .WithinTolerance (
317+ result , err := tc .firstFp .WithinTolerance (
315318 tc .secondFp , NewInt [N ]().FromUint64 (tc .tolerancePpm ),
316319 )
317320
321+ // If either of the coefficients are zero, we expect an error.
322+ if tc .firstFp .Coefficient .Equals (zeroCoefficient ) ||
323+ tc .secondFp .Coefficient .Equals (zeroCoefficient ) {
324+
325+ require .Error (t , err )
326+ require .False (t , result )
327+ continue
328+ }
329+
330+ require .NoError (t , err , "Test case %d failed" , idx )
331+
318332 // Compare bounds check result with expected test case within
319333 // bounds flag.
320334 require .Equal (
@@ -330,7 +344,7 @@ func testWithinToleranceEqualValues(t *rapid.T) {
330344 tolerancePpm := rapid .Int64Min (0 ).Draw (t , "tolerance" )
331345
332346 // Generate a random coefficient and scale.
333- coefficient := rapid .Int64Min (0 ).Draw (t , "coefficient" )
347+ coefficient := rapid .Int64Min (1 ).Draw (t , "coefficient" )
334348 scale := rapid .Uint8Range (0 , 18 ).Draw (t , "scale" )
335349
336350 // Create two identical FixedPoint[BigInt] values.
@@ -348,7 +362,9 @@ func testWithinToleranceEqualValues(t *rapid.T) {
348362
349363 // The result should always be true when the fixed-point values
350364 // are equal.
351- result := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
365+ result , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
366+ require .NoError (t , err )
367+
352368 if ! result {
353369 t .Fatalf ("WithinTolerance should be true when values " +
354370 "are equal, but got false" )
@@ -363,7 +379,7 @@ func testWithinToleranceZeroTolerance(t *rapid.T) {
363379 tolerancePpmBigInt := NewBigInt (big .NewInt (0 ))
364380
365381 // Generate two equal fixed-points.
366- coefficient := rapid .Int64Min (0 ).Draw (t , "coefficient" )
382+ coefficient := rapid .Int64Min (1 ).Draw (t , "coefficient" )
367383 scale := rapid .Uint8Range (0 , 18 ).Draw (t , "scale" )
368384 f1 := FixedPoint [BigInt ]{
369385 Coefficient : NewBigInt (big .NewInt (coefficient )),
@@ -375,16 +391,18 @@ func testWithinToleranceZeroTolerance(t *rapid.T) {
375391 Scale : scale ,
376392 }
377393
378- require .True (t , f1 .WithinTolerance (f2 , tolerancePpmBigInt ))
394+ result , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
395+ require .NoError (t , err )
396+ require .True (t , result )
379397}
380398
381399// testWithinToleranceSymmetric is a property-based test which ensures that the
382400// WithinTolerance method is symmetric (swapping the order of the fixed-point
383401// values does not change the result).
384402func testWithinToleranceSymmetric (t * rapid.T ) {
385403 // Generate random coefficients, scales, and tolerance
386- coefficient := rapid .Int64Min (0 ).Draw (t , "coefficient_1" )
387- coefficient2 := rapid .Int64Min (0 ).Draw (t , "coefficient_2" )
404+ coefficient := rapid .Int64Min (1 ).Draw (t , "coefficient_1" )
405+ coefficient2 := rapid .Int64Min (1 ).Draw (t , "coefficient_2" )
388406 scale1 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_1" )
389407 scale2 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_2" )
390408 tolerancePpm := rapid .Int64Range (0 , 1_000_000 ).Draw (t , "tolerance" )
@@ -401,8 +419,11 @@ func testWithinToleranceSymmetric(t *rapid.T) {
401419
402420 tolerancePpmBigInt := NewBigInt (big .NewInt (tolerancePpm ))
403421
404- result1 := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
405- result2 := f2 .WithinTolerance (f1 , tolerancePpmBigInt )
422+ result1 , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
423+ require .NoError (t , err )
424+
425+ result2 , err := f2 .WithinTolerance (f1 , tolerancePpmBigInt )
426+ require .NoError (t , err )
406427
407428 if result1 != result2 {
408429 t .Fatalf ("WithinTolerance is not symmetric: " +
@@ -420,14 +441,14 @@ func testWithinToleranceMaxTolerance(t *rapid.T) {
420441 tolerancePpmBigInt := NewBigInt (big .NewInt (tolerancePpm ))
421442
422443 // Generate random fixed-point values.
423- coefficient1 := rapid .Int64Min (0 ).Draw (t , "coefficient_1" )
444+ coefficient1 := rapid .Int64Min (1 ).Draw (t , "coefficient_1" )
424445 scale1 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_1" )
425446 f1 := FixedPoint [BigInt ]{
426447 Coefficient : NewBigInt (big .NewInt (coefficient1 )),
427448 Scale : scale1 ,
428449 }
429450
430- coefficient2 := rapid .Int64Min (0 ).Draw (t , "coefficient_2" )
451+ coefficient2 := rapid .Int64Min (1 ).Draw (t , "coefficient_2" )
431452 scale2 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_2" )
432453 f2 := FixedPoint [BigInt ]{
433454 Coefficient : NewBigInt (big .NewInt (coefficient2 )),
@@ -436,13 +457,59 @@ func testWithinToleranceMaxTolerance(t *rapid.T) {
436457
437458 // The result should always be true when tolerancePpm is at its max or
438459 // larger.
439- result := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
460+ result , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
461+ require .NoError (t , err )
462+
440463 if ! result {
441464 t .Fatalf ("WithinTolerance should be true when tolerancePpm " +
442465 "is large, but got false" )
443466 }
444467}
445468
469+ // testWithinToleranceCoefficientZeroError is a property-based test which
470+ // ensures that the WithinTolerance method returns an error when either or both
471+ // of the fixed-point values have a coefficient of zero.
472+ func testWithinToleranceCoefficientZeroError (t * rapid.T ) {
473+ // Set tolerancePpm to any value above 100%.
474+ tolerancePpm := rapid .Int64Min (1_000_000 ).Draw (t , "tolerance" )
475+ tolerancePpmBigInt := NewBigInt (big .NewInt (tolerancePpm ))
476+
477+ // Generate a random mode to determine which coefficient(s) to set to
478+ // zero.
479+ mode := rapid .Int64Range (0 , 2 ).Draw (t , "mode" )
480+
481+ var coefficient1 , coefficient2 int64
482+ switch mode {
483+ case 0 :
484+ coefficient1 = 0
485+ coefficient2 = rapid .Int64Min (1 ).Draw (t , "coefficient_2" )
486+ case 1 :
487+ coefficient1 = rapid .Int64Min (1 ).Draw (t , "coefficient_1" )
488+ coefficient2 = 0
489+ case 2 :
490+ coefficient1 = 0
491+ coefficient2 = 0
492+ }
493+
494+ // Generate random fixed-point values from the coefficients.
495+ scale1 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_1" )
496+ f1 := FixedPoint [BigInt ]{
497+ Coefficient : NewBigInt (big .NewInt (coefficient1 )),
498+ Scale : scale1 ,
499+ }
500+
501+ scale2 := rapid .Uint8Range (0 , 18 ).Draw (t , "scale_2" )
502+ f2 := FixedPoint [BigInt ]{
503+ Coefficient : NewBigInt (big .NewInt (coefficient2 )),
504+ Scale : scale2 ,
505+ }
506+
507+ // We always expect an error when either or both coefficients are zero.
508+ result , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
509+ require .Error (t , err )
510+ require .False (t , result )
511+ }
512+
446513// testWithinToleranceFloatReproduce is a property-based test that verifies
447514// the reproducibility of the WithinTolerance method's result using calculations
448515// on float64 values.
@@ -452,7 +519,7 @@ func testWithinToleranceFloatReproduce(t *rapid.T) {
452519 tolerancePpmBigInt := NewBigInt (big .NewInt (tolerancePpm ))
453520
454521 // Generate random fixed-point values.
455- coefficientsRange := rapid .Int64Range (0 , 1_000_000_000 )
522+ coefficientsRange := rapid .Int64Range (1 , 1_000_000_000 )
456523
457524 coefficient1 := coefficientsRange .Draw (t , "coefficient_1" )
458525 scale1 := rapid .Uint8Range (0 , 9 ).Draw (t , "scale_1" )
@@ -469,7 +536,8 @@ func testWithinToleranceFloatReproduce(t *rapid.T) {
469536 }
470537
471538 // Compute the result using the WithinTolerance method.
472- result := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
539+ result , err := f1 .WithinTolerance (f2 , tolerancePpmBigInt )
540+ require .NoError (t , err )
473541
474542 // Compute expected result using float64.
475543 f1Float := f1 .ToFloat64 ()
@@ -523,6 +591,11 @@ func testWithinTolerance(t *testing.T) {
523591 rapid .MakeCheck (testWithinToleranceMaxTolerance ),
524592 )
525593
594+ t .Run (
595+ "within_tolerance_coefficient_zero_error" ,
596+ rapid .MakeCheck (testWithinToleranceCoefficientZeroError ),
597+ )
598+
526599 t .Run (
527600 "within_tolerance_float_reproduce" ,
528601 rapid .MakeCheck (testWithinToleranceFloatReproduce ),
0 commit comments