|
| 1 | +# UfixedBase{T,f} maps Uints from 0 to 2^f-1 to the range [0.0, 1.0] |
| 2 | +# For example, a Ufixed8 maps 0x00 to 0.0 and 0xff to 1.0 |
| 3 | + |
| 4 | +immutable UfixedBase{T<:Unsigned,f} <: Ufixed |
| 5 | + i::T |
| 6 | + |
| 7 | + UfixedBase(i::Integer,_) = new(i) # for setting by raw representation |
| 8 | + UfixedBase(x) = convert(UfixedBase{T,f}, x) |
| 9 | +end |
| 10 | + |
| 11 | +typealias Ufixed8 UfixedBase{Uint8,8} |
| 12 | +typealias Ufixed10 UfixedBase{Uint16,10} |
| 13 | +typealias Ufixed12 UfixedBase{Uint16,12} |
| 14 | +typealias Ufixed14 UfixedBase{Uint16,14} |
| 15 | +typealias Ufixed16 UfixedBase{Uint16,16} |
| 16 | + |
| 17 | +const UF = (Ufixed8, Ufixed10, Ufixed12, Ufixed14, Ufixed16) |
| 18 | + |
| 19 | + rawtype{T,f}(::Type{UfixedBase{T,f}}) = T |
| 20 | +nbitsfrac{T,f}(::Type{UfixedBase{T,f}}) = f |
| 21 | + |
| 22 | +# The next lines mimic the floating-point literal syntax "3.2f0" |
| 23 | +immutable UfixedConstructor{T,f} end |
| 24 | +*{T,f}(n::Integer, ::UfixedConstructor{T,f}) = UfixedBase{T,f}(n,0) |
| 25 | +const uf8 = UfixedConstructor{Uint8,8}() |
| 26 | +const uf10 = UfixedConstructor{Uint16,10}() |
| 27 | +const uf12 = UfixedConstructor{Uint16,12}() |
| 28 | +const uf14 = UfixedConstructor{Uint16,14}() |
| 29 | +const uf16 = UfixedConstructor{Uint16,16}() |
| 30 | + |
| 31 | +zero{T,f}(::Type{UfixedBase{T,f}}) = UfixedBase{T,f}(zero(T),0) |
| 32 | +for T in UF |
| 33 | + f = nbitsfrac(T) |
| 34 | + @eval begin |
| 35 | + one(::Type{$T}) = UfixedBase{$(rawtype(T)),$f}($(2^f-1),0) |
| 36 | + end |
| 37 | +end |
| 38 | +zero(x::Ufixed) = zero(typeof(x)) |
| 39 | + one(x::Ufixed) = one(typeof(x)) |
| 40 | +rawone(v) = reinterpret(one(v)) |
| 41 | + |
| 42 | +# Conversions |
| 43 | +convert{T<:Ufixed}(::Type{T}, x::Real) = T(iround(rawtype(T), rawone(T)*x),0) |
| 44 | + |
| 45 | +convert(::Type{BigFloat}, x::Ufixed) = reinterpret(x)*(1/BigFloat(rawone(x))) |
| 46 | +convert{T<:FloatingPoint}(::Type{T}, x::Ufixed) = reinterpret(x)*(1/convert(T, rawone(x))) |
| 47 | +convert(::Type{Bool}, x::Ufixed) = x == zero(x) ? false : true |
| 48 | +convert{T<:Integer}(::Type{T}, x::Ufixed) = convert(T, x*(1/one(T))) |
| 49 | +convert{Ti<:Integer}(::Type{Rational{Ti}}, x::Ufixed) = convert(Ti, reinterpret(x))//convert(Ti, rawone(x)) |
| 50 | +convert(::Type{Rational}, x::Ufixed) = reinterpret(x)//rawone(x) |
| 51 | + |
| 52 | +# Traits |
| 53 | +typemin{T<:Ufixed}(::Type{T}) = zero(T) |
| 54 | +typemax{T<:Ufixed}(::Type{T}) = T(typemax(rawtype(T)),0) |
| 55 | +realmin{T<:Ufixed}(::Type{T}) = typemin(T) |
| 56 | +realmax{T<:Ufixed}(::Type{T}) = typemax(T) |
| 57 | +eps{T<:Ufixed}(::Type{T}) = T(one(rawtype(T)),0) |
| 58 | +eps{T<:Ufixed}(::T) = eps(T) |
| 59 | +sizeof{T<:Ufixed}(::Type{T}) = sizeof(rawtype(T)) |
| 60 | + |
| 61 | +# Arithmetic |
| 62 | +# Ufixed types are closed under addition and subtraction |
| 63 | ++{T,f}(x::UfixedBase{T,f}, y::UfixedBase{T,f}) = UfixedBase{T,f}(convert(T, reinterpret(x)+reinterpret(y)),0) |
| 64 | +-{T,f}(x::UfixedBase{T,f}, y::UfixedBase{T,f}) = UfixedBase{T,f}(convert(T, reinterpret(x)-reinterpret(y)),0) |
| 65 | +*{T,f}(x::UfixedBase{T,f}, y::UfixedBase{T,f}) = float32(x)*float32(y) |
| 66 | +/(x::Ufixed, y::Ufixed) = float32(x)/float32(y) |
| 67 | + |
| 68 | +# Comparisons |
| 69 | +< {T<:Ufixed}(x::T, y::T) = reinterpret(x) < reinterpret(y) |
| 70 | +<={T<:Ufixed}(x::T, y::T) = reinterpret(x) < reinterpret(y) |
| 71 | + |
| 72 | +# Functions |
| 73 | +trunc{T<:Ufixed}(x::T) = T(div(reinterpret(x), rawone(T))*rawone(T),0) |
| 74 | +floor{T<:Ufixed}(x::T) = trunc(x) |
| 75 | +for T in UF |
| 76 | + f = nbitsfrac(T) |
| 77 | + R = rawtype(T) |
| 78 | + roundmask = convert(R, 1<<(f-1)) |
| 79 | + k = 8*sizeof(R)-f |
| 80 | + ceilmask = (typemax(R)<<k)>>k |
| 81 | + @eval begin |
| 82 | + round(x::$T) = (y = trunc(x); return reinterpret(x-y)&$roundmask>0 ? y+one($T) : y) |
| 83 | + ceil(x::$T) = (y = trunc(x); return reinterpret(x-y)&$ceilmask >0 ? y+one($T) : y) |
| 84 | + end |
| 85 | +end |
| 86 | + |
| 87 | +itrunc{T<:Integer}(::Type{T}, x::Ufixed) = convert(T, div(reinterpret(x), rawone(x))) |
| 88 | +iround{T<:Integer}(::Type{T}, x::Ufixed) = iround(T, reinterpret(x)/rawone(x)) |
| 89 | +ifloor{T<:Integer}(::Type{T}, x::Ufixed) = itrunc(T, x) |
| 90 | + iceil{T<:Integer}(::Type{T}, x::Ufixed) = iceil(T, reinterpret(x)/rawone(x)) |
| 91 | +itrunc(x::Ufixed) = itrunc(Int, x) |
| 92 | +iround(x::Ufixed) = iround(Int, x) |
| 93 | +ifloor(x::Ufixed) = ifloor(Int, x) |
| 94 | + iceil(x::Ufixed) = iceil(Int, x) |
| 95 | + |
| 96 | +bswap{f}(x::UfixedBase{Uint8,f}) = x |
| 97 | +bswap(x::Ufixed) = typeof(x)(bswap(reinterpret(x)),0) |
| 98 | + |
| 99 | +for f in (:div, :fld, :rem, :mod, :mod1, :rem1, :fld1, :min, :max) |
| 100 | + @eval begin |
| 101 | + $f{T<:Ufixed}(x::T, y::T) = T($f(reinterpret(x),reinterpret(y)),0) |
| 102 | + end |
| 103 | +end |
| 104 | +function minmax{T<:Ufixed}(x::T, y::T) |
| 105 | + a, b = minmax(reinterpret(x), reinterpret(y)) |
| 106 | + T(a,0), T(b,0) |
| 107 | +end |
| 108 | + |
| 109 | +# Iteration |
| 110 | +# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around |
| 111 | +# unless we iterate using a wider type |
| 112 | +if VERSION < v"0.3-" |
| 113 | + start{T<:Ufixed}(r::Range{T}) = convert(typeof(reinterpret(r.start)+reinterpret(r.step)), reinterpret(r.start)) |
| 114 | + next{T<:Ufixed}(r::Range{T}, i::Integer) = (T(i,0), i+reinterpret(r.step)) |
| 115 | + done{T<:Ufixed}(r::Range{T}, i::Integer) = isempty(r) || (i > r.len) |
| 116 | +else |
| 117 | + start{T<:Ufixed}(r::StepRange{T}) = convert(typeof(reinterpret(r.start)+reinterpret(r.step)), reinterpret(r.start)) |
| 118 | + next{T<:Ufixed}(r::StepRange{T}, i::Integer) = (T(i,0), i+reinterpret(r.step)) |
| 119 | + done{T<:Ufixed}(r::StepRange{T}, i::Integer) = isempty(r) || (i > reinterpret(r.stop)) |
| 120 | +end |
| 121 | + |
| 122 | +# Promotions |
| 123 | +for T in UF |
| 124 | + @eval begin |
| 125 | + promote_rule(::Type{$T}, ::Type{Float32}) = Float32 |
| 126 | + promote_rule(::Type{$T}, ::Type{Float64}) = Float64 |
| 127 | + promote_rule{TR<:Rational}(::Type{$T}, ::Type{TR}) = TR |
| 128 | + end |
| 129 | + for Ti in (Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64) |
| 130 | + Tp = eps(float32(typemax(Ti))) > eps(T) ? Float64 : Float32 |
| 131 | + @eval begin |
| 132 | + promote_rule(::Type{$T}, ::Type{$Ti}) = $Tp |
| 133 | + end |
| 134 | + end |
| 135 | +end |
| 136 | + |
| 137 | +# Show |
| 138 | +function show(io::IO, x::Ufixed) |
| 139 | + print(io, "Ufixed", nbitsfrac(typeof(x))) |
| 140 | + print(io, "(") |
| 141 | + showcompact(io, x) |
| 142 | + print(io, ")") |
| 143 | +end |
| 144 | +showcompact(io::IO, x::Ufixed) = show(io, round(convert(Float64,x), iceil(nbitsfrac(typeof(x))/_log2_10))) |
0 commit comments