Skip to content

Commit add18eb

Browse files
committed
Turn Fixed into a general FixedPoint implementation.
This expands the implementation in Fixed to handle more cases and be generally more useful. In the future `UFixed` should be merged in and the special behaviour required by ColorTypes implemented as a new type, based on this implementation.
1 parent e9ba16f commit add18eb

File tree

3 files changed

+120
-66
lines changed

3 files changed

+120
-66
lines changed

src/FixedPointNumbers.jl

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,59 @@ export
4141
scaledual
4242

4343
getindex(x::FixedPoint) = x.i
44+
reinterpret{T,f}(::Type{T}, x::FixedPoint{T,f}) = x[]
45+
# reinterpret{T <: Integer,f}(::Type{FixedPoint{T,f}}, x::T) = FixedPoint{T,f}(x, 0)
46+
4447

4548
# comparison
4649
=={T <: FixedPoint}(x::T, y::T) = x[] == y[]
4750
<{T <: FixedPoint}(x::T, y::T) = x[] < y[]
4851
<={T <: FixedPoint}(x::T, y::T) = x[] <= y[]
4952

50-
# predicates
51-
isinteger{T,f}(x::FixedPoint{T,f}) = (x[]&(1<<f-1)) == 0
53+
#predicates
54+
isfinite(x::FixedPoint) = true
55+
isnan(x::FixedPoint) = false
56+
isinf(x::FixedPoint) = false
5257

58+
#traits
5359
typemax{T<: FixedPoint}(::Type{T}) = T(typemax(rawtype(T)), 0)
5460
typemin{T<: FixedPoint}(::Type{T}) = T(typemin(rawtype(T)), 0)
5561
realmin{T<: FixedPoint}(::Type{T}) = typemin(T)
5662
realmax{T<: FixedPoint}(::Type{T}) = typemax(T)
63+
eps{T<:FixedPoint}(::Type{T}) = T(one(rawtype(T)),0)
64+
eps{T<:FixedPoint}(::T) = eps(T)
65+
sizeof{T<:FixedPoint}(::Type{T}) = sizeof(rawtype(T))
66+
67+
zero{T <: FixedPoint}(::Type{T}) = T(zero(rawtype(T)),0)
68+
zero{T <: FixedPoint}(x::T) = zero(T)
69+
one{T <: FixedPoint}(x::T) = one(T)
70+
71+
# Basic operators & arithmetics
72+
(-){T<:FixedPoint}(x::T) = T(-x[], 0)
73+
(~){T<:FixedPoint}(x::T) = T(~x[], 0)
74+
abs{T<:FixedPoint}(x::T) = T(abs(x[]),0)
75+
76+
+{T<:FixedPoint}(x::T, y::T) = T(x[] + y[],0)
77+
-{T<:FixedPoint}(x::T, y::T) = T(x[] - y[],0)
78+
79+
for f in (:div, :fld, :rem, :mod, :mod1, :rem1, :fld1, :min, :max)
80+
@eval begin
81+
$f{T<:FixedPoint}(x::T, y::T) = T($f(x[],y[]),0)
82+
end
83+
end
84+
85+
function minmax{T<:FixedPoint}(x::T, y::T)
86+
a, b = minmax(x[], y[])
87+
T(a,0), T(b,0)
88+
end
89+
90+
bswap{T <: Union{UInt8, Int8}, f}(x::FixedPoint{T,f}) = x
91+
bswap{T <: FixedPoint}(x::T) = T(bswap(x[]),0)
5792

5893
include("fixed.jl")
5994
include("ufixed.jl")
6095
include("deprecations.jl")
6196

62-
6397
# Promotions for reductions
6498
const Treduce = Float64
6599
for F in (AddFun, MulFun)
@@ -73,13 +107,12 @@ reducedim_init{T<:FixedPoint}(f::IdFun, op::MulFun,
73107
A::AbstractArray{T}, region) =
74108
reducedim_initarray(A, region, one(Treduce))
75109

76-
# TODO: rewrite this by @generated
77-
for T in tuple(Fixed16, UF...)
78-
R = rawtype(T)
79-
@eval begin
80-
reinterpret(::Type{$R}, x::$T) = x[]
81-
end
82-
end
110+
# Iteration
111+
# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around
112+
# unless we iterate using a wider type
113+
start{T<:FixedPoint}(r::StepRange{T}) = convert(typeof(r.start[] + r.step[]), r.start[])
114+
next{T<:FixedPoint}(r::StepRange{T}, i::Integer) = (T(i,0), i+r.step[])
115+
done{T<:FixedPoint}(r::StepRange{T}, i::Integer) = isempty(r) || (i > r.stop[])
83116

84117
# When multiplying by a float, reduce two multiplies to one.
85118
# Particularly useful for arrays.

src/fixed.jl

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1-
# 32-bit fixed point; parameter `f` is the number of fraction bits
2-
immutable Fixed{T <: Signed,f} <: FixedPoint{T, f}
1+
###
2+
# Fixed implements a general purpose FixedPoint number.
3+
# The underlying storage type is given by the parameter `T`,
4+
# and the number of fractional bits is given by `f`
5+
# The dot is just before the fractional part so in order to represent one,
6+
# `f` needs to be atleast smaller by 1 in the unsigned case and smaller by two
7+
# in the signed case, then the number of bits in `T`.
8+
#
9+
# In a further iteration of the design `Fixed` should be renamed to `FixedPoint` and the aliase `typealias Fixed{T <: Signed, f} FixedPoint{T, f}` and `typealias UFixed{T <: Unsigned, f} FixedPoint{T, f}` introduced.
10+
###
11+
immutable Fixed{T,f} <: FixedPoint{T, f}
312
i::T
413

514
# constructor for manipulating the representation;
615
# selected by passing an extra dummy argument
16+
Fixed(i::T, _) = new(i)
717
Fixed(i::Integer,_) = new(i % T)
818

919
Fixed(x) = convert(Fixed{T,f}, x)
@@ -14,22 +24,73 @@ typealias Fixed16 Fixed{Int32, 16}
1424
rawtype{T,f}(::Type{Fixed{T,f}}) = T
1525
nbitsfrac{T,f}(::Type{Fixed{T,f}}) = f
1626

17-
# basic operators
18-
-{T,f}(x::Fixed{T,f}) = Fixed{T,f}(-x[],0)
19-
abs{T,f}(x::Fixed{T,f}) = Fixed{T,f}(abs(x[]),0)
27+
reinterpret{T <: Integer,f}(::Type{Fixed{T,f}}, x::T) = Fixed{T,f}(x, 0)
2028

21-
+{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(x[]+y[],0)
22-
-{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(x[]-y[],0)
29+
## predicates
30+
isinteger{T,f}(x::Fixed{T,f}) = (x[]&(1<<f-1)) == 0
31+
32+
function one{T, f}(::Type{Fixed{T, f}})
33+
if T <: Unsigned && sizeof(T) * 8 > f ||
34+
T <: Signed && sizeof(T) * 8 > (f+1)
35+
return Fixed{T, f}(2^f-1,0)
36+
else
37+
throw(DomainError())
38+
end
39+
end
40+
41+
## basic operators & arithmetics
2342

2443
# with truncation:
25-
#*{f}(x::Fixed32{f}, y::Fixed32{f}) = Fixed32{f}(Base.widemul(x[],y[])>>f,0)
44+
# *{T<:Fixed}(x::T, y::T) =
45+
# T(Base.widemul(x[],y[]) >> nbitsfrac(T),0)
2646
# with rounding up:
27-
*{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}((Base.widemul(x[],y[]) + (convert(widen(T), 1) << (f-1) ))>>f,0)
47+
function *{T<:Fixed}(x::T, y::T)
48+
f = nbitsfrac(T)
49+
i = Base.widemul(x[],y[])
50+
T((i + convert(widen(rawtype(T)), 1) << (f-1) )>>f,0)
51+
end
52+
53+
function /{T<:Fixed}(x::T, y::T)
54+
f = nbitsfrac(T)
55+
T(div(convert(widen(rawtype(T)), x[]) << f, y.i), 0)
56+
end
57+
58+
## rounding
59+
# Round towards negative infinity
60+
trunc{T<:Fixed}(x::T) = T(x[] & ~(1 << nbitsfrac(T) - 1), 0)
61+
# Round towards negative infinity
62+
floor{T<:Fixed}(x::T) = trunc(x)
63+
# Round towards positive infinity
64+
ceil{T<:Fixed}(x::T) = trunc(T(x[] + 1 << (nbitsfrac(T)-1), 0))
65+
# Round towards even
66+
function round{T<:Fixed}(x::T)
67+
even = x[] & (1 << nbitsfrac(T)) == 0
68+
if even
69+
return floor(x)
70+
else
71+
return ceil(x)
72+
end
73+
end
74+
# Round towards positive infinity
75+
ceil{T<:Fixed}(x::T) = trunc(T(x[] + 1 << (nbitsfrac(T)-1), 0))
76+
# Round towards even
77+
function round{T<:Fixed}(x::T)
78+
even = x[] & (1 << nbitsfrac(T)) == 0
79+
if even
80+
return floor(x)
81+
else
82+
return ceil(x)
83+
end
84+
end
2885

29-
/{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(div(convert(widen(T), x[]) << f, y[]), 0)
86+
trunc{TI<:Integer, T <: Fixed}(::Type{TI}, x::T) =
87+
convert(TI, x[] >> nbitsfrac(T))
88+
floor{T<:Integer}(::Type{T}, x::Fixed) = trunc(T, x)
89+
ceil{T<:Integer}(::Type{T}, x::Fixed) = trunc(T, ceil(x))
90+
round{T<:Integer}(::Type{T}, x::Fixed) = trunc(T, round(x))
3091

3192

32-
# # conversions and promotions
93+
## conversions and promotions
3394
convert{T,f}(::Type{Fixed{T,f}}, x::Integer) = Fixed{T,f}(convert(T,x)<<f,0)
3495
convert{T,f}(::Type{Fixed{T,f}}, x::AbstractFloat) = Fixed{T,f}(trunc(T,x)<<f + round(T, rem(x,1)*(1<<f)),0)
3596
convert{T,f}(::Type{Fixed{T,f}}, x::Rational) = Fixed{T,f}(x.num)/Fixed{T,f}(x.den)
@@ -52,7 +113,6 @@ promote_rule{T,f,TI<:Integer}(ft::Type{Fixed{T,f}}, ::Type{TI}) = Fixed{T,f}
52113
promote_rule{T,f,TF<:AbstractFloat}(::Type{Fixed{T,f}}, ::Type{TF}) = TF
53114
promote_rule{T,f,TR}(::Type{Fixed{T,f}}, ::Type{Rational{TR}}) = Rational{TR}
54115

55-
# TODO: Document and check that it still does the right thing.
56116
decompose{T,f}(x::Fixed{T,f}) = x[], -f, 1
57117

58118
# printing

src/ufixed.jl

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# UFixed{T,f} maps UInts from 0 to 2^f-1 to the range [0.0, 1.0]
22
# For example, a UFixed8 maps 0x00 to 0.0 and 0xff to 1.0
3-
43
immutable UFixed{T<:Unsigned,f} <: FixedPoint{T,f}
54
i::T
65

7-
UFixed(i::Integer,_) = new(i%T) # for setting by raw representation
6+
# constructor for manipulating the representation;
7+
# selected by passing an extra dummy argument
8+
UFixed(i::T, _) = new(i)
9+
UFixed(i::Integer,_) = new(i % T)
10+
811
UFixed(x) = convert(UFixed{T,f}, x)
912
end
1013

@@ -34,7 +37,6 @@ const uf12 = UFixedConstructor{UInt16,12}()
3437
const uf14 = UFixedConstructor{UInt16,14}()
3538
const uf16 = UFixedConstructor{UInt16,16}()
3639

37-
zero{T,f}(::Type{UFixed{T,f}}) = UFixed{T,f}(zero(T),0)
3840
for uf in UF
3941
TT = rawtype(uf)
4042
f = nbitsfrac(uf)
@@ -43,8 +45,6 @@ for uf in UF
4345
one(::Type{$T}) = $T($(2^f-1),0)
4446
end
4547
end
46-
zero(x::UFixed) = zero(typeof(x))
47-
one(x::UFixed) = one(typeof(x))
4848
rawone(v) = one(v)[]
4949

5050
# Conversions
@@ -80,18 +80,9 @@ sizeof{T<:UFixed}(::Type{T}) = sizeof(rawtype(T))
8080
abs(x::UFixed) = x
8181

8282
# Arithmetic
83-
(-){T<:UFixed}(x::T) = T(-x[], 0)
84-
(~){T<:UFixed}(x::T) = T(~x[], 0)
85-
86-
+{T,f}(x::UFixed{T,f}, y::UFixed{T,f}) = UFixed{T,f}(convert(T, x[]+y[]),0)
87-
-{T,f}(x::UFixed{T,f}, y::UFixed{T,f}) = UFixed{T,f}(convert(T, x[]-y[]),0)
8883
*{T,f}(x::UFixed{T,f}, y::UFixed{T,f}) = UFixed{T,f}((Base.widemul(x[],y[]) + (convert(widen(T), 1) << (f-1) ))>>f,0)
8984
/{T,f}(x::UFixed{T,f}, y::UFixed{T,f}) = UFixed{T,f}(div(convert(widen(T), x[])<<f, y[]),0)
9085

91-
# Comparisons
92-
<{T<:UFixed}(x::T, y::T) = x[] < y[]
93-
<={T<:UFixed}(x::T, y::T) = x[] < y[]
94-
9586
# Functions
9687
trunc{T<:UFixed}(x::T) = T(div(x[], rawone(T))*rawone(T),0)
9788
floor{T<:UFixed}(x::T) = trunc(x)
@@ -116,36 +107,6 @@ round(x::UFixed) = round(Int, x)
116107
floor(x::UFixed) = floor(Int, x)
117108
ceil(x::UFixed) = ceil(Int, x)
118109

119-
isfinite(x::UFixed) = true
120-
isnan(x::UFixed) = false
121-
isinf(x::UFixed) = false
122-
123-
bswap{f}(x::UFixed{UInt8,f}) = x
124-
bswap(x::UFixed) = typeof(x)(bswap(x[]),0)
125-
126-
for f in (:div, :fld, :rem, :mod, :mod1, :rem1, :fld1, :min, :max)
127-
@eval begin
128-
$f{T<:UFixed}(x::T, y::T) = T($f(x[],y[]),0)
129-
end
130-
end
131-
function minmax{T<:UFixed}(x::T, y::T)
132-
a, b = minmax(x[], y[])
133-
T(a,0), T(b,0)
134-
end
135-
136-
# Iteration
137-
# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around
138-
# unless we iterate using a wider type
139-
if VERSION < v"0.3-"
140-
start{T<:UFixed}(r::Range{T}) = convert(typeof(r.start[] + r.step[]), r.start[])
141-
next{T<:UFixed}(r::Range{T}, i::Integer) = (T(i,0), i + r.step[])
142-
done{T<:UFixed}(r::Range{T}, i::Integer) = isempty(r) || (i > r.len)
143-
else
144-
start{T<:UFixed}(r::StepRange{T}) = convert(typeof(r.start[] + r.step[]), r.start[])
145-
next{T<:UFixed}(r::StepRange{T}, i::Integer) = (T(i,0), i + r.step[])
146-
done{T<:UFixed}(r::StepRange{T}, i::Integer) = isempty(r) || (i > r.stop[])
147-
end
148-
149110
function decompose(x::UFixed)
150111
g = gcd(x[], rawone(x))
151112
div(x[],g), 0, div(rawone(x),g)

0 commit comments

Comments
 (0)