Skip to content

Commit 9da3c8b

Browse files
committed
Rename UFixed to Normed
This rename reflects the nature of `UFixed` it is not just a unsigned fixpoint number type (for that you can use `Fixed{T<:Unsigned}`), but rather a number type that is normalised to a specific `one`.
1 parent fdf5506 commit 9da3c8b

7 files changed

Lines changed: 219 additions & 216 deletions

File tree

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ is the number of fraction bits.
2828

2929
For `T<:Signed` (a signed integer), there is a fixed-point type
3030
`Fixed{T, f}`; for `T<:Unsigned` (an unsigned integer), there is the
31-
`UFixed{T, f}` type. However, there are slight differences in behavior
31+
`Normed{T, f}` type. However, there are slight differences in behavior
3232
that go beyond signed/unsigned distinctions.
3333

3434
The `Fixed{T,f}` types use 1 bit for sign, and `f` bits to represent
@@ -43,23 +43,23 @@ is interpreted as if the integer representation has been divided by
4343

4444
because the range of `Int8` is from -128 to 127.
4545

46-
In contrast, the `UFixed{T,f}`, with `f` fraction bits, map the closed
46+
In contrast, the `Normed{T,f}`, with `f` fraction bits, map the closed
4747
interval [0.0,1.0] to the span of numbers with `f` bits. For example,
48-
the `UFixed8` type (aliased to `UFixed{UInt8,8}`) is represented
48+
the `Normed8` type (aliased to `Normed{UInt8,8}`) is represented
4949
internally by a `UInt8`, and makes `0x00` equivalent to `0.0` and
50-
`0xff` to `1.0`. Consequently, `UFixed` numbers are scaled by `2^f-1`
51-
rather than `2^f`. The type aliases `UFixed10`, `UFixed12`,
52-
`UFixed14`, and `UFixed16` are all based on `UInt16` and reach the
50+
`0xff` to `1.0`. Consequently, `Normed` numbers are scaled by `2^f-1`
51+
rather than `2^f`. The type aliases `Normed10`, `Normed12`,
52+
`Normed14`, and `Normed16` are all based on `UInt16` and reach the
5353
value `1.0` at 10, 12, 14, and 16 bits, respectively (`0x03ff`,
5454
`0x0fff`, `0x3fff`, and `0xffff`).
5555

56-
To construct such a number, use `convert(UFixed12, 1.3)`, `UFixed12(1.3)`, `UFixed{UInt16,12}(1.3)`, or the literal syntax
57-
`0x14ccuf12`. The latter syntax means to construct a `UFixed12` (it ends in
56+
To construct such a number, use `convert(Normed12, 1.3)`, `Normed12(1.3)`, `Normed{UInt16,12}(1.3)`, or the literal syntax
57+
`0x14ccuf12`. The latter syntax means to construct a `Normed12` (it ends in
5858
`uf12`) from the `UInt16` value `0x14cc`.
5959

6060
More generally, an arbitrary number of bits from any of the standard unsigned
6161
integer widths can be used for the fractional part. For example:
62-
`UFixed{UInt32,16}`, `UFixed{UInt64,3}`, `UFixed{UInt128,7}`.
62+
`Normed{UInt32,16}`, `Normed{UInt64,3}`, `Normed{UInt128,7}`.
6363

6464
There currently is no literal syntax for signed `Fixed` numbers.
6565

src/FixedPointNumbers.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ abstract FixedPoint{T <: Integer, f} <: Real
3030
export
3131
FixedPoint,
3232
Fixed,
33-
UFixed,
33+
Normed,
3434
# "special" typealiases
3535
# Q and U typealiases are exported in separate source files
3636
# literal constructor constants
@@ -112,7 +112,7 @@ showcompact{T,f}(io::IO, x::FixedPoint{T,f}) = show(io, round(convert(Float64,x)
112112

113113

114114
include("fixed.jl")
115-
include("ufixed.jl")
115+
include("normed.jl")
116116
include("deprecations.jl")
117117

118118
eps{T<:FixedPoint}(::Type{T}) = T(one(rawtype(T)),0)

src/deprecations.jl

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import Base.@deprecate_binding
77
@deprecate_binding UFixed14 N2f14
88
@deprecate_binding UFixed16 N0f16
99

10-
@deprecate_binding UfixedBase UFixed
11-
@deprecate_binding Ufixed UFixed
10+
@deprecate_binding UfixedBase Normed
11+
@deprecate_binding Ufixed Normed
12+
@deprecate_binding UFixed Normed
1213
@deprecate_binding Ufixed8 N0f8
1314
@deprecate_binding Ufixed10 N6f10
1415
@deprecate_binding Ufixed12 N4f12
@@ -35,20 +36,22 @@ Compat.@dep_vectorize_1arg Real ufixed16
3536

3637
## The next lines mimic the floating-point literal syntax "3.2f0"
3738
# construction using a UInt, i.e., 0xccuf8
38-
immutable UFixedConstructor{T,f} end
39-
function *{T,f}(n::Integer, ::UFixedConstructor{T,f})
39+
immutable NormedConstructor{T,f} end
40+
function *{T,f}(n::Integer, ::NormedConstructor{T,f})
4041
i = 8*sizeof(T)-f
4142
io = IOBuffer()
4243
show(io, n)
4344
nstr = takebuf_string(io)
4445
cstr = typeof(n) == T ? nstr : "convert($T, $nstr)"
4546
Base.depwarn("$(nstr)uf$f is deprecated, please use reinterpret(N$(i)f$f, $cstr) instead", :*)
46-
reinterpret(UFixed{T,f}, convert(T, n))
47+
reinterpret(Normed{T,f}, convert(T, n))
4748
end
48-
const uf8 = UFixedConstructor{UInt8,8}()
49-
const uf10 = UFixedConstructor{UInt16,10}()
50-
const uf12 = UFixedConstructor{UInt16,12}()
51-
const uf14 = UFixedConstructor{UInt16,14}()
52-
const uf16 = UFixedConstructor{UInt16,16}()
49+
const uf8 = NormedConstructor{UInt8,8}()
50+
const uf10 = NormedConstructor{UInt16,10}()
51+
const uf12 = NormedConstructor{UInt16,12}()
52+
const uf14 = NormedConstructor{UInt16,14}()
53+
const uf16 = NormedConstructor{UInt16,16}()
54+
55+
@deprecate_binding UfixedConstructor NormedConstructor
56+
@deprecate_binding UFixedConstructor NormedConstructor
5357

54-
@deprecate_binding UfixedConstructor UFixedConstructor

src/normed.jl

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Normed{T,f} maps UInts from 0 to 2^f-1 to the range [0.0, 1.0]
2+
# For example, Normed{UInt8,8} == N0f8 maps 0x00 to 0.0 and 0xff to 1.0
3+
4+
immutable Normed{T<:Unsigned,f} <: FixedPoint{T,f}
5+
i::T
6+
7+
Normed(i::Integer,_) = new(i%T) # for setting by raw representation
8+
Normed(x) = convert(Normed{T,f}, x)
9+
end
10+
11+
rawtype{T,f}(::Type{Normed{T,f}}) = T
12+
rawtype(x::Number) = rawtype(typeof(x))
13+
nbitsfrac{T,f}(::Type{Normed{T,f}}) = f
14+
floattype{T<:Normed}(::Type{T}) = floattype(supertype(T))
15+
typechar{X<:Normed}(::Type{X}) = 'N'
16+
signbits{X<:Normed}(::Type{X}) = 0
17+
18+
for T in (UInt8, UInt16, UInt32, UInt64)
19+
for f in 0:sizeof(T)*8
20+
sym = Symbol(takebuf_string(showtype(_iotypealias, Normed{T,f})))
21+
@eval begin
22+
typealias $sym Normed{$T,$f}
23+
export $sym
24+
end
25+
end
26+
end
27+
28+
reinterpret{T<:Unsigned, f}(::Type{Normed{T,f}}, x::T) = Normed{T,f}(x, 0)
29+
30+
zero{T,f}(::Type{Normed{T,f}}) = Normed{T,f}(zero(T),0)
31+
function one{T<:Normed}(::Type{T})
32+
T(typemax(rawtype(T)) >> (8*sizeof(T)-nbitsfrac(T)), 0)
33+
end
34+
zero(x::Normed) = zero(typeof(x))
35+
one(x::Normed) = one(typeof(x))
36+
rawone(v) = reinterpret(one(v))
37+
38+
# Conversions
39+
convert{T<:Normed}(::Type{T}, x::T) = x
40+
convert{T1,T2,f}(::Type{Normed{T1,f}}, x::Normed{T2,f}) = Normed{T1,f}(convert(T1, x.i), 0)
41+
function convert{T,T2,f}(::Type{Normed{T,f}}, x::Normed{T2})
42+
U = Normed{T,f}
43+
y = round((rawone(U)/rawone(x))*reinterpret(x))
44+
(0 <= y) & (y <= typemax(T)) || throw_converterror(U, x)
45+
reinterpret(U, _unsafe_trunc(T, y))
46+
end
47+
convert(::Type{N0f16}, x::N0f8) = reinterpret(N0f16, convert(UInt16, 0x0101*reinterpret(x)))
48+
convert{U<:Normed}(::Type{U}, x::Real) = _convert(U, rawtype(U), x)
49+
function _convert{U<:Normed,T}(::Type{U}, ::Type{T}, x)
50+
y = round(widen1(rawone(U))*x)
51+
(0 <= y) & (y <= typemax(T)) || throw_converterror(U, x)
52+
U(_unsafe_trunc(T, y), 0)
53+
end
54+
function _convert{U<:Normed}(::Type{U}, ::Type{UInt128}, x)
55+
y = round(rawone(U)*x) # for UInt128, we can't widen
56+
(0 <= y) & (y <= typemax(UInt128)) & (x <= Float64(typemax(U))) || throw_converterror(U, x)
57+
U(_unsafe_trunc(UInt128, y), 0)
58+
end
59+
60+
rem{T<:Normed}(x::T, ::Type{T}) = x
61+
rem{T<:Normed}(x::Normed, ::Type{T}) = reinterpret(T, _unsafe_trunc(rawtype(T), round((rawone(T)/rawone(x))*reinterpret(x))))
62+
rem{T<:Normed}(x::Real, ::Type{T}) = reinterpret(T, _unsafe_trunc(rawtype(T), round(rawone(T)*x)))
63+
64+
# convert(::Type{AbstractFloat}, x::Normed) = convert(floattype(x), x)
65+
float(x::Normed) = convert(floattype(x), x)
66+
67+
convert(::Type{BigFloat}, x::Normed) = reinterpret(x)*(1/BigFloat(rawone(x)))
68+
function convert{T<:AbstractFloat}(::Type{T}, x::Normed)
69+
y = reinterpret(x)*(one(rawtype(x))/convert(T, rawone(x)))
70+
convert(T, y) # needed for types like Float16 which promote arithmetic to Float32
71+
end
72+
convert(::Type{Bool}, x::Normed) = x == zero(x) ? false : true
73+
convert{T<:Integer}(::Type{T}, x::Normed) = convert(T, x*(1/one(T)))
74+
convert{Ti<:Integer}(::Type{Rational{Ti}}, x::Normed) = convert(Ti, reinterpret(x))//convert(Ti, rawone(x))
75+
convert(::Type{Rational}, x::Normed) = reinterpret(x)//rawone(x)
76+
77+
# Traits
78+
abs(x::Normed) = x
79+
80+
(-){T<:Normed}(x::T) = T(-reinterpret(x), 0)
81+
(~){T<:Normed}(x::T) = T(~reinterpret(x), 0)
82+
83+
+{T,f}(x::Normed{T,f}, y::Normed{T,f}) = Normed{T,f}(convert(T, x.i+y.i),0)
84+
-{T,f}(x::Normed{T,f}, y::Normed{T,f}) = Normed{T,f}(convert(T, x.i-y.i),0)
85+
*{T<:Normed}(x::T, y::T) = convert(T,convert(floattype(T), x)*convert(floattype(T), y))
86+
/{T<:Normed}(x::T, y::T) = convert(T,convert(floattype(T), x)/convert(floattype(T), y))
87+
88+
# Comparisons
89+
<{T<:Normed}(x::T, y::T) = reinterpret(x) < reinterpret(y)
90+
<={T<:Normed}(x::T, y::T) = reinterpret(x) <= reinterpret(y)
91+
92+
# Functions
93+
trunc{T<:Normed}(x::T) = T(div(reinterpret(x), rawone(T))*rawone(T),0)
94+
floor{T<:Normed}(x::T) = trunc(x)
95+
function round{T,f}(x::Normed{T,f})
96+
mask = convert(T, 1<<(f-1))
97+
y = trunc(x)
98+
return convert(T, reinterpret(x)-reinterpret(y)) & mask>0 ?
99+
Normed{T,f}(y+one(Normed{T,f})) : y
100+
end
101+
function ceil{T,f}(x::Normed{T,f})
102+
k = 8*sizeof(T)-f
103+
mask = (typemax(T)<<k)>>k
104+
y = trunc(x)
105+
return convert(T, reinterpret(x)-reinterpret(y)) & (mask)>0 ?
106+
Normed{T,f}(y+one(Normed{T,f})) : y
107+
end
108+
109+
trunc{T<:Integer}(::Type{T}, x::Normed) = convert(T, div(reinterpret(x), rawone(x)))
110+
round{T<:Integer}(::Type{T}, x::Normed) = round(T, reinterpret(x)/rawone(x))
111+
floor{T<:Integer}(::Type{T}, x::Normed) = trunc(T, x)
112+
ceil{T<:Integer}(::Type{T}, x::Normed) = ceil(T, reinterpret(x)/rawone(x))
113+
114+
isfinite(x::Normed) = true
115+
isnan(x::Normed) = false
116+
isinf(x::Normed) = false
117+
118+
bswap{f}(x::Normed{UInt8,f}) = x
119+
bswap(x::Normed) = typeof(x)(bswap(reinterpret(x)),0)
120+
121+
function minmax{T<:Normed}(x::T, y::T)
122+
a, b = minmax(reinterpret(x), reinterpret(y))
123+
T(a,0), T(b,0)
124+
end
125+
126+
# Iteration
127+
# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around
128+
# unless we iterate using a wider type
129+
@inline start{T<:Normed}(r::StepRange{T}) = widen1(reinterpret(r.start))
130+
@inline next{T<:Normed}(r::StepRange{T}, i::Integer) = (T(i,0), i+reinterpret(r.step))
131+
@inline function done{T<:Normed}(r::StepRange{T}, i::Integer)
132+
i1, i2 = reinterpret(r.start), reinterpret(r.stop)
133+
isempty(r) | (i < min(i1, i2)) | (i > max(i1, i2))
134+
end
135+
136+
function decompose(x::Normed)
137+
g = gcd(reinterpret(x), rawone(x))
138+
div(reinterpret(x),g), 0, div(rawone(x),g)
139+
end
140+
141+
# Promotions
142+
promote_rule{T<:Normed,Tf<:AbstractFloat}(::Type{T}, ::Type{Tf}) = promote_type(floattype(T), Tf)
143+
promote_rule{T<:Normed, R<:Rational}(::Type{T}, ::Type{R}) = R
144+
function promote_rule{T<:Normed, Ti<:Union{Signed,Unsigned}}(::Type{T}, ::Type{Ti})
145+
floattype(T)
146+
end
147+
@generated function promote_rule{T1,T2,f1,f2}(::Type{Normed{T1,f1}}, ::Type{Normed{T2,f2}})
148+
f = max(f1, f2) # ensure we have enough precision
149+
T = promote_type(T1, T2)
150+
# make sure we have enough integer bits
151+
i1, i2 = 8*sizeof(T1)-f1, 8*sizeof(T2)-f2 # number of integer bits for each
152+
i = 8*sizeof(T)-f
153+
while i < max(i1, i2)
154+
T = widen1(T)
155+
i = 8*sizeof(T)-f
156+
end
157+
:(Normed{$T,$f})
158+
end
159+
160+
_unsafe_trunc{T}(::Type{T}, x::Integer) = x % T
161+
_unsafe_trunc{T}(::Type{T}, x) = unsafe_trunc(T, x)

0 commit comments

Comments
 (0)