Skip to content

Specialize sign-related functions #187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/FixedPointNumbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret,
big, rationalize, float, trunc, round, floor, ceil, bswap, clamp,
div, fld, rem, mod, mod1, fld1, min, max, minmax,
signed, unsigned, copysign, flipsign, signbit,
rand, length

import Statistics # for _mean_promote
Expand Down Expand Up @@ -46,6 +47,9 @@ reinterpret(::Type{X}, x::T) where {T <: Integer, X <: FixedPoint{T}} = X(x, 0)
nbitsfrac(::Type{X}) where {T, f, X <: FixedPoint{T,f}} = f
rawtype(::Type{X}) where {T, X <: FixedPoint{T}} = T

# traits based on static parameters
signbits(::Type{X}) where {T, X <: FixedPoint{T}} = T <: Unsigned ? 0 : 1

# construction using the (approximate) intended value, i.e., N0f8
*(x::Real, ::Type{X}) where {X <: FixedPoint} = _convert(X, x)

Expand Down Expand Up @@ -189,6 +193,30 @@ 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

# Since `FixedPoint` is not an integer type, it is not clear in what type
# `signed` and `unsigned` for `FixedPoint` should return values. They should
# currently throw errors in case we support "unsigned Fixed" or "signed Normed"
# in the future. The following "incomplete" code is necessary for Julia v1.0
# etc. to prevent accidental conversion to an integer type.
signed(x::X) where {X <: FixedPoint} = signed(X)(signed(x.i), 0)
unsigned(x::X) where {X <: FixedPoint} = unsigned(X)(unsigned(x.i), 0)

function copysign(x::X, y::Real) where {T, X <: FixedPoint{T}}
T <: Signed ? X(copysign(x.i, y), 0) : throw_not_a_signed_number_error(x)
end
function flipsign(x::X, y::Real) where {T, X <: FixedPoint{T}}
T <: Signed ? X(flipsign(x.i, y), 0) : throw_not_a_signed_number_error(x)
end
if copysign(-1, 0x1) !== 1 # for Julia v1.0 and v1.1 (julia #30748)
copysign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = copysign(x, signed(y))
flipsign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = flipsign(x, signed(y))
end
@noinline function throw_not_a_signed_number_error(x)
throw(ArgumentError("$x is not a signed number."))
end

signbit(x::X) where {X <: FixedPoint} = signbit(x.i)

for f in (:zero, :oneunit, :one, :eps, :rawone, :rawtype, :floattype)
@eval begin
$f(x::FixedPoint) = $f(typeof(x))
Expand Down
1 change: 0 additions & 1 deletion src/fixed.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ struct Fixed{T <: Signed, f} <: FixedPoint{T, f}
end

typechar(::Type{X}) where {X <: Fixed} = 'Q'
signbits(::Type{X}) where {X <: Fixed} = 1

for T in (Int8, Int16, Int32, Int64)
io = IOBuffer()
Expand Down
3 changes: 0 additions & 3 deletions src/normed.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ struct Normed{T <: Unsigned, f} <: FixedPoint{T, f}
end

typechar(::Type{X}) where {X <: Normed} = 'N'
signbits(::Type{X}) where {X <: Normed} = 0

for T in (UInt8, UInt16, UInt32, UInt64)
io = IOBuffer()
Expand Down Expand Up @@ -248,8 +247,6 @@ Base.BigFloat(x::Normed) = reinterpret(x) / BigFloat(rawone(x))

Base.Rational(x::Normed) = reinterpret(x)//rawone(x)

abs(x::Normed) = x

# unchecked arithmetic
*(x::T, y::T) where {T <: Normed} = convert(T,convert(floattype(T), x)*convert(floattype(T), y))
/(x::T, y::T) where {T <: Normed} = convert(T,convert(floattype(T), x)/convert(floattype(T), y))
Expand Down
17 changes: 17 additions & 0 deletions test/fixed.jl
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,23 @@ end
@test clamp(1.5Q1f6, Q0f7) === 0.992Q0f7
end

@testset "sign-related functions" begin
@test_throws Exception signed(Q0f7)
@test_throws Exception signed(0.5Q0f7)
@test_throws Exception unsigned(Q0f7)
@test_throws Exception unsigned(0.5Q0f7)
@test copysign(0.5Q0f7, 0x1) === 0.5Q0f7
@test copysign(0.5Q0f7, -1) === -0.5Q0f7
@test flipsign(0.5Q0f7, 0x1) === 0.5Q0f7
@test flipsign(0.5Q0f7, -1) === -0.5Q0f7
@test_throws ArgumentError sign(0Q0f7)
@test sign(0Q1f6) === 0Q1f6
@test sign(0.5Q1f6) === 1Q1f6
@test sign(-0.5Q1f6) === -1Q1f6
@test signbit(0.5Q0f7) === false
@test signbit(-0.5Q0f7) === true
end

@testset "Promotion within Fixed" begin
@test @inferred(promote(Q0f7(0.25), Q0f7(0.75))) ===
(Q0f7(0.25), Q0f7(0.75))
Expand Down
13 changes: 13 additions & 0 deletions test/normed.jl
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,19 @@ end
@test clamp(2.0N1f7, N0f8) === 1.0N0f8
end

@testset "sign-related functions" begin
@test_throws Exception signed(N0f8)
@test_throws Exception signed(1N0f8)
@test_throws Exception unsigned(N0f8)
@test_throws Exception unsigned(1N0f8)
@test_throws ArgumentError copysign(1N0f8, 0x1)
@test_throws ArgumentError copysign(1N0f8, -1)
@test_throws ArgumentError flipsign(1N0f8, 0x1)
@test_throws ArgumentError flipsign(1N0f8, -1)
@test_throws ArgumentError sign(0N0f8)
@test signbit(1N0f8) === false
end

@testset "unit range" begin
@test length(N0f8(0):N0f8(1)) == 2
@test length(N0f8(1):N0f8(0)) == 0
Expand Down