@@ -11,7 +11,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
1111
1212import Statistics # for _mean_promote
1313
14- using Base. Checked: checked_add, checked_sub, checked_div
14+ import Base. Checked: checked_neg, checked_add, checked_sub, checked_div
1515
1616using Base: @pure
1717
3434# "special" typealiases
3535 # Q and N typealiases are exported in separate source files
3636# Functions
37- scaledual
37+ scaledual,
38+ wrapping_neg, wrapping_add, wrapping_sub,
39+ saturating_neg, saturating_add, saturating_sub
3840
3941include (" utilities.jl" )
4042
@@ -178,6 +180,49 @@ floattype(::Type{Base.TwicePrecision{T}}) where T<:Union{Float16,Float32} = wide
178180
179181float (x:: FixedPoint ) = convert (floattype (x), x)
180182
183+ # wrapping arithmetic
184+ wrapping_neg (x:: X ) where {X <: FixedPoint } = X (- x. i, 0 )
185+ wrapping_add (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i + y. i, 0 )
186+ wrapping_sub (x:: X , y:: X ) where {X <: FixedPoint } = X (x. i - y. i, 0 )
187+
188+ # saturating arithmetic
189+ saturating_neg (x:: X ) where {X <: FixedPoint } = X (~ min (x. i - true , x. i), 0 )
190+ saturating_neg (x:: X ) where {X <: FixedPoint{<:Unsigned} } = zero (X)
191+
192+ function saturating_add (x:: X , y:: X ) where {X <: FixedPoint }
193+ r, f = Base. Checked. add_with_overflow (x. i, y. i)
194+ ifelse (f, ifelse (y. i < 0 , typemin (X), typemax (X)), X (r, 0 ))
195+ end
196+ saturating_add (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i + min (~ x. i, y. i), 0 )
197+
198+ function saturating_sub (x:: X , y:: X ) where {X <: FixedPoint }
199+ r, f = Base. Checked. sub_with_overflow (x. i, y. i)
200+ ifelse (f, ifelse (y. i < 0 , typemax (X), typemin (X)), X (r, 0 ))
201+ end
202+ saturating_sub (x:: X , y:: X ) where {X <: FixedPoint{<:Unsigned} } = X (x. i - min (x. i, y. i), 0 )
203+
204+ # checked arithmetic
205+ checked_neg (x:: X ) where {X <: FixedPoint } = X (checked_neg (x. i), 0 )
206+ checked_add (x:: X , y:: X ) where {X <: FixedPoint } = X (checked_add (x. i, y. i), 0 )
207+ checked_sub (x:: X , y:: X ) where {X <: FixedPoint } = X (checked_sub (x. i, y. i), 0 )
208+
209+ # default arithmetic
210+ const DEFAULT_ARITHMETIC = :wrapping
211+
212+ for (op, name) in ((:- , :neg ), )
213+ f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
214+ @eval begin
215+ $ op (x:: X ) where {X <: FixedPoint } = $ f (x)
216+ end
217+ end
218+ for (op, name) in ((:+ , :add ), (:- , :sub ))
219+ f = Symbol (DEFAULT_ARITHMETIC, :_ , name)
220+ @eval begin
221+ $ op (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x, y)
222+ end
223+ end
224+
225+
181226function minmax (x:: X , y:: X ) where {X <: FixedPoint }
182227 a, b = minmax (reinterpret (x), reinterpret (y))
183228 X (a,0 ), X (b,0 )
@@ -227,12 +272,12 @@ for f in (:(==), :<, :<=, :div, :fld, :fld1)
227272 $ f (x:: X , y:: X ) where {X <: FixedPoint } = $ f (x. i, y. i)
228273 end
229274end
230- for f in (:- , : ~ , :abs )
275+ for f in (:~ , :abs )
231276 @eval begin
232277 $ f (x:: X ) where {X <: FixedPoint } = X ($ f (x. i), 0 )
233278 end
234279end
235- for f in (:+ , : - , : rem , :mod , :mod1 , :min , :max )
280+ for f in (:rem , :mod , :mod1 , :min , :max )
236281 @eval begin
237282 $ f (x:: X , y:: X ) where {X <: FixedPoint } = X ($ f (x. i, y. i), 0 )
238283 end
0 commit comments