1- using Base: promote, afoldl, @_inline_meta
1+ using Base: BitInteger, promote, afoldl, @_inline_meta
22import Base. Checked: checked_neg, checked_add, checked_sub, checked_mul, checked_abs
3+ using Base. Checked: mul_with_overflow
34
45if VERSION ≥ v " 1.11-alpha"
6+ import Base: power_by_squaring
57 import Base. Checked: checked_pow
68else
7- using Base: BitInteger, throw_domerr_powbysq, to_power_type
8- using Base. Checked: mul_with_overflow, throw_overflowerr_binaryop
9+ using Base: throw_domerr_powbysq, to_power_type
10+ using Base. Checked: throw_overflowerr_binaryop
911end
1012
1113# The Base methods have unchecked semantics, so just pass through
@@ -22,13 +24,22 @@ checked_add(a, b, c, xs...) = @checked (@_inline_meta; afoldl(+, (+)((+)(a, b),
2224checked_sub (a, b, c, xs... ) = @checked (@_inline_meta ; afoldl (- , (- )((- )(a, b), c), xs... ))
2325checked_mul (a, b, c, xs... ) = @checked (@_inline_meta ; afoldl (* , (* )((* )(a, b), c), xs... ))
2426
27+ saturating_add (a, b, c, xs... ) = @saturating (@_inline_meta ; afoldl (+ , (+ )((+ )(a, b), c), xs... ))
28+ saturating_sub (a, b, c, xs... ) = @saturating (@_inline_meta ; afoldl (- , (- )((- )(a, b), c), xs... ))
29+ saturating_mul (a, b, c, xs... ) = @saturating (@_inline_meta ; afoldl (* , (* )((* )(a, b), c), xs... ))
30+
2531
2632# promote unmatched number types to same type
2733checked_add (x:: Number , y:: Number ) = checked_add (promote (x, y)... )
2834checked_sub (x:: Number , y:: Number ) = checked_sub (promote (x, y)... )
2935checked_mul (x:: Number , y:: Number ) = checked_mul (promote (x, y)... )
3036checked_pow (x:: Number , y:: Number ) = checked_pow (promote (x, y)... )
3137
38+ saturating_add (x:: Number , y:: Number ) = saturating_add (promote (x, y)... )
39+ saturating_sub (x:: Number , y:: Number ) = saturating_sub (promote (x, y)... )
40+ saturating_mul (x:: Number , y:: Number ) = saturating_mul (promote (x, y)... )
41+ saturating_pow (x:: Number , y:: Number ) = saturating_pow (promote (x, y)... )
42+
3243
3344# fallback to `unchecked_` for `Number` types that don't have more specific `checked_` methods
3445checked_neg (x:: T ) where T <: Number = unchecked_neg (x)
@@ -38,6 +49,13 @@ checked_mul(x::T, y::T) where T <: Number = unchecked_mul(x, y)
3849checked_pow (x:: T , y:: T ) where T <: Number = unchecked_pow (x, y)
3950checked_abs (x:: T ) where T <: Number = unchecked_abs (x)
4051
52+ saturating_neg (x:: T ) where T <: Number = unchecked_neg (x)
53+ saturating_add (x:: T , y:: T ) where T <: Number = unchecked_add (x, y)
54+ saturating_sub (x:: T , y:: T ) where T <: Number = unchecked_sub (x, y)
55+ saturating_mul (x:: T , y:: T ) where T <: Number = unchecked_mul (x, y)
56+ saturating_pow (x:: T , y:: T ) where T <: Number = unchecked_pow (x, y)
57+ saturating_abs (x:: T ) where T <: Number = unchecked_abs (x)
58+
4159
4260# fallback to `unchecked_` for non-`Number` types
4361checked_neg (x) = unchecked_neg (x)
@@ -51,50 +69,38 @@ checked_abs(x) = unchecked_abs(x)
5169if VERSION < v " 1.11"
5270# Base.Checked only gained checked powers in 1.11
5371
54- function checked_pow (x:: T , y:: S ) where {T <: BitInteger , S <: BitInteger }
55- @_inline_meta
56- z, b = pow_with_overflow (x, y)
57- b && throw_overflowerr_binaryop (:^ , x, y)
58- z
59- end
72+ checked_pow (x_:: T , p:: S ) where {T <: BitInteger , S <: BitInteger } =
73+ power_by_squaring (x_, p; mul = checked_mul)
6074
61- function pow_with_overflow (x_, p:: Integer )
75+ # Base.@assume_effects :terminates_locally # present in Julia 1.11 code, but only supported from 1.8 on
76+ function power_by_squaring (x_, p:: Integer ; mul= * )
6277 x = to_power_type (x_)
6378 if p == 1
64- return ( copy (x), false )
79+ return copy (x)
6580 elseif p == 0
66- return ( one (x), false )
81+ return one (x)
6782 elseif p == 2
68- return mul_with_overflow (x, x)
83+ return mul (x, x)
6984 elseif p < 0
70- isone (x) && return ( copy (x), false )
71- isone (- x) && return ( iseven (p) ? one (x) : copy (x), false )
85+ isone (x) && return copy (x)
86+ isone (- x) && return iseven (p) ? one (x) : copy (x)
7287 throw_domerr_powbysq (x, p)
7388 end
7489 t = trailing_zeros (p) + 1
7590 p >>= t
76- b = false
7791 while (t -= 1 ) > 0
78- x, b1 = mul_with_overflow (x, x)
79- b |= b1
92+ x = mul (x, x)
8093 end
8194 y = x
8295 while p > 0
8396 t = trailing_zeros (p) + 1
8497 p >>= t
8598 while (t -= 1 ) >= 0
86- x, b1 = mul_with_overflow (x, x)
87- b |= b1
99+ x = mul (x, x)
88100 end
89- y, b1 = mul_with_overflow (y, x)
90- b |= b1
101+ y = mul (y, x)
91102 end
92- return y, b
93- end
94- pow_with_overflow (x:: Bool , p:: Unsigned ) = ((p== 0 ) | x, false )
95- function pow_with_overflow (x:: Bool , p:: Integer )
96- p < 0 && ! x && throw_domerr_powbysq (x, p)
97- return (p== 0 ) | x, false
103+ return y
98104end
99105
100106end
0 commit comments