@@ -445,7 +445,7 @@ overflow/underflow did in fact happen. Throws a DivideError on divide-by-zero.
445445function div_with_overflow (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
446446 C = coefficient (FD{T, f})
447447 # 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)
449449 # To perform the div and overflow means reaching the max and adding 1, so typemin.
450450 return (x, true )
451451 end
@@ -454,6 +454,77 @@ function div_with_overflow(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
454454 return (reinterpret (FD{T,f}, v), b)
455455end
456456
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+
457528Base. checked_add (x:: FD , y:: FD ) = Base. checked_add (promote (x, y)... )
458529Base. checked_sub (x:: FD , y:: FD ) = Base. checked_sub (promote (x, y)... )
459530Base. checked_mul (x:: FD , y:: FD ) = Base. checked_mul (promote (x, y)... )
@@ -547,28 +618,22 @@ See also:
547618checked_rdiv (x:: FD , y:: FD ) = checked_rdiv (promote (x, y)... )
548619
549620function 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
555624end
556625
557626# These functions allow us to perform division with integers outside of the range of the
558627# FixedDecimal.
559628function 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
566632end
567633function 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
572637end
573638
574639
0 commit comments