Skip to content

Instantly share code, notes, and snippets.

@philtomson
Last active August 29, 2015 14:09
Show Gist options
  • Save philtomson/5f7dbb1bc2b51f505750 to your computer and use it in GitHub Desktop.
Save philtomson/5f7dbb1bc2b51f505750 to your computer and use it in GitHub Desktop.
start of a fixed point package
# 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