@@ -445,7 +445,7 @@ overflow/underflow did in fact happen. Throws a DivideError on divide-by-zero.
445
445
function div_with_overflow (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
446
446
C = coefficient (FD{T, f})
447
447
# This case will break the div call below.
448
- if T <: Signed && x . i == typemin (T) && y . i == - 1
448
+ if y . i == - 1 && T <: Signed && hasmethod ( typemin, (Type{T},)) && x . i == typemin (T)
449
449
# To perform the div and overflow means reaching the max and adding 1, so typemin.
450
450
return (x, true )
451
451
end
@@ -454,6 +454,77 @@ function div_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
454
454
return (reinterpret (FD{T,f}, v), b)
455
455
end
456
456
457
+ # Does not exist in Base.Checked, so just exists in this package.
458
+ @doc """
459
+ FixedPointDecimals.fld_with_overflow(x::FD, y::FD)::Tuple{FD,Bool}
460
+
461
+ Calculates the largest integer less than or equal to `x / y`, checking for overflow errors
462
+ where applicable, returning the result and a boolean indicating whether overflow occured.
463
+ Throws a DivideError on divide-by-zero.
464
+
465
+ The overflow protection may impose a perceptible performance penalty.
466
+
467
+ See also:
468
+ - `Base.checked_fld`.
469
+ """
470
+ function fld_with_overflow (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
471
+ C = coefficient (FD{T, f})
472
+ # This case will break the fld call below.
473
+ if y. i == - 1 && T <: Signed && hasmethod (typemin, (Type{T},)) && x. i == typemin (T)
474
+ # To fld and overflow means reaching the max and adding 1, so typemin (x).
475
+ return (x, true )
476
+ end
477
+ # Note: The fld() will already throw for divide-by-zero, that's not an overflow.
478
+ v, b = Base. Checked. mul_with_overflow (C, fld (x. i, y. i))
479
+ return (reinterpret (FD{T, f}, v), b)
480
+ end
481
+
482
+ """
483
+ FixedPointDecimals.rdiv_with_overflow(x::FD, y::FD)::Tuple{FD,Bool}
484
+
485
+ Calculates `x / y`, checking for overflow errors where applicable, returning the result
486
+ and a boolean indicating whether overflow occured. Throws a DivideError on divide-by-zero.
487
+
488
+ The overflow protection may impose a perceptible performance penalty.
489
+
490
+ See also:
491
+ - `Base.checked_rdiv`.
492
+ """
493
+ function rdiv_with_overflow (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
494
+ powt = coefficient (FD{T, f})
495
+ # No multiplication can reach the typemax/typemin of a wider type, thus no typemin / -1.
496
+ quotient, remainder = fldmod (_widemul (x. i, powt), y. i)
497
+ # quotient is necessarily not typemax/typemin. x.i * powt cannot reach typemax/typemin
498
+ # of the widened type and y.i is an integer. Thus the following call cannot overflow.
499
+ v = _round_to_nearest (quotient, remainder, y. i)
500
+ return (reinterpret (FD{T,f}, rem (v, T)), v < typemin (T) || v > typemax (T))
501
+ end
502
+
503
+ # These functions allow us to perform division with integers outside of the range of the
504
+ # FixedDecimal.
505
+ function rdiv_with_overflow (x:: Integer , y:: FD{T, f} ) where {T<: Integer , f}
506
+ powt = coefficient (FD{T, f})
507
+ powtsq = _widemul (powt, powt)
508
+ # No multiplication can reach the typemax/typemin of a wider type, thus no typemin / -1.
509
+ quotient, remainder = fldmod (_widemul (x, powtsq), y. i)
510
+ # Same deal as previous overload as to why this will not overload. Note that all
511
+ # multiplication operations were widemuls.
512
+ v = _round_to_nearest (quotient, remainder, y. i)
513
+ return (reinterpret (FD{T,f}, rem (v, T)), v < typemin (T) || v > typemax (T))
514
+ end
515
+ function rdiv_with_overflow (x:: FD{T, f} , y:: Integer ) where {T<: Integer , f}
516
+ if y == - 1 && T <: Signed && hasmethod (typemin, (Type{T},)) && x. i == typemin (T)
517
+ # typemin / -1 for signed integers wraps, giving typemin (x) again.
518
+ return (x, true )
519
+ end
520
+
521
+ quotient, remainder = fldmod (x. i, y)
522
+ # It is impossible for both the quotient to be typemax/typemin AND remainder to be
523
+ # non-zero because y is an integer. Thus the following call cannot overflow.
524
+ v = _round_to_nearest (quotient, remainder, y)
525
+ return (reinterpret (FD{T, f}, v), false )
526
+ end
527
+
457
528
Base. checked_add (x:: FD , y:: FD ) = Base. checked_add (promote (x, y)... )
458
529
Base. checked_sub (x:: FD , y:: FD ) = Base. checked_sub (promote (x, y)... )
459
530
Base. checked_mul (x:: FD , y:: FD ) = Base. checked_mul (promote (x, y)... )
@@ -547,28 +618,22 @@ See also:
547
618
checked_rdiv (x:: FD , y:: FD ) = checked_rdiv (promote (x, y)... )
548
619
549
620
function checked_rdiv (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
550
- powt = coefficient (FD{T, f})
551
- quotient, remainder = fldmod (_widemul (x. i, powt), y. i)
552
- v = _round_to_nearest (quotient, remainder, y. i)
553
- typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
554
- return reinterpret (FD{T, f}, v)
621
+ (z, b) = rdiv_with_overflow (x, y)
622
+ b && Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
623
+ return z
555
624
end
556
625
557
626
# These functions allow us to perform division with integers outside of the range of the
558
627
# FixedDecimal.
559
628
function checked_rdiv (x:: Integer , y:: FD{T, f} ) where {T<: Integer , f}
560
- powt = coefficient (FD{T, f})
561
- powtsq = _widemul (powt, powt)
562
- quotient, remainder = fldmod (_widemul (x, powtsq), y. i)
563
- v = _round_to_nearest (quotient, remainder, y. i)
564
- typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
565
- reinterpret (FD{T, f}, v)
629
+ (z, b) = rdiv_with_overflow (x, y)
630
+ b && Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
631
+ return z
566
632
end
567
633
function checked_rdiv (x:: FD{T, f} , y:: Integer ) where {T<: Integer , f}
568
- quotient, remainder = fldmod (x. i, y)
569
- v = _round_to_nearest (quotient, remainder, y)
570
- typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
571
- reinterpret (FD{T, f}, v)
634
+ (z, b) = rdiv_with_overflow (x, y)
635
+ b && Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
636
+ return z
572
637
end
573
638
574
639
0 commit comments