Skip to content

Commit 7f2cb6c

Browse files
committed
Fix UnitRange construction and length(r)
1 parent 3048c18 commit 7f2cb6c

File tree

6 files changed

+70
-4
lines changed

6 files changed

+70
-4
lines changed

src/FixedPointNumbers.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Base: ==, <, <=, -, +, *, /, ~, isapprox,
88
div, fld, rem, mod, mod1, fld1, min, max, minmax,
99
rand
1010

11+
using Base.Checked: checked_add, checked_sub
12+
1113
using Base: @pure
1214

1315
"""

src/fixed.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ function rawone(::Type{Fixed{T,f}}) where {T, f}
4343
f >= bitwidth(T)-1 && throw_converterror(Fixed{T,f}, 1)
4444
oneunit(T) << f
4545
end
46+
function rawminusone(::Type{Fixed{T,f}}) where {T, f}
47+
(-oneunit(T)) << f
48+
end
4649

4750
# unchecked arithmetic
4851

@@ -85,6 +88,27 @@ end
8588
(::Type{TR})(x::Fixed{T,f}) where {TR <: Rational,T,f} =
8689
TR(x.i>>f + (x.i&(1<<f-1))//(one(widen1(T))<<f))
8790

91+
# The following are needed for range construction
92+
function round(x::Fixed{T,f}, ::RoundingMode{:Down}) where {T,f}
93+
mask = abs(rawminusone(Fixed{T,f}) + oneunit(T))
94+
xraw = reinterpret(x)
95+
return Fixed{T,f}((xraw & ~mask) + (signbit(xraw) & (xraw & mask) != 0 ? rawminusone(Fixed{T,f}) : zero(xraw)), 0)
96+
end
97+
Base.unitrange_last(start::T, stop::T) where {T<:Fixed} =
98+
ifelse(stop >= start, convert(T,start+floor(stop-start)),
99+
convert(T,start+T(-1)))
100+
101+
102+
# Range lengths
103+
Base.unsafe_length(r::AbstractUnitRange{X}) where {X <: Fixed{<:Union{SShorterThanInt,Int},f}} where {f} =
104+
Int(reinterpret(last(r)) >> f - reinterpret(first(r)) >> f) + 1
105+
Base.unsafe_length(r::AbstractUnitRange{X}) where {X <: Fixed{T,f}} where {T<:Signed,f} =
106+
T(reinterpret(last(r)) >> f - reinterpret(first(r)) >> f) + oneunit(T)
107+
Base.length(r::AbstractUnitRange{X}) where {X <: Fixed{<:SShorterThanInt,f}} where {f} =
108+
Base.unsafe_length(r)
109+
Base.length(r::AbstractUnitRange{X}) where {X <: Fixed{T,f}} where {T<:Signed,f} =
110+
checked_add(checked_sub(T(reinterpret(last(r)) >> f), T(reinterpret(first(r)) >> f)), oneunit(T))
111+
88112
promote_rule(ft::Type{Fixed{T,f}}, ::Type{TI}) where {T,f,TI <: Integer} = Fixed{T,f}
89113
promote_rule(::Type{Fixed{T,f}}, ::Type{TF}) where {T,f,TF <: AbstractFloat} = TF
90114
promote_rule(::Type{Fixed{T,f}}, ::Type{Rational{TR}}) where {T,f,TR} = Rational{TR}

src/normed.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,16 @@ function decompose(x::Normed)
275275
div(reinterpret(x),g), 0, div(rawone(x),g)
276276
end
277277

278+
# Range lengths
279+
Base.unsafe_length(r::AbstractUnitRange{X}) where {X <: Normed{<:UShorterThanInt}} =
280+
Int(last(r)) - Int(first(r)) + 1
281+
Base.unsafe_length(r::AbstractUnitRange{X}) where {X <: Normed{T}} where {T<:Unsigned} =
282+
T(last(r)) - T(first(r)) + oneunit(T)
283+
Base.length(r::AbstractUnitRange{X}) where {X <: Normed{<:ShorterThanInt}} =
284+
Base.unsafe_length(r)
285+
Base.length(r::AbstractUnitRange{X}) where {X <: Normed{T}} where {T<:Integer} =
286+
checked_add(checked_sub(T(last(r)), T(first(r))), oneunit(T))
287+
278288
# Promotions
279289
promote_rule(::Type{T}, ::Type{Tf}) where {T <: Normed,Tf <: AbstractFloat} = promote_type(floattype(T), Tf)
280290
promote_rule(::Type{T}, ::Type{R}) where {T <: Normed,R <: Rational} = R

src/utilities.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ widen1(x::Integer) = x % widen1(typeof(x))
1616
const ShortInts = Union{Int8, UInt8, Int16, UInt16}
1717
const LongInts = Union{Int64, UInt64, Int128, UInt128, BigInt}
1818

19+
const ShorterThanInt = Int === Int32 ? ShortInts : Union{ShortInts, Int32, UInt32}
20+
const NotBiggerThanInt = Union{ShorterThanInt, Int, UInt}
21+
const SShorterThanInt = typeintersect(ShorterThanInt, Signed)
22+
const UShorterThanInt = typeintersect(ShorterThanInt, Unsigned)
23+
1924
macro f32(x::Float64) # just for hexadecimal floating-point literals
2025
:(Float32($x))
2126
end

test/fixed.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,17 @@ end
111111
end
112112
end
113113

114+
@testset "unit range" begin
115+
@test length(Q1f6(-1):Q1f6(0)) == 2
116+
@test collect(Q1f6(-1):Q1f6(0)) == Q1f6[-1, 0]
117+
@test length(Q6f1(-64):Q6f1(63)) == 128
118+
QIntW = Fixed{Int,bitwidth(Int)-1}
119+
@test length(QIntW(-1):QIntW(0)) == 2
120+
QInt1 = Fixed{Int,1}
121+
@test length(typemin(QInt1):typemax(QInt1)-oneunit(QInt1)) == typemax(Int)-1
122+
@test length(typemin(QInt1):typemax(QInt1)) == typemax(Int)
123+
end
124+
114125
@testset "reductions" begin
115126
F8 = Fixed{Int8,8}
116127
a = F8[0.498, 0.1]

test/normed.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,31 @@ end
295295
@test bswap(N0f8(0.5)) === N0f8(0.5)
296296
@test bswap(N0f16(0.5)) === reinterpret(N0f16, 0x0080)
297297
@test minmax(N0f8(0.8), N0f8(0.2)) === (N0f8(0.2), N0f8(0.8))
298+
end
298299

299-
r = reinterpret(N0f8, 0x01):reinterpret(N0f8, 0x01):reinterpret(N0f8, convert(UInt8, 48))
300-
@test length(r) == 48
301-
end
300+
@testset "unit range" begin
301+
@test length(N0f8(0):N0f8(1)) == 2
302+
@test collect(N0f8(0):N0f8(1)) == N0f8[0, 1]
303+
@test length(N7f1(0):N7f1(255)) == 256
304+
NIntW = Normed{UInt,bitwidth(UInt)}
305+
@test length(NIntW(0):NIntW(1)) == 2
306+
NInt1 = Normed{UInt,1}
307+
@test length(NInt1(0):typemax(NInt1)-oneunit(NInt1)) == typemax(UInt)
308+
@test_throws OverflowError length(NInt1(0):typemax(NInt1))
309+
@test Base.unsafe_length(NInt1(0):typemax(NInt1)) == 0 # overflow
310+
N64f64 = Normed{UInt128,64}
311+
@test_broken length(N64f64(0):typemax(N64f64)) == UInt128(typemax(UInt64)) + 1
312+
end
302313

303-
@testset "step range" begin
314+
@testset "step range" begin
304315
counter = 0
305316
for x in N0f8(0):eps(N0f8):N0f8(1)
306317
counter += 1
307318
end
308319
@test counter == 256
320+
@test length(N0f8(0):eps(N0f8):N0f8(1)) == 256
321+
r = reinterpret(N0f8, 0x01):reinterpret(N0f8, 0x01):reinterpret(N0f8, convert(UInt8, 48))
322+
@test length(r) == 48
309323
end
310324

311325
@testset "Promotion within Normed" begin

0 commit comments

Comments
 (0)