diff --git a/src/FixedPointNumbers.jl b/src/FixedPointNumbers.jl index 8c19a2e2..f75c82ac 100644 --- a/src/FixedPointNumbers.jl +++ b/src/FixedPointNumbers.jl @@ -1,4 +1,4 @@ -VERSION >= v"0.4.0-dev+6521" && __precompile__() +# ERSION >= v"0.4.0-dev+6521" && __precompile__() module FixedPointNumbers @@ -9,13 +9,10 @@ using Base: IdFun, AddFun, MulFun, reducedim_initarray import Base: ==, <, <=, -, +, *, /, ~, convert, promote_rule, show, showcompact, isinteger, abs, decompose, isnan, isinf, isfinite, - zero, one, typemin, typemax, realmin, realmax, eps, sizeof, reinterpret, + zero, one, typemin, typemax, realmin, realmax, eps, sizeof, reinterpret, getindex, trunc, round, floor, ceil, bswap, div, fld, rem, mod, mod1, rem1, fld1, min, max, start, next, done, r_promote, reducedim_init -# T => BaseType -# f => Number of Bytes reserved for fractional part -abstract FixedPoint{T <: Integer, f} <: Real export FixedPoint, @@ -33,6 +30,7 @@ export ufixed12, ufixed14, ufixed16, + fixed16, # literal constructor constants uf8, uf10, @@ -42,25 +40,213 @@ export # Functions scaledual -reinterpret(x::FixedPoint) = x.i +# T => BaseType +# f => Number of Bytes reserved for fractional part +immutable FixedPoint{T <: Integer, f} <: Real + i::T + + # constructor for manipulating the representation; + # selected by passing an extra dummy argument + FixedPoint(i::T, _) = new(i) + FixedPoint(i::Integer,_) = new(i % T) + + FixedPoint(x) = convert(FixedPoint{T,f}, x) +end -# comparison -=={T <: FixedPoint}(x::T, y::T) = x.i == y.i - <{T <: FixedPoint}(x::T, y::T) = x.i < y.i -<={T <: FixedPoint}(x::T, y::T) = x.i <= y.i +# basic typealiases for signed and unsigned +typealias Fixed{T <: Signed, f} FixedPoint{T, f} +typealias UFixed{T <: Unsigned, f} FixedPoint{T, f} + +# default provided typealiases +typealias Fixed16 Fixed{Int32, 16} +typealias UFixed8 UFixed{UInt8,8} +typealias UFixed10 UFixed{UInt16,10} +typealias UFixed12 UFixed{UInt16,12} +typealias UFixed14 UFixed{UInt16,14} +typealias UFixed16 UFixed{UInt16,16} + +getindex(x::FixedPoint) = x.i +reinterpret{T,f}(::Type{T}, x::FixedPoint{T,f}) = x[] +reinterpret{T <: Integer,f}(::Type{FixedPoint{T,f}}, x::T) = FixedPoint{T,f}(x, 0) + +rawtype{T,f}(::Type{FixedPoint{T,f}}) = T +nbitsfrac{T,f}(::Type{FixedPoint{T,f}}) = f +rawone(v) = one(v)[] + +# comparisons +=={T <: FixedPoint}(x::T, y::T) = x[] == y[] + <{T <: FixedPoint}(x::T, y::T) = x[] < y[] +<={T <: FixedPoint}(x::T, y::T) = x[] <= y[] # predicates -isinteger{T,f}(x::FixedPoint{T,f}) = (x.i&(1< f + return FixedPoint{T, f}(2^f-1,0) + else + throw(DomainError()) + end +end + +# basic operators & arithmetics +(-){T<:FixedPoint}(x::T) = T(-x[], 0) +(~){T<:FixedPoint}(x::T) = T(~x[], 0) +abs{T<:FixedPoint}(x::T) = T(abs(x[]),0) + ++{T<:FixedPoint}(x::T, y::T) = T(x[] + y[],0) +-{T<:FixedPoint}(x::T, y::T) = T(x[] - y[],0) + +# with truncation: +# *{T<:FixedPoint}(x::T, y::T) = +# T(Base.widemul(x[],y[]) >> nbitsfrac(T),0) +# with rounding up: +function *{T<:FixedPoint}(x::T, y::T) + f = nbitsfrac(T) + i = Base.widemul(x[],y[]) + T((i + convert(widen(rawtype(T)), 1) << (f-1) )>>f,0) +end + +function /{T<:FixedPoint}(x::T, y::T) + f = nbitsfrac(T) + T(div(convert(widen(rawtype(T)), x[]) << f, y.i), 0) +end + +# Conversions to FixedPoint +convert{T,f}(::Type{FixedPoint{T,f}}, x::Integer) = + FixedPoint{T,f}(convert(T,x)<>f) + convert(BigFloat,x[]&(1<>f) + convert(TF,x[]&(1<>f) +end +convert{TR<:Rational,T <: Signed,f}(::Type{TR}, x::FixedPoint{T,f}) = + convert(TR, x[] >> f + (x[] & (1 << f - 1)) // (1 << f)) +convert{Ti<:Integer}(::Type{Rational{Ti}}, x::UFixed) = convert(Ti, x[])//convert(Ti, rawone(x)) +convert(::Type{Rational}, x::UFixed) = x[]//rawone(x) + +# Special conversions for constructors +convert{T<:FixedPoint}(::Type{T}, x::T) = x +convert{T1<:FixedPoint}(::Type{T1}, x::FixedPoint) = reinterpret(T1, round(rawtype(T1), (rawone(T1)/rawone(x))*x[])) +convert(::Type{UFixed16}, x::UFixed8) = reinterpret(UFixed16, convert(UInt16, 0x0101*x[])) +convert{T<:FixedPoint}(::Type{T}, x::Real) = T(round(rawtype(T), rawone(T)*x),0) + +# Constructors +ufixed8(x) = convert(UFixed8, x) +ufixed10(x) = convert(UFixed10, x) +ufixed12(x) = convert(UFixed12, x) +ufixed14(x) = convert(UFixed14, x) +ufixed16(x) = convert(UFixed16, x) +fixed16(x) = convert(Fixed16, x) + +@vectorize_1arg Real ufixed8 +@vectorize_1arg Real ufixed10 +@vectorize_1arg Real ufixed12 +@vectorize_1arg Real ufixed14 +@vectorize_1arg Real ufixed16 +@vectorize_1arg Real fixed16 + +# Promote rules +promote_rule{T <: FixedPoint,TI<:Integer}(::Type{T}, ::Type{TI}) = T +promote_rule{T <: FixedPoint,TF<:AbstractFloat}(::Type{T}, ::Type{TF}) = TF +promote_rule{T <: FixedPoint,TR <: Rational}(::Type{T}, ::Type{TR}) = TR + +# for T in UF +# for Ti in (Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64) +# Tp = eps(convert(Float32, typemax(Ti))) > eps(T) ? Float64 : Float32 +# @eval begin +# promote_rule(::Type{$T}, ::Type{$Ti}) = $Tp +# end +# end +# end + +# Math functions +# Round towards negative infinity +trunc{T<:FixedPoint}(x::T) = T(x[] & ~(1 << nbitsfrac(T) - 1), 0) +# Round towards negative infinity +floor{T<:FixedPoint}(x::T) = trunc(x) +# Round towards positive infinity +ceil{T<:FixedPoint}(x::T) = trunc(T(x[] + 1 << (nbitsfrac(T)-1), 0)) +# Round towards even +function round{T<:FixedPoint}(x::T) + even = x[] & (1 << nbitsfrac(T)) == 0 + if even + return floor(x) + else + return ceil(x) + end +end + +trunc{TI<:Integer, T <: FixedPoint}(::Type{TI}, x::T) = + convert(TI, x[] >> nbitsfrac(T)) +floor{T<:Integer}(::Type{T}, x::FixedPoint) = trunc(T, x) +ceil{T<:Integer}(::Type{T}, x::FixedPoint) = trunc(T, ceil(x)) +round{T<:Integer}(::Type{T}, x::FixedPoint) = trunc(T, round(x)) + +# for T in UF +# f = nbitsfrac(T) +# R = rawtype(T) +# roundmask = convert(R, 1<<(f-1)) +# k = 8*sizeof(R)-f +# ceilmask = (typemax(R)<>k +# @eval begin +# round(x::$T) = (y = trunc(x); return convert(rawtype($T), x[]-y[])&$roundmask>0 ? $T(y+one($T)) : y) +# ceil(x::$T) = (y = trunc(x); return convert(rawtype($T), x[]-y[])&$ceilmask >0 ? $T(y+one($T)) : y) +# end +# end + +for f in (:div, :fld, :rem, :mod, :mod1, :rem1, :fld1, :min, :max) + @eval begin + $f{T<:FixedPoint}(x::T, y::T) = T($f(x[],y[]),0) + end +end + +function minmax{T<:UFixed}(x::T, y::T) + a, b = minmax(x[], y[]) + T(a,0), T(b,0) +end + +# Special function +decompose{T,f}(x::FixedPoint{T,f}) = x[], -f, 1 +# function decompose(x::UFixed) +# g = gcd(x[], rawone(x)) +# div(x[],g), 0, div(rawone(x),g) +# end + +bswap{T <: Union{UInt8, Int8}, f}(x::FixedPoint{T,f}) = x +bswap{T <: FixedPoint}(x::T) = T(bswap(x[]),0) # Promotions for reductions const Treduce = Float64 @@ -75,14 +261,6 @@ reducedim_init{T<:FixedPoint}(f::IdFun, op::MulFun, A::AbstractArray{T}, region) = reducedim_initarray(A, region, one(Treduce)) -# TODO: rewrite this by @generated -for T in tuple(Fixed16, UF...) - R = rawtype(T) - @eval begin - reinterpret(::Type{$R}, x::$T) = x.i - end -end - # When multiplying by a float, reduce two multiplies to one. # Particularly useful for arrays. scaledual(Tdual::Type, x) = one(Tdual), x @@ -92,4 +270,32 @@ scaledual{Tdual<:Number}(b::Tdual, x) = b, x @compat scaledual{Tdual<:Number, T<:FixedPoint}(b::Tdual, x::Union{T,AbstractArray{T}}) = convert(Tdual, b/one(T)), reinterpret(rawtype(T), x) +# Show +function show(io::IO, x::FixedPoint) + print(io, typeof(x)) + print(io, "(") + showcompact(io, x) + print(io, ")") +end + +const _log2_10 = 3.321928094887362 +showcompact{T,f}(io::IO, x::FixedPoint{T,f}) = show(io, round(convert(Float64,x), ceil(Int,f/_log2_10))) + +# Iteration +# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around +# unless we iterate using a wider type +start{T<:FixedPoint}(r::StepRange{T}) = convert(typeof(r.start[] + r.step[]), r.start[]) +next{T<:FixedPoint}(r::StepRange{T}, i::Integer) = (T(i,0), i+r.step[]) +done{T<:FixedPoint}(r::StepRange{T}, i::Integer) = isempty(r) || (i > r.stop[]) + +immutable UFixedConstructor{T,f} end +*{T,f}(n::Integer, ::UFixedConstructor{T,f}) = UFixed{T,f}(n,0) +const uf8 = UFixedConstructor{UInt8,8}() +const uf10 = UFixedConstructor{UInt16,10}() +const uf12 = UFixedConstructor{UInt16,12}() +const uf14 = UFixedConstructor{UInt16,14}() +const uf16 = UFixedConstructor{UInt16,16}() + +include("deprecations.jl") + end # module diff --git a/src/deprecations.jl b/src/deprecations.jl index 3b348871..ab8c04c1 100644 --- a/src/deprecations.jl +++ b/src/deprecations.jl @@ -10,4 +10,5 @@ import Base.@deprecate_binding @deprecate_binding Ufixed16 UFixed16 @deprecate_binding Fixed32 Fixed16 -@deprecate Fixed(x::Real) convert(Fixed{Int32, 16}, x) + +@deprecate reinterpret(x::FixedPoint) getindex(x) diff --git a/src/fixed.jl b/src/fixed.jl deleted file mode 100644 index f76970c8..00000000 --- a/src/fixed.jl +++ /dev/null @@ -1,66 +0,0 @@ -# 32-bit fixed point; parameter `f` is the number of fraction bits -immutable Fixed{T <: Signed,f} <: FixedPoint{T, f} - i::T - - # constructor for manipulating the representation; - # selected by passing an extra dummy argument - Fixed(i::Integer,_) = new(i % T) - - Fixed(x) = convert(Fixed{T,f}, x) -end - -typealias Fixed16 Fixed{Int32, 16} - - rawtype{T,f}(::Type{Fixed{T,f}}) = T -nbitsfrac{T,f}(::Type{Fixed{T,f}}) = f - -# basic operators --{T,f}(x::Fixed{T,f}) = Fixed{T,f}(-x.i,0) -abs{T,f}(x::Fixed{T,f}) = Fixed{T,f}(abs(x.i),0) - -+{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(x.i+y.i,0) --{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(x.i-y.i,0) - -# with truncation: -#*{f}(x::Fixed32{f}, y::Fixed32{f}) = Fixed32{f}(Base.widemul(x.i,y.i)>>f,0) -# with rounding up: -*{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}((Base.widemul(x.i,y.i) + (convert(widen(T), 1) << (f-1) ))>>f,0) - -/{T,f}(x::Fixed{T,f}, y::Fixed{T,f}) = Fixed{T,f}(div(convert(widen(T), x.i) << f, y.i), 0) - - -# # conversions and promotions -convert{T,f}(::Type{Fixed{T,f}}, x::Integer) = Fixed{T,f}(convert(T,x)<>f) + convert(BigFloat,x.i&(1<>f) + convert(TF,x.i&(1<>f) -end - -convert{TR<:Rational,T,f}(::Type{TR}, x::Fixed{T,f}) = - convert(TR, x.i>>f + (x.i&(1<>f,0) -/{T,f}(x::UFixed{T,f}, y::UFixed{T,f}) = UFixed{T,f}(div(convert(widen(T), x.i)<>k - @eval begin - round(x::$T) = (y = trunc(x); return convert(rawtype($T), reinterpret(x)-reinterpret(y))&$roundmask>0 ? $T(y+one($T)) : y) - ceil(x::$T) = (y = trunc(x); return convert(rawtype($T), reinterpret(x)-reinterpret(y))&$ceilmask >0 ? $T(y+one($T)) : y) - end -end - -trunc{T<:Integer}(::Type{T}, x::UFixed) = convert(T, div(reinterpret(x), rawone(x))) -round{T<:Integer}(::Type{T}, x::UFixed) = round(T, reinterpret(x)/rawone(x)) -floor{T<:Integer}(::Type{T}, x::UFixed) = trunc(T, x) - ceil{T<:Integer}(::Type{T}, x::UFixed) = ceil(T, reinterpret(x)/rawone(x)) -trunc(x::UFixed) = trunc(Int, x) -round(x::UFixed) = round(Int, x) -floor(x::UFixed) = floor(Int, x) - ceil(x::UFixed) = ceil(Int, x) - -isfinite(x::UFixed) = true -isnan(x::UFixed) = false -isinf(x::UFixed) = false - -bswap{f}(x::UFixed{UInt8,f}) = x -bswap(x::UFixed) = typeof(x)(bswap(reinterpret(x)),0) - -for f in (:div, :fld, :rem, :mod, :mod1, :rem1, :fld1, :min, :max) - @eval begin - $f{T<:UFixed}(x::T, y::T) = T($f(reinterpret(x),reinterpret(y)),0) - end -end -function minmax{T<:UFixed}(x::T, y::T) - a, b = minmax(reinterpret(x), reinterpret(y)) - T(a,0), T(b,0) -end - -# Iteration -# The main subtlety here is that iterating over 0x00uf8:0xffuf8 will wrap around -# unless we iterate using a wider type -if VERSION < v"0.3-" - start{T<:UFixed}(r::Range{T}) = convert(typeof(reinterpret(r.start)+reinterpret(r.step)), reinterpret(r.start)) - next{T<:UFixed}(r::Range{T}, i::Integer) = (T(i,0), i+reinterpret(r.step)) - done{T<:UFixed}(r::Range{T}, i::Integer) = isempty(r) || (i > r.len) -else - start{T<:UFixed}(r::StepRange{T}) = convert(typeof(reinterpret(r.start)+reinterpret(r.step)), reinterpret(r.start)) - next{T<:UFixed}(r::StepRange{T}, i::Integer) = (T(i,0), i+reinterpret(r.step)) - done{T<:UFixed}(r::StepRange{T}, i::Integer) = isempty(r) || (i > reinterpret(r.stop)) -end - -function decompose(x::UFixed) - g = gcd(reinterpret(x), rawone(x)) - div(reinterpret(x),g), 0, div(rawone(x),g) -end - -# Promotions -for T in UF - @eval begin - promote_rule(::Type{$T}, ::Type{Float32}) = Float32 - promote_rule(::Type{$T}, ::Type{Float64}) = Float64 - promote_rule{TR<:Rational}(::Type{$T}, ::Type{TR}) = TR - end - for Ti in (Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64) - Tp = eps(convert(Float32, typemax(Ti))) > eps(T) ? Float64 : Float32 - @eval begin - promote_rule(::Type{$T}, ::Type{$Ti}) = $Tp - end - end -end - -# Show -function show{T,f}(io::IO, x::UFixed{T,f}) - print(io, "UFixed", f) - print(io, "(") - showcompact(io, x) - print(io, ")") -end -showcompact{T,f}(io::IO, x::UFixed{T,f}) = show(io, round(convert(Float64,x), ceil(Int,f/_log2_10)))