Skip to content

Commit 3caea52

Browse files
committed
Put utility functions and macros into a new file "utilities.jl"
1 parent dfc3669 commit 3caea52

File tree

6 files changed

+77
-65
lines changed

6 files changed

+77
-65
lines changed

src/FixedPointNumbers.jl

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export
3131
# Functions
3232
scaledual
3333

34+
include("utilities.jl")
35+
36+
# reinterpretation
3437
reinterpret(x::FixedPoint) = x.i
3538
reinterpret(::Type{T}, x::FixedPoint{T,f}) where {T,f} = x.i
3639

@@ -64,20 +67,6 @@ typemin(::Type{T}) where {T <: FixedPoint} = T(typemin(rawtype(T)), 0)
6467
floatmin(::Type{T}) where {T <: FixedPoint} = eps(T)
6568
floatmax(::Type{T}) where {T <: FixedPoint} = typemax(T)
6669

67-
widen1(::Type{Int8}) = Int16
68-
widen1(::Type{UInt8}) = UInt16
69-
widen1(::Type{Int16}) = Int32
70-
widen1(::Type{UInt16}) = UInt32
71-
widen1(::Type{Int32}) = Int64
72-
widen1(::Type{UInt32}) = UInt64
73-
widen1(::Type{Int64}) = Int128
74-
widen1(::Type{UInt64}) = UInt128
75-
widen1(::Type{Int128}) = Int128
76-
widen1(::Type{UInt128}) = UInt128
77-
widen1(x::Integer) = x % widen1(typeof(x))
78-
79-
const ShortInts = Union{Int8,UInt8,Int16,UInt16}
80-
const LongInts = Union{UInt64, UInt128, Int64, Int128, BigInt}
8170

8271
"""
8372
floattype(::Type{T})
@@ -124,7 +113,7 @@ rawtype(x::FixedPoint) = rawtype(typeof(x))
124113
function showtype(io::IO, ::Type{X}) where {X <: FixedPoint}
125114
print(io, typechar(X))
126115
f = nbitsfrac(X)
127-
m = sizeof(X)*8-f-signbits(X)
116+
m = bitwidth(X)-f-signbits(X)
128117
print(io, m, 'f', f)
129118
io
130119
end
@@ -188,13 +177,13 @@ scaledual(::Type{Tdual}, x::FixedPoint) where Tdual = convert(Tdual, 1/rawone(x)
188177
scaledual(::Type{Tdual}, x::AbstractArray{T}) where {Tdual, T <: FixedPoint} =
189178
convert(Tdual, 1/rawone(T)), reinterpret(rawtype(T), x)
190179

191-
@noinline function throw_converterror(::Type{T}, x) where {T <: FixedPoint}
192-
n = 2^(8*sizeof(T))
193-
bitstring = sizeof(T) == 1 ? "an 8-bit" : "a $(8*sizeof(T))-bit"
180+
@noinline function throw_converterror(::Type{X}, x) where {X <: FixedPoint}
181+
n = 2^bitwidth(X)
182+
bitstring = bitwidth(X) == 8 ? "an 8-bit" : "a $(bitwidth(X))-bit"
194183
io = IOBuffer()
195-
show(IOContext(io, :compact=>true), typemin(T)); Tmin = String(take!(io))
196-
show(IOContext(io, :compact=>true), typemax(T)); Tmax = String(take!(io))
197-
throw(ArgumentError("$T is $bitstring type representing $n values from $Tmin to $Tmax; cannot represent $x"))
184+
show(IOContext(io, :compact=>true), typemin(X)); Xmin = String(take!(io))
185+
show(IOContext(io, :compact=>true), typemax(X)); Xmax = String(take!(io))
186+
throw(ArgumentError("$X is $bitstring type representing $n values from $Xmin to $Xmax; cannot represent $x"))
198187
end
199188

200189
rand(::Type{T}) where {T <: FixedPoint} = reinterpret(T, rand(rawtype(T)))

src/fixed.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ signbits(::Type{X}) where {X <: Fixed} = 1
3232

3333
for T in (Int8, Int16, Int32, Int64)
3434
io = IOBuffer()
35-
for f in 0:sizeof(T)*8-1
35+
for f in 0:bitwidth(T)-1
3636
sym = Symbol(String(take!(showtype(io, Fixed{T,f}))))
3737
@eval begin
3838
const $sym = Fixed{$T,$f}
@@ -96,13 +96,13 @@ promote_rule(::Type{Fixed{T,f}}, ::Type{Rational{TR}}) where {T,f,TR} = Rational
9696
f = max(f1, f2) # ensure we have enough precision
9797
T = promote_type(T1, T2)
9898
# make sure we have enough integer bits
99-
i1, i2 = 8*sizeof(T1)-f1, 8*sizeof(T2)-f2 # number of integer bits for each
100-
i = 8*sizeof(T)-f
99+
i1, i2 = bitwidth(T1)-f1, bitwidth(T2)-f2 # number of integer bits for each
100+
i = bitwidth(T)-f
101101
while i < max(i1, i2)
102102
Tw = widen1(T)
103103
T == Tw && break
104104
T = Tw
105-
i = 8*sizeof(T)-f
105+
i = bitwidth(T)-f
106106
end
107107
:(Fixed{$T,$f})
108108
end

src/normed.jl

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ signbits(::Type{X}) where {X <: Normed} = 0
2626

2727
for T in (UInt8, UInt16, UInt32, UInt64)
2828
io = IOBuffer()
29-
for f in 1:sizeof(T)*8
29+
for f in 1:bitwidth(T)
3030
sym = Symbol(String(take!(showtype(io, Normed{T,f}))))
3131
@eval begin
3232
const $sym = Normed{$T,$f}
@@ -39,7 +39,7 @@ reinterpret(::Type{Normed{T,f}}, x::T) where {T <: Unsigned,f} = Normed{T,f}(x,
3939

4040
zero(::Type{Normed{T,f}}) where {T,f} = Normed{T,f}(zero(T),0)
4141
function oneunit(::Type{T}) where {T <: Normed}
42-
T(typemax(rawtype(T)) >> (8*sizeof(T)-nbitsfrac(T)), 0)
42+
T(typemax(rawtype(T)) >> (bitwidth(T)-nbitsfrac(T)), 0)
4343
end
4444
one(::Type{T}) where {T <: Normed} = oneunit(T)
4545
zero(x::Normed) = zero(typeof(x))
@@ -76,36 +76,34 @@ function _convert(::Type{U}, x::Float16) where {T, f, U <: Normed{T,f}}
7676
end
7777
return _convert(U, Float32(x))
7878
end
79-
function _convert(::Type{U}, x::Tf) where {T, f, U <: Normed{T,f}, Tf <: Union{Float32, Float64}}
80-
if T == UInt128 && f == 53
81-
0 <= x <= Tf(3.777893186295717e22) || throw_converterror(U, x)
79+
function _convert(::Type{N}, x::Tf) where {T, f, N <: Normed{T,f}, Tf <: Union{Float32, Float64}}
80+
if T === UInt128 && f == 53
81+
0 <= x <= Tf(3.777893186295717e22) || throw_converterror(N, x)
8282
else
83-
0 <= x <= Tf((typemax(T)-rawone(U))/rawone(U)+1) || throw_converterror(U, x)
83+
0 <= x <= Tf((typemax(T)-rawone(N))/rawone(N)+1) || throw_converterror(N, x)
8484
end
8585

86-
significand_bits = Tf == Float64 ? 52 : 23
87-
if f <= (significand_bits + 1) && sizeof(T) * 8 < significand_bits
88-
return reinterpret(U, unsafe_trunc(T, round(rawone(U) * x)))
86+
if f <= (significand_bits(Tf) + 1) && bitwidth(T) < significand_bits(Tf)
87+
return reinterpret(N, unsafe_trunc(T, round(rawone(N) * x)))
8988
end
9089
# cf. the implementation of `frexp`
91-
Tw = f < sizeof(T) * 8 ? T : widen1(T)
92-
bits = sizeof(Tw) * 8 - 1
93-
xu = reinterpret(Tf == Float64 ? UInt64 : UInt32, x)
94-
k = Int(xu >> significand_bits)
95-
k == 0 && return zero(U) # neglect subnormal numbers
96-
significand = xu | (one(xu) << significand_bits)
97-
yh = unsafe_trunc(Tw, significand) << (bits - significand_bits)
98-
exponent_bias = Tf == Float64 ? 1023 : 127
99-
ex = exponent_bias - k + bits - f
90+
Tw = f < bitwidth(T) ? T : widen1(T)
91+
bits = bitwidth(Tw) - 1
92+
xu = reinterpret(Unsigned, x)
93+
k = Int(xu >> significand_bits(Tf))
94+
k == 0 && return zero(N) # neglect subnormal numbers
95+
significand = xu | (one(xu) << significand_bits(Tf))
96+
yh = unsafe_trunc(Tw, significand) << (bits - significand_bits(Tf))
97+
ex = exponent_bias(Tf) - k + bits - f
10098
yi = bits >= f ? yh - (yh >> f) : yh
10199
if ex <= 0
102-
ex == 0 && return reinterpret(U, unsafe_trunc(T, yi))
103-
ex != -1 || signbit(signed(yi)) && return typemax(U)
104-
return reinterpret(U, unsafe_trunc(T, yi + yi))
100+
ex == 0 && return reinterpret(N, unsafe_trunc(T, yi))
101+
ex != -1 || signbit(signed(yi)) && return typemax(N)
102+
return reinterpret(N, unsafe_trunc(T, yi + yi))
105103
end
106-
ex > bits && return reinterpret(U, ex == bits + 1 ? one(T) : zero(T))
104+
ex > bits && return reinterpret(N, ex == bits + 1 ? one(T) : zero(T))
107105
yi += one(Tw)<<((ex - 1) & bits) # RoundNearestTiesUp
108-
return reinterpret(U, unsafe_trunc(T, yi >> (ex & bits)))
106+
return reinterpret(N, unsafe_trunc(T, yi >> (ex & bits)))
109107
end
110108

111109
rem(x::T, ::Type{T}) where {T <: Normed} = x
@@ -115,14 +113,6 @@ rem(x::Float16, ::Type{T}) where {T <: Normed} = rem(Float32(x), T) # avoid ove
115113

116114
float(x::Normed) = convert(floattype(x), x)
117115

118-
macro f32(x::Float64) # just for hexadecimal floating-point literals
119-
:(Float32($x))
120-
end
121-
macro exp2(n)
122-
:(_exp2(Val($(esc(n)))))
123-
end
124-
_exp2(::Val{N}) where {N} = exp2(N)
125-
126116
# for Julia v1.0, which does not fold `div_float` before inlining
127117
inv_rawone(x) = (@generated) ? (y = 1.0 / rawone(x); :($y)) : 1.0 / rawone(x)
128118

@@ -275,7 +265,7 @@ function round(x::Normed{T,f}) where {T,f}
275265
Normed{T,f}(y+oneunit(Normed{T,f})) : y
276266
end
277267
function ceil(x::Normed{T,f}) where {T,f}
278-
k = 8*sizeof(T)-f
268+
k = bitwidth(T)-f
279269
mask = (typemax(T)<<k)>>k
280270
y = trunc(x)
281271
return convert(T, reinterpret(x)-reinterpret(y)) & (mask)>0 ?
@@ -324,13 +314,13 @@ end
324314
f = max(f1, f2) # ensure we have enough precision
325315
T = promote_type(T1, T2)
326316
# make sure we have enough integer bits
327-
i1, i2 = 8*sizeof(T1)-f1, 8*sizeof(T2)-f2 # number of integer bits for each
328-
i = 8*sizeof(T)-f
317+
i1, i2 = bitwidth(T1)-f1, bitwidth(T2)-f2 # number of integer bits for each
318+
i = bitwidth(T)-f
329319
while i < max(i1, i2)
330320
Tw = widen1(T)
331321
T == Tw && break
332322
T = Tw
333-
i = 8*sizeof(T)-f
323+
i = bitwidth(T)-f
334324
end
335325
:(Normed{$T,$f})
336326
end

src/utilities.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# utility functions and macros, which are independent of `FixedPoint`
2+
bitwidth(T::Type) = 8sizeof(T)
3+
4+
widen1(::Type{Int8}) = Int16
5+
widen1(::Type{UInt8}) = UInt16
6+
widen1(::Type{Int16}) = Int32
7+
widen1(::Type{UInt16}) = UInt32
8+
widen1(::Type{Int32}) = Int64
9+
widen1(::Type{UInt32}) = UInt64
10+
widen1(::Type{Int64}) = Int128
11+
widen1(::Type{UInt64}) = UInt128
12+
widen1(::Type{Int128}) = Int128
13+
widen1(::Type{UInt128}) = UInt128
14+
widen1(x::Integer) = x % widen1(typeof(x))
15+
16+
const ShortInts = Union{Int8, UInt8, Int16, UInt16}
17+
const LongInts = Union{Int64, UInt64, Int128, UInt128, BigInt}
18+
19+
macro f32(x::Float64) # just for hexadecimal floating-point literals
20+
:(Float32($x))
21+
end
22+
macro exp2(n)
23+
:(_exp2(Val($(esc(n)))))
24+
end
25+
_exp2(::Val{N}) where {N} = exp2(N)
26+
27+
# these are defined in julia/float.jl or julia/math.jl, but not exported
28+
significand_bits(::Type{Float32}) = 23
29+
significand_bits(::Type{Float64}) = 52
30+
exponent_bias(::Type{Float32}) = 127
31+
exponent_bias(::Type{Float64}) = 1023

test/fixed.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using FixedPointNumbers, Test
2+
using FixedPointNumbers: bitwidth
23

34
function test_op(fun::F, ::Type{T}, fx, fy, fxf, fyf, tol) where {F,T}
45
# Make sure that the result is representable
@@ -164,7 +165,7 @@ end
164165
(Int64, 63))
165166
tmax = typemax(Fixed{T, f})
166167
@test tmax == BigInt(typemax(T)) / BigInt(2)^f
167-
tol = (tmax + BigFloat(1.0)) / (sizeof(T) * 8)
168+
tol = (tmax + BigFloat(1.0)) / bitwidth(T)
168169
for x in range(-1, stop=BigFloat(tmax)-tol, length=50)
169170
@test abs(Fixed{T, f}(x) - x) <= tol
170171
end

test/normed.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using FixedPointNumbers, Test
2+
using FixedPointNumbers: bitwidth
23

34
@testset "reinterpret" begin
45
@test reinterpret(N0f8, 0xa2).i === 0xa2
@@ -106,7 +107,7 @@ end
106107
# issue 102
107108
for T in (UInt8, UInt16, UInt32, UInt64, UInt128)
108109
for Tf in (Float16, Float32, Float64)
109-
@testset "Normed{$T,$f}(::$Tf)" for f = 1:sizeof(T)*8
110+
@testset "Normed{$T,$f}(::$Tf)" for f = 1:bitwidth(T)
110111
U = Normed{T,f}
111112
r = FixedPointNumbers.rawone(U)
112113

@@ -123,7 +124,7 @@ end
123124
isinf(input_upper) && continue # for Julia v0.7
124125
@test reinterpret(U(input_upper)) == T(min(round(BigFloat(input_upper) * r), typemax(T)))
125126

126-
input_exp2 = Tf(exp2(sizeof(T) * 8 - f))
127+
input_exp2 = Tf(exp2(bitwidth(T) - f))
127128
isinf(input_exp2) && continue
128129
@test reinterpret(U(input_exp2)) == T(input_exp2) * r
129130
end
@@ -143,7 +144,7 @@ end
143144

144145
for Tf in (Float16, Float32, Float64)
145146
@testset "$Tf(::Normed{$Ti})" for Ti in (UInt8, UInt16)
146-
@testset "$Tf(::Normed{$Ti,$f})" for f = 1:(sizeof(Ti)*8)
147+
@testset "$Tf(::Normed{$Ti,$f})" for f = 1:bitwidth(Ti)
147148
T = Normed{Ti,f}
148149
float_err = 0.0
149150
for i = typemin(Ti):typemax(Ti)
@@ -156,7 +157,7 @@ end
156157
end
157158
end
158159
@testset "$Tf(::Normed{$Ti})" for Ti in (UInt32, UInt64, UInt128)
159-
@testset "$Tf(::Normed{$Ti,$f})" for f = 1:(sizeof(Ti)*8)
160+
@testset "$Tf(::Normed{$Ti,$f})" for f = 1:bitwidth(Ti)
160161
T = Normed{Ti,f}
161162
error_count = 0
162163
for i in vcat(Ti(0x00):Ti(0xFF), (typemax(Ti)-0xFF):typemax(Ti))

0 commit comments

Comments
 (0)