34
34
#include <math.h>
35
35
#include <float.h>
36
36
37
+ REBOOL almost_equal (REBDEC a , REBDEC b , REBCNT max_diff ); // in t-decimal.c
38
+
37
39
#define LOG2 0.6931471805599453
38
40
#define EPS 2.718281828459045235360287471
39
41
@@ -359,6 +361,77 @@ enum {SINE, COSINE, TANGENT};
359
361
}
360
362
361
363
364
+ /***********************************************************************
365
+ **
366
+ */ void modulus (REBVAL * ret , REBVAL * val1 , REBVAL * val2 , REBOOL round )
367
+ /*
368
+ ** Based on: https://stackoverflow.com/a/66777048/494472
369
+ **
370
+ ***********************************************************************/
371
+ {
372
+ double a , aa , b , m ;
373
+ if (IS_INTEGER (val1 ) && IS_INTEGER (val2 )) {
374
+ REBI64 ia = VAL_INT64 (val1 );
375
+ REBI64 ib = VAL_INT64 (val2 );
376
+ if (ib == 0 ) Trap0 (RE_ZERO_DIVIDE );
377
+ SET_INTEGER (ret , ((ia % ib ) + ib ) % ib );
378
+ return ;
379
+ }
380
+
381
+ a = Number_To_Dec (val1 );
382
+ b = Number_To_Dec (val2 );
383
+
384
+ if (b == 0.0 ) Trap0 (RE_ZERO_DIVIDE );
385
+
386
+ if (round && b < 0.0 ) b = fabs (b );
387
+
388
+ m = fmod (fmod (a , b ) + b , b );
389
+
390
+ if (round && (almost_equal (a , a - m , 10 ) || almost_equal (b , b + m , 10 ))) {
391
+ m = 0.0 ;
392
+ }
393
+ switch (VAL_TYPE (val1 )) {
394
+ case REB_DECIMAL :
395
+ case REB_PERCENT : SET_DECIMAL (ret , m ); break ;
396
+ case REB_INTEGER : SET_INTEGER (ret , (REBI64 )m ); break ;
397
+ case REB_TIME : VAL_TIME (ret ) = DEC_TO_SECS (m ); break ;
398
+ case REB_MONEY : VAL_DECI (ret ) = decimal_to_deci (m ); break ;
399
+ case REB_CHAR : SET_CHAR (ret , (REBINT )m ); break ;
400
+ }
401
+ SET_TYPE (ret , VAL_TYPE (val1 ));
402
+ }
403
+
404
+ /***********************************************************************
405
+ **
406
+ */ REBNATIVE (mod )
407
+ /*
408
+ // mod: native [
409
+ // {Compute a nonnegative remainder of A divided by B.}
410
+ // a [number! money! char! time!]
411
+ // b [number! money! char! time!] "Must be nonzero."
412
+ // ]
413
+ ***********************************************************************/
414
+ {
415
+ modulus (D_RET , D_ARG (1 ), D_ARG (2 ), FALSE);
416
+ return R_RET ;
417
+ }
418
+
419
+ /***********************************************************************
420
+ **
421
+ */ REBNATIVE (modulo )
422
+ /*
423
+ // modulo: native [
424
+ // {Wrapper for MOD that handles errors like REMAINDER. Negligible values (compared to A and B) are rounded to zero.}
425
+ // a [number! money! char! time!]
426
+ // b [number! money! char! time!] "Absolute value will be used."
427
+ // ]
428
+ ***********************************************************************/
429
+ {
430
+ modulus (D_RET , D_ARG (1 ), D_ARG (2 ), TRUE);
431
+ return R_RET ;
432
+ }
433
+
434
+
362
435
/***********************************************************************
363
436
**
364
437
*/ REBNATIVE (log_10 )
@@ -578,6 +651,10 @@ enum {SINE, COSINE, TANGENT};
578
651
}
579
652
else if (tb == REB_INTEGER || tb == REB_CHAR ) // special negative?, zero?, ...
580
653
goto compare ;
654
+ else if (tb == REB_TIME ) {
655
+ SET_INTEGER (b , (REBI64 )SECS_IN (VAL_TIME (b )));
656
+ goto compare ;
657
+ }
581
658
break ;
582
659
583
660
case REB_DECIMAL :
@@ -592,6 +669,10 @@ enum {SINE, COSINE, TANGENT};
592
669
}
593
670
else if (tb == REB_DECIMAL || tb == REB_PERCENT ) // equivalent types
594
671
goto compare ;
672
+ else if (tb == REB_TIME ) {
673
+ SET_DECIMAL (b , (REBDEC )VAL_TIME (b ) * NANO );
674
+ goto compare ;
675
+ }
595
676
break ;
596
677
597
678
case REB_MONEY :
@@ -627,6 +708,17 @@ enum {SINE, COSINE, TANGENT};
627
708
//o: with not integer numbers (money, decimal, percent)
628
709
if (tb == REB_INTEGER )
629
710
goto compare ;
711
+ break ;
712
+ case REB_TIME :
713
+ if (tb == REB_INTEGER ) {
714
+ SET_INTEGER (a , (REBI64 )SECS_IN (VAL_TIME (a )));
715
+ goto compare ;
716
+ }
717
+ else if (tb == REB_DECIMAL || tb == REB_PERCENT ) {
718
+ SET_DECIMAL (a , (REBDEC )VAL_TIME (a ) * NANO );
719
+ goto compare ;
720
+ }
721
+ break ;
630
722
}
631
723
if (strictness == 0 || strictness == 1 ) return FALSE;
632
724
//if (strictness >= 2)
0 commit comments