@@ -10,7 +10,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
1010
1111import Statistics # for _mean_promote
1212
13- using Base. Checked: checked_add, checked_sub, checked_div
13+ import Base. Checked: checked_neg, checked_add, checked_sub, checked_div
1414
1515using Base: @pure
1616
3333# "special" typealiases
3434 # Q and N typealiases are exported in separate source files
3535# Functions
36- scaledual
36+ scaledual,
37+ wrapping_neg, wrapping_add, wrapping_sub,
38+ saturating_neg, saturating_add, saturating_sub
3739
3840include (" utilities.jl" )
3941
@@ -166,6 +168,49 @@ floattype(::Type{Base.TwicePrecision{T}}) where T<:Union{Float16,Float32} = wide
166168
167169float (x:: FixedPoint ) = convert (floattype (x), x)
168170
171+ # wrapping arithmetic
172+ wrapping_neg (x:: X ) where {X <: FixedPoint } = X (- x. i, 0 )
173+ wrapping_add (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i + y. i, 0 )
174+ wrapping_sub (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i - y. i, 0 )
175+
176+ # saturating arithmetic
177+ saturating_neg (x:: X ) where {X <: FixedPoint } = X (~ min (x. i - true , x. i), 0 )
178+ saturating_neg (x:: X ) where {X <: FixedPoint{<:Unsigned} } = zero (X)
179+
180+ function saturating_add (x:: X , y:: X ) where {X <: FixedPoint }
181+ r, f = Base. Checked. add_with_overflow (x. i, y. i)
182+ ifelse (f, ifelse (y. i < 0 , typemin (X), typemax (X)), X (r, 0 ))
183+ end
184+ saturating_add (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i + min (~ x. i, y. i), 0 )
185+
186+ function saturating_sub (x:: X , y:: X ) where {X <: FixedPoint }
187+ r, f = Base. Checked. sub_with_overflow (x. i, y. i)
188+ ifelse (f, ifelse (y. i < 0 , typemax (X), typemin (X)), X (r, 0 ))
189+ end
190+ saturating_sub (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i - min (x. i, y. i), 0 )
191+
192+ # checked arithmetic
193+ checked_neg (x:: X ) where {X <: FixedPoint } = X (checked_neg (x. i), 0 )
194+ checked_add (x:: X , y:: X ) where {X <: FixedPoint } = X (checked_add (x. i, y. i), 0 )
195+ checked_sub (x:: X , y:: X ) where {X <: FixedPoint } = X (checked_sub (x. i, y. i), 0 )
196+
197+ # default arithmetic
198+ const DEFAULT_ARITHMETIC = :wrapping
199+
200+ for (op, name) in ((:- , :neg ), )
201+ f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
202+ @eval begin
203+ $ op (x:: X ) where {X <: FixedPoint } = $ f (x)
204+ end
205+ end
206+ for (op, name) in ((:+ , :add ), (:- , :sub ))
207+ f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
208+ @eval begin
209+ $ op (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x, y)
210+ end
211+ end
212+
213+
169214function minmax (x:: X , y:: X ) where {X <: FixedPoint }
170215 a, b = minmax (reinterpret (x), reinterpret (y))
171216 X (a,0 ), X (b,0 )
@@ -183,12 +228,12 @@ for f in (:(==), :<, :<=, :div, :fld, :fld1)
183228 $ f (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x. i, y. i)
184229 end
185230end
186- for f in (:- , : ~ , :abs )
231+ for f in (:~ , :abs )
187232 @eval begin
188233 $ f (x:: X ) where {X <: FixedPoint } = X ($ f (x. i), 0 )
189234 end
190235end
191- for f in (:+ , : - , : rem , :mod , :mod1 , :min , :max )
236+ for f in (:rem , :mod , :mod1 , :min , :max )
192237 @eval begin
193238 $ f (x:: X , y:: X ) where {X <: FixedPoint } = X ($ f (x. i, y. i), 0 )
194239 end
0 commit comments