diff --git a/src/FixedPointNumbers.jl b/src/FixedPointNumbers.jl index ff38030a..85783f3c 100644 --- a/src/FixedPointNumbers.jl +++ b/src/FixedPointNumbers.jl @@ -4,7 +4,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox, convert, promote_rule, show, bitstring, abs, decompose, isnan, isinf, isfinite, isinteger, zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret, - big, rationalize, float, trunc, round, floor, ceil, bswap, + big, rationalize, float, trunc, round, floor, ceil, bswap, clamp, div, fld, rem, mod, mod1, fld1, min, max, minmax, rand, length @@ -183,6 +183,12 @@ bitstring(x::FixedPoint) = bitstring(x.i) bswap(x::X) where {X <: FixedPoint} = sizeof(X) == 1 ? x : X(bswap(x.i), 0) +# At least on Julia v1.5.0 or earlier, the following specialization helps the +# SIMD vectorization. (cf. PR #194) +clamp(x::X, lo::X, hi::X) where {X <: FixedPoint} = X(clamp(x.i, lo.i, hi.i), 0) + +clamp(x, ::Type{X}) where {X <: FixedPoint} = clamp(x, typemin(X), typemax(X)) % X + for f in (:zero, :oneunit, :one, :eps, :rawone, :rawtype, :floattype) @eval begin $f(x::FixedPoint) = $f(typeof(x)) diff --git a/test/fixed.jl b/test/fixed.jl index 24e8a185..1c8e7a4a 100644 --- a/test/fixed.jl +++ b/test/fixed.jl @@ -406,6 +406,19 @@ end @test bswap(Q0f15(0.5)) === reinterpret(Q0f15, signed(0x0040)) end +@testset "clamp" begin + @test clamp(0.5Q0f7, -0.8Q0f7, 0.8Q0f7) === 0.5Q0f7 + @test clamp(0.5Q0f7, 0.75Q0f7, 0.8Q0f7) === 0.75Q0f7 + @test clamp(0.5Q0f7, -0.8Q0f7, 0.25Q0f7) === 0.25Q0f7 + @test clamp(0.5, -0.8Q0f7, 0.8Q0f7) === 0.5 + @test clamp(0.5f0, 0.75Q0f7, 0.8Q0f7) === 0.75f0 + @test clamp(0.5Q0f15, -0.8Q0f7, 0.25Q0f7) === 0.25Q0f15 + @test clamp(0.5Q0f7, -Inf, Inf) === 0.5 + @test clamp(0.5, Q0f7) === 0.5Q0f7 + @test clamp(-1.5f0, Q0f7) === -1.0Q0f7 + @test clamp(1.5Q1f6, Q0f7) === 0.992Q0f7 +end + @testset "Promotion within Fixed" begin @test @inferred(promote(Q0f7(0.25), Q0f7(0.75))) === (Q0f7(0.25), Q0f7(0.75)) diff --git a/test/normed.jl b/test/normed.jl index 542d08a8..fd620860 100644 --- a/test/normed.jl +++ b/test/normed.jl @@ -338,6 +338,19 @@ end @test minmax(N0f8(0.8), N0f8(0.2)) === (N0f8(0.2), N0f8(0.8)) end +@testset "clamp" begin + @test clamp(0.5N0f8, 0.2N0f8, 0.8N0f8) === 0.5N0f8 + @test clamp(0.5N0f8, 0.6N0f8, 0.8N0f8) === 0.6N0f8 + @test clamp(0.5N0f8, 0.2N0f8, 0.4N0f8) === 0.4N0f8 + @test clamp(0.5, 0.2N0f8, 0.8N0f8) === 0.5 + @test clamp(0.5f0, 0.6N0f8, 0.8N0f8) === 0.6f0 + @test clamp(0.5N0f16, 0.2N0f8, 0.4N0f8) === 0.4N0f16 + @test clamp(0.6N0f8, -Inf, Inf) === 0.6 + @test clamp(0.5, N0f8) === 0.5N0f8 + @test clamp(-1.0f0, N0f8) === 0.0N0f8 + @test clamp(2.0N1f7, N0f8) === 1.0N0f8 +end + @testset "unit range" begin @test length(N0f8(0):N0f8(1)) == 2 @test length(N0f8(1):N0f8(0)) == 0