Skip to content

Commit ee128d4

Browse files
committed
Specialize sign-related functions
1 parent 7c90fb6 commit ee128d4

File tree

5 files changed

+58
-4
lines changed

5 files changed

+58
-4
lines changed

src/FixedPointNumbers.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
66
zero, oneunit, one, typemin, typemax, floatmin, floatmax, eps, reinterpret,
77
float, trunc, round, floor, ceil, bswap,
88
div, fld, rem, mod, mod1, fld1, min, max, minmax,
9+
signed, unsigned, copysign, flipsign, signbit,
910
rand, length
1011

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

50+
# traits based on static parameters
51+
signbits(::Type{X}) where {T, X <: FixedPoint{T}} = T <: Unsigned ? 0 : 1
52+
4953
# construction using the (approximate) intended value, i.e., N0f8
5054
*(x::Real, ::Type{X}) where {X <: FixedPoint} = _convert(X, x)
5155

@@ -173,6 +177,30 @@ end
173177

174178
bswap(x::X) where {X <: FixedPoint} = sizeof(X) == 1 ? x : X(bswap(x.i), 0)
175179

180+
# Since `FixedPoint` is not an integer type, it is not clear in what type
181+
# `signed` and `unsigned` for `FixedPoint` should return values. They should
182+
# currently throw errors in case we support "unsigned Fixed" or "signed Normed"
183+
# in the future. The following "incomplete" code is necessary for Julia v1.0
184+
# etc. to prevent accidental conversion to an integer type.
185+
signed(x::X) where {X <: FixedPoint} = signed(X)(signed(x.i), 0)
186+
unsigned(x::X) where {X <: FixedPoint} = unsigned(X)(unsigned(x.i), 0)
187+
188+
function copysign(x::X, y::Real) where {T, X <: FixedPoint{T}}
189+
T <: Signed ? X(copysign(x.i, y), 0) : throw_not_a_signed_number_error(x)
190+
end
191+
function flipsign(x::X, y::Real) where {T, X <: FixedPoint{T}}
192+
T <: Signed ? X(flipsign(x.i, y), 0) : throw_not_a_signed_number_error(x)
193+
end
194+
if copysign(-1, 0x1) !== 1 # for Julia v1.0 and v1.1 (julia #30748)
195+
copysign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = copysign(x, signed(y))
196+
flipsign(x::X, y::Unsigned) where {T, X <: FixedPoint{T}} = flipsign(x, signed(y))
197+
end
198+
@noinline function throw_not_a_signed_number_error(x)
199+
throw(ArgumentError("$x is not a signed number."))
200+
end
201+
202+
signbit(x::X) where {X <: FixedPoint} = signbit(x.i)
203+
176204
for f in (:zero, :oneunit, :one, :eps, :rawone, :rawtype, :floattype)
177205
@eval begin
178206
$f(x::FixedPoint) = $f(typeof(x))

src/fixed.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ struct Fixed{T <: Signed, f} <: FixedPoint{T, f}
2525
end
2626

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

3029
for T in (Int8, Int16, Int32, Int64)
3130
io = IOBuffer()

src/normed.jl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ struct Normed{T <: Unsigned, f} <: FixedPoint{T, f}
2020
end
2121

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

2524
for T in (UInt8, UInt16, UInt32, UInt64)
2625
io = IOBuffer()
@@ -248,8 +247,6 @@ Base.BigFloat(x::Normed) = reinterpret(x)*(1/BigFloat(rawone(x)))
248247

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

251-
abs(x::Normed) = x
252-
253250
# unchecked arithmetic
254251
*(x::T, y::T) where {T <: Normed} = convert(T,convert(floattype(T), x)*convert(floattype(T), y))
255252
/(x::T, y::T) where {T <: Normed} = convert(T,convert(floattype(T), x)/convert(floattype(T), y))

test/fixed.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,23 @@ end
399399
@test bswap(Q0f15(0.5)) === reinterpret(Q0f15, signed(0x0040))
400400
end
401401

402+
@testset "sign-related functions" begin
403+
@test_throws Exception signed(Q0f7)
404+
@test_throws Exception signed(0.5Q0f7)
405+
@test_throws Exception unsigned(Q0f7)
406+
@test_throws Exception unsigned(0.5Q0f7)
407+
@test copysign(0.5Q0f7, 0x1) === 0.5Q0f7
408+
@test copysign(0.5Q0f7, -1) === -0.5Q0f7
409+
@test flipsign(0.5Q0f7, 0x1) === 0.5Q0f7
410+
@test flipsign(0.5Q0f7, -1) === -0.5Q0f7
411+
@test_throws ArgumentError sign(0Q0f7)
412+
@test sign(0Q1f6) === 0Q1f6
413+
@test sign(0.5Q1f6) === 1Q1f6
414+
@test sign(-0.5Q1f6) === -1Q1f6
415+
@test signbit(0.5Q0f7) === false
416+
@test signbit(-0.5Q0f7) === true
417+
end
418+
402419
@testset "Promotion within Fixed" begin
403420
@test @inferred(promote(Q0f7(0.25), Q0f7(0.75))) ===
404421
(Q0f7(0.25), Q0f7(0.75))

test/normed.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,19 @@ end
318318
@test minmax(N0f8(0.8), N0f8(0.2)) === (N0f8(0.2), N0f8(0.8))
319319
end
320320

321+
@testset "sign-related functions" begin
322+
@test_throws Exception signed(N0f8)
323+
@test_throws Exception signed(1N0f8)
324+
@test_throws Exception unsigned(N0f8)
325+
@test_throws Exception unsigned(1N0f8)
326+
@test_throws ArgumentError copysign(1N0f8, 0x1)
327+
@test_throws ArgumentError copysign(1N0f8, -1)
328+
@test_throws ArgumentError flipsign(1N0f8, 0x1)
329+
@test_throws ArgumentError flipsign(1N0f8, -1)
330+
@test_throws ArgumentError sign(0N0f8)
331+
@test signbit(1N0f8) === false
332+
end
333+
321334
@testset "unit range" begin
322335
@test length(N0f8(0):N0f8(1)) == 2
323336
@test length(N0f8(1):N0f8(0)) == 0

0 commit comments

Comments
 (0)