Last active
August 29, 2015 14:09
-
-
Save philtomson/5f7dbb1bc2b51f505750 to your computer and use it in GitHub Desktop.
start of a fixed point package
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 32-bit fixed point; parameter `f` is the number of fraction bits | |
function create_mask(wp,fp) | |
(2^wp-1)<<fp + (2^fp-1) | |
end | |
abstract FixedPoint <: Real | |
abstract Fixed <: FixedPoint | |
#abstract Ufixed <: FixedPoint # unsigned variant | |
immutable FixedPt{wp,fp} <: Fixed | |
i::Int64 | |
# constructor for manipulating the representation; | |
# selected by passing an extra dummy argument | |
function FixedPt(i::Integer,_) | |
if wp+fp > (sizeof(typeof(i))*8) | |
error("$wp+$fp exceeds maximum number of bits (64)" ) | |
end | |
new(i&create_mask(wp,fp)) | |
end | |
FixedPt(x) = convert(FixedPt{wp,fp}, x) | |
end | |
FixedPt(x::Real) = convert(FixedPt{32}, x) | |
rawtype(::Type{FixedPt}) = Int64 | |
rawtype{wp,fp}(::Type{FixedPt{wp,fp}}) = Int64 | |
nbitsfrac{wp,fp}(::Type{FixedPt{wp,fp}}) = fp | |
# comparisons | |
# =={wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = x.i == y.i | |
#= | |
=={wp1,fp1,wp2,fp2}(x::FixedPt{wp1,fp1},y::FixedPt{wp2,fp2}) = | |
if (wp1 > wp2) && (fp1 > fp2) #move to FixedPt{wp1,fp1} | |
x.i&create_mask(wp2,fp2) == (y.i << (fp1 - fp2)) | |
elseif (wp1 < wp2) && (fp1 > fp2) | |
x.i&create_mask(wp1,fp2) == (y.i << (fp1-fp2))&create_mask(wp1,fp2) | |
elseif((wp1 > wp2) && (fp1 < fp2)) #move to FixedPt{wp1,fp2} | |
(x.i << (fp2-fp1)) == (y.i)&create_mask(wp2,fp1) | |
elseif((wp1 < wp2) && (fp1 < fp2)) #move to FixedPt{wp2,fp2} | |
((x.i) << (fp2-fp1)) == y.i&create_mask(wp1,fp1) | |
else #must be equal | |
x.i == y.i | |
end | |
=# | |
#= | |
for op = (:*, :/, :+, :-) | |
println("$op") | |
@eval begin | |
($op){wp1,fp1,wp2,fp2}(x::FixedPt{wp1,fp1},y::FixedPt{wp2,fp2}) = | |
if (wp1 > wp2) && (fp1 > fp2) #move to FixedPt{wp1,fp1} | |
FixedPt{wp1,fp1}( $op(x.i , (y.i << (fp1 - fp2)) ),0) | |
elseif (wp1 < wp2) && (fp1 > fp2) | |
FixedPt{wp2,fp1}($op(x.i , (y.i << (fp1-fp2))) ) | |
elseif((wp1 > wp2) && (fp1 < fp2)) #move to FixedPt{wp1,fp2} | |
FixedPt{wp1,fp2}(($op)((x.i << (fp2-fp1)) ,(y.i))) | |
elseif((wp1 < wp2) && (fp1 < fp2)) #move to FixedPt{wp2,fp2} | |
FixedPt{wp2,fp2}(($op)(((x.i) << (fp2-fp1)) ,(y.i))) | |
else #must be equal | |
#(x.i) $op (y.i) | |
FixedPt{wp1,fp1}(($op)(x.i,y.i),0) | |
end | |
end | |
end | |
=# | |
for op = ( symbol("=="), :<, :<=, :>, :>= ) | |
println("$op") | |
@eval begin | |
($op){wp1,fp1,wp2,fp2}(x::FixedPt{wp1,fp1},y::FixedPt{wp2,fp2}) = | |
if (wp1 > wp2) && (fp1 > fp2) #move to FixedPt{wp1,fp1} | |
#x.i $op (y.i << (fp1 - fp2)) | |
($op)(x.i , (y.i << (fp1 - fp2)) ) | |
elseif (wp1 < wp2) && (fp1 > fp2) | |
($op)(x.i , (y.i << (fp1-fp2))) | |
#x.i $op (y.i << (fp1-fp2)) | |
elseif((wp1 > wp2) && (fp1 < fp2)) #move to FixedPt{wp1,fp2} | |
#(x.i << (fp2-fp1)) $op (y.i) | |
($op)((x.i << (fp2-fp1)) ,(y.i)) | |
elseif((wp1 < wp2) && (fp1 < fp2)) #move to FixedPt{wp2,fp2} | |
#((x.i) << (fp2-fp1)) $op (y.i) | |
($op)(((x.i) << (fp2-fp1)) ,(y.i)) | |
else #must be equal | |
#(x.i) $op (y.i) | |
($op)(x.i,y.i) | |
end | |
end | |
end | |
#< {wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = x.i < y.i | |
#<={wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = x.i <= y.i | |
# predicates | |
isinteger{wp,fp}(x::FixedPt{wp,fp}) = (x.i&(1<<fp-1)) == 0 | |
# basic operators | |
-{wp,fp}(x::FixedPt{wp,fp}) = FixedPt{wp,fp}(-x.i,0) | |
abs{wp,fp}(x::FixedPt{wp,fp}) = FixedPt{wp,fp}(abs(x.i),0) | |
+{wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = FixedPt{wp,fp}((x.i+y.i)&create_mask(wp,fp),0) | |
-{wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = FixedPt{wp,fp}((x.i-y.i)&create_mask(wp,fp),0) | |
# with truncation: | |
#*{wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = FixedPt{wp,fp}(Base.widemul(x.i,y.i)>>fp,0) | |
# with rounding up: | |
*{wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = FixedPt{wp,fp}(((Base.widemul(x.i,y.i)+(int64(1)<<(fp-1)))>>fp)&create_mask(wp,fp),0) | |
#*{wp1,fp1,wp2,fp2}(x::FixedPt{wp1,fp1},y::FixedPt{wp2,fp2}) = | |
/{wp,fp}(x::FixedPt{wp,fp}, y::FixedPt{wp,fp}) = FixedPt{wp,fp}((div(int64(x.i)<<fp)&create_mask(wp,fp), y.i),0) | |
# conversions and promotions | |
convert{wp,fp}(::Type{FixedPt{wp,fp}},x::Integer) = FixedPt{wp,fp}((x<<fp)&create_mask(wp,fp),0) | |
convert{wp,fp}(::Type{FixedPt{wp,fp}}, x::FloatingPoint) = FixedPt{wp,fp}((itrunc(x)<<fp + int32(rem(x,1)*(1<<fp)))&create_mask(wp,fp),0) | |
convert{wp,fp}(::Type{FixedPt{wp,fp}}, x::Rational) = FixedPt{wp,fp}(x.num)/FixedPt{wp,fp}(x.den) | |
convert{wp,fp}(::Type{BigFloat}, x::FixedPt{wp,fp}) = | |
convert(BigFloat,x.i>>fp) + convert(BigFloat,x.i&(1<<fp - 1))/convert(BigFloat,1<<fp) | |
#convert{T<:FloatingPoint, wp,fp}(::Type{T}, x::FixedPt{wp,fp}) = | |
# convert(T,x.i>>fp) + convert(T,x.i&(1<<fp - 1))/convert(T,1<<fp) | |
function convert{T<:FloatingPoint,wp,fp}(::Type{T}, x::FixedPt{wp,fp}) | |
typex = typeof(x) | |
typet = Type{T} | |
println("Convert $typex to $typet") | |
(x.i>>fp)+(x.i&(1<<fp-1))/(1<<fp) | |
end | |
to_f{wp,fp}(x::FixedPt{wp,fp}) = (x.i>>fp)+(x.i&(1<<fp-1))/(1<<fp) | |
convert(::Type{Bool}, x::FixedPt) = x.i!=0 | |
function convert{T<:Integer, wp,fp}(::Type{T}, x::FixedPt{wp,fp}) | |
isinteger(x) || throw(InexactError()) | |
x.i>>fp | |
end | |
convert{T<:Rational, wp,fp}(::Type{T}, x::FixedPt{wp,fp}) = | |
convert(T, x.i>>fp + (x.i&(1<<fp-1))//(1<<fp)) | |
promote_rule{wp,fp,T<:Integer}(ft::Type{FixedPt{wp,fp}}, ::Type{T}) = fp | |
promote_rule{wp,fp,T<:FloatingPoint}(::Type{FixedPt{wp,fp}}, ::Type{T}) = T | |
#Not sure if this is correct: | |
promote_rule{wp1,fp1,wp2,fp2}(x::FixedPt{wp1,fp1},y::FixedPt{wp2,fp2}) = | |
if wp1 >= wp2 && fp1 >= fp2 | |
FixedPt{wp1,wp2} | |
elseif wp1 >= wp2 && fp1 <= fp2 | |
FixedPt{wp1,fp2} | |
elseif wp1 <= wp2 && fp1 >= fp2 | |
FixedPt{wp2,fp1} | |
elseif wp1 <= wp2 && fp1 <= fp2 | |
FixedPt{wp2,fp2} | |
else | |
FixedPt{wp1,wp2} | |
end | |
# printing | |
function show(io::IO, x::FixedPt) | |
print(io, typeof(x)) | |
end | |
fp = FixedPt{4,4}(8.25) | |
fp1 = FixedPt{6,7}(8.25) | |
println("bin(fp.i):") | |
println(bin(fp.i)) | |
fp2 = FixedPt{15,14}(245.789) | |
if fp == fp1 | |
println("equal") | |
else | |
println("nope") | |
end | |
if fp < fp2 | |
println("less") | |
else | |
println("not less") | |
end | |
floatval = convert(Float32,fp) | |
println("$floatval") | |
println(typeof(floatval)) | |
fp4 = fp1 + fp | |
println(to_f(fp4)) | |
fp5 = fp1 / fp2 | |
println(to_f(fp5)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment