Copyright | (C) 2013-2015, University of Twente |
---|---|
License | BSD2 (see the file LICENSE) |
Maintainer | Christiaan Baaij <christiaan.baaij@gmail.com> |
Safe Haskell | None |
Language | Haskell2010 |
Extensions |
|
Fixed point numbers
- The
Num
operators for the given types saturate on overflow, and use truncation as the rounding method. Fixed
has an instance forFractional
meaning you use fractional literals(3.75 ::
.SFixed
4 18)- Both integer literals and fractional literals are clipped to
minBound
andmaxBound
. - There is no
Floating
instance forFixed
, but you can use$$(
to createfLit
d)Fixed
point literal fromDouble
constant at compile-time. - Use Constraint synonyms when writing type signatures
for polymorphic functions that use
Fixed
point numbers.
BEWARE: rounding by truncation introduces a sign bias!
- Truncation for positive numbers effectively results in: round towards zero.
- Truncation for negative numbers effectively results in: round towards -infinity.
- type SFixed = Fixed Signed
- sf :: SNat frac -> Signed (int + frac) -> SFixed int frac
- unSF :: SFixed int frac -> Signed (int + frac)
- type UFixed = Fixed Unsigned
- uf :: SNat frac -> Unsigned (int + frac) -> UFixed int frac
- unUF :: UFixed int frac -> Unsigned (int + frac)
- divide :: DivideC rep int1 frac1 int2 frac2 => Fixed rep int1 frac1 -> Fixed rep int2 frac2 -> Fixed rep ((int1 + frac2) + 1) (int2 + frac1)
- fLit :: forall rep int frac size. (size ~ (int + frac), KnownNat frac, Bounded (rep size), Integral (rep size)) => Double -> Q (TExp (Fixed rep int frac))
- newtype Fixed rep int frac = Fixed {}
- resizeF :: (ResizeFC rep int1 frac1 int2 frac2, Bounded (rep (int2 + frac2))) => Fixed rep int1 frac1 -> Fixed rep int2 frac2
- fracShift :: KnownNat frac => Fixed rep int frac -> Int
- type NumSFixedC int frac = (KnownNat frac, KnownNat (frac + frac), KnownNat (int + frac), KnownNat (1 + (int + frac)), KnownNat ((int + frac) + (int + frac)), ((int + int) + (frac + frac)) ~ ((int + frac) + (int + frac)))
- type ENumSFixedC int1 frac1 int2 frac2 = (KnownNat frac1, KnownNat frac2, KnownNat (Max frac1 frac2), KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat ((int1 + int2) + (frac1 + frac2)), KnownNat (1 + Max (int1 + frac1) (int2 + frac2)), KnownNat ((1 + Max int1 int2) + Max frac1 frac2), ((int1 + frac1) + (int2 + frac2)) ~ ((int1 + int2) + (frac1 + frac2)))
- type FracSFixedC int frac = (NumSFixedC int frac, KnownNat int, KnownNat (((int + frac) + 1) + (int + frac)))
- type ResizeSFC int1 frac1 int2 frac2 = (KnownNat frac1, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2))
- type DivideSC int1 frac1 int2 frac2 = (KnownNat int2, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat (((int1 + frac2) + 1) + (int2 + frac1)))
- type NumUFixedC int frac = NumSFixedC int frac
- type ENumUFixedC int1 frac1 int2 frac2 = ENumSFixedC int1 frac1 int2 frac2
- type FracUFixedC int frac = FracSFixedC int frac
- type ResizeUFC int1 frac1 int2 frac2 = ResizeSFC int1 frac1 int2 frac2
- type DivideUC int1 frac1 int2 frac2 = DivideSC int1 frac1 int2 frac2
- type NumFixedC rep int frac = (SaturatingNum (rep (int + frac)), ExtendingNum (rep (int + frac)) (rep (int + frac)), ResizeFC rep (int + int) (frac + frac) int frac, MResult (rep (int + frac)) (rep (int + frac)) ~ rep ((int + int) + (frac + frac)))
- type ENumFixedC rep int1 frac1 int2 frac2 = (ResizeFC rep int1 frac1 (1 + Max int1 int2) (Max frac1 frac2), ResizeFC rep int2 frac2 (1 + Max int1 int2) (Max frac1 frac2), Bounded (rep ((1 + Max int1 int2) + Max frac1 frac2)), Num (rep ((1 + Max int1 int2) + Max frac1 frac2)), ExtendingNum (rep (int1 + frac1)) (rep (int2 + frac2)), MResult (rep (int1 + frac1)) (rep (int2 + frac2)) ~ rep ((int1 + int2) + (frac1 + frac2)))
- type FracFixedC rep int frac = (NumFixedC rep int frac, DivideC rep int frac int frac, Integral (rep (int + frac)))
- type ResizeFC rep int1 frac1 int2 frac2 = (Resize rep, Ord (rep (int1 + frac1)), Num (rep (int1 + frac1)), Bits (rep (int1 + frac1)), Bits (rep (int2 + frac2)), KnownNat frac1, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2))
- type DivideC rep int1 frac1 int2 frac2 = (Resize rep, Integral (rep (((int1 + frac2) + 1) + (int2 + frac1))), Bits (rep (((int1 + frac2) + 1) + (int2 + frac1))), KnownNat int2, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat (((int1 + frac2) + 1) + (int2 + frac1)))
- asRepProxy :: Fixed rep int frac -> Proxy rep
- asIntProxy :: Fixed rep int frac -> Proxy int
SFixed
: Signed
Fixed
point numbers
type SFixed = Fixed Signed Source
Signed Fixed
-point number, with int
integer bits (including sign-bit)
and frac
fractional bits.
- The range
SFixed
int
frac
numbers is: [-(2^(int
-1)) .. 2^(int
-1) - 2^-frac
] - The resolution of
SFixed
int
frac
numbers is: 2^frac
- The
Num
operators for this type saturate on overflow, and use truncation as the rounding method.
>>>
maxBound :: SFixed 3 4
3.9375>>>
minBound :: SFixed 3 4
-4.0>>>
1 + 2 :: SFixed 3 4
3.0>>>
2 + 3 :: SFixed 3 4
3.9375>>>
(-2) + (-3) :: SFixed 3 4
-4.0>>>
1.375 * (-0.8125) :: SFixed 3 4
-1.125>>>
(1.375 :: SFixed 3 4) `times` (-0.8125 :: SFixed 3 4) :: SFixed 6 8
-1.1171875>>>
(2 :: SFixed 3 4) `plus` (3 :: SFixed 3 4) :: SFixed 4 4
5.0>>>
(-2 :: SFixed 3 4) `plus` (-3 :: SFixed 3 4) :: SFixed 4 4
-5.0
unSF :: SFixed int frac -> Signed (int + frac) Source
See the underlying representation of a Signed Fixed-point integer
UFixed
: Unsigned
Fixed
point numbers
type UFixed = Fixed Unsigned Source
Unsigned Fixed
-point number, with int
integer bits and frac
fractional bits
- The range
UFixed
int
frac
numbers is: [0 .. 2^int
- 2^-frac
] - The resolution of
UFixed
int
frac
numbers is: 2^frac
- The
Num
operators for this type saturate on overflow, and use truncation as the rounding method.
>>>
maxBound :: UFixed 3 4
7.9375>>>
minBound :: UFixed 3 4
0.0>>>
1 + 2 :: UFixed 3 4
3.0>>>
2 + 6 :: UFixed 3 4
7.9375>>>
1 - 3 :: UFixed 3 4
0.0>>>
1.375 * 0.8125 :: UFixed 3 4
1.0625>>>
(1.375 :: UFixed 3 4) `times` (0.8125 :: UFixed 3 4) :: UFixed 6 8
1.1171875>>>
(2 :: UFixed 3 4) `plus` (6 :: UFixed 3 4) :: UFixed 4 4
8.0
However, minus
does not saturate to minBound
on underflow:
>>>
(1 :: UFixed 3 4) `minus` (3 :: UFixed 3 4) :: UFixed 4 4
14.0
unUF :: UFixed int frac -> Unsigned (int + frac) Source
See the underlying representation of an Unsigned Fixed-point integer
Division
divide :: DivideC rep int1 frac1 int2 frac2 => Fixed rep int1 frac1 -> Fixed rep int2 frac2 -> Fixed rep ((int1 + frac2) + 1) (int2 + frac1) Source
Fixed point division
When used in a polymorphic setting, use the following Constraint synonyms for less verbose type signatures:
for:DivideC
rep int1 frac1 int2 frac2Fixed
rep int1 frac1 ->Fixed
rep int2 frac2 ->Fixed
rep (int1 + frac2 + 1) (int2 + frac1)
for:DivideSC
rep int1 frac1 int2 frac2SFixed
int1 frac1 ->SFixed
int2 frac2 ->SFixed
(int1 + frac2 + 1) (int2 + frac1)
for:DivideUC
rep int1 frac1 int2 frac2UFixed
int1 frac1 ->UFixed
int2 frac2 ->UFixed
(int1 + frac2 + 1) (int2 + frac1)
Compile-time Double
conversion
fLit :: forall rep int frac size. (size ~ (int + frac), KnownNat frac, Bounded (rep size), Integral (rep size)) => Double -> Q (TExp (Fixed rep int frac)) Source
Convert, at compile-time, a Double
constant to a Fixed
-point literal.
The conversion saturates on overflow, and uses truncation as its rounding
method.
So when you type:
n = $$(fLit
pi) ::SFixed
4 4
The compiler sees:
n =Fixed
(fromInteger 50) ::SFixed
4 4
Upon evaluation you see that the value is rounded / truncated in accordance to the fixed point representation:
>>>
n
3.125
Further examples:
>>>
sin 0.5 :: Double
0.479425538604203>>>
$$(fLit (sin 0.5)) :: SFixed 1 8
0.4765625>>>
atan 0.2 :: Double
0.19739555984988078>>>
$$(fLit (atan 0.2)) :: SFixed 1 8
0.1953125>>>
$$(fLit (atan 0.2)) :: SFixed 1 20
0.19739532470703125
Fixed
point wrapper
newtype Fixed rep int frac Source
Fixed
-point number
Where:
rep
is the underlying representationint
is the number of bits used to represent the integer partfrac
is the number of bits used to represent the fractional part
The Num
operators for this type saturate to maxBound
on overflow and
minBound
on underflow, and use truncation as the rounding method.
Bounded (rep ((+) int frac)) => Bounded (Fixed rep int frac) Source | |
Enum (rep ((+) int frac)) => Enum (Fixed rep int frac) Source | |
Eq (rep ((+) int frac)) => Eq (Fixed rep int frac) Source | |
FracFixedC rep int frac => Fractional (Fixed rep int frac) Source | The operators of this instance saturate on overflow, and use truncation as the rounding method. When used in a polymorphic setting, use the following Constraint synonyms for less verbose type signatures:
|
NumFixedC rep int frac => Num (Fixed rep int frac) Source | The operators of this instance saturate on overflow, and use truncation as the rounding method. When used in a polymorphic setting, use the following Constraint synonyms for less verbose type signatures:
|
Ord (rep ((+) int frac)) => Ord (Fixed rep int frac) Source | |
((~) Nat size ((+) int frac), KnownNat frac, Integral (rep size)) => Show (Fixed rep int frac) Source | |
Bits (rep ((+) int frac)) => Bits (Fixed rep int frac) Source | |
Default (rep ((+) int frac)) => Default (Fixed rep int frac) Source | |
(Lift (rep ((+) int frac)), KnownNat frac, KnownNat int, Typeable (Nat -> *) rep) => Lift (Fixed rep int frac) Source | |
NumFixedC rep int frac => SaturatingNum (Fixed rep int frac) Source | |
BitPack (rep ((+) int frac)) => BitPack (Fixed rep int frac) Source | |
Bundle (Fixed rep int frac) Source | |
ENumFixedC rep int1 frac1 int2 frac2 => ExtendingNum (Fixed rep int1 frac1) (Fixed rep int2 frac2) Source | When used in a polymorphic setting, use the following Constraint synonyms for less verbose type signatures:
|
type Unbundled' clk (Fixed rep int frac) = Signal' clk (Fixed rep int frac) | |
type BitSize (Fixed rep int frac) = BitSize (rep ((+) int frac)) Source | |
type AResult (Fixed rep int1 frac1) (Fixed rep int2 frac2) = Fixed rep ((+) 1 (Max int1 int2)) (Max frac1 frac2) Source | |
type MResult (Fixed rep int1 frac1) (Fixed rep int2 frac2) = Fixed rep ((+) int1 int2) ((+) frac1 frac2) Source |
resizeF :: (ResizeFC rep int1 frac1 int2 frac2, Bounded (rep (int2 + frac2))) => Fixed rep int1 frac1 -> Fixed rep int2 frac2 Source
Saturating resize operation, truncates for rounding
>>>
0.8125 :: SFixed 3 4
0.8125>>>
resizeF (0.8125 :: SFixed 3 4) :: SFixed 2 3
0.75>>>
3.4 :: SFixed 3 4
3.375>>>
resizeF (3.4 :: SFixed 3 4) :: SFixed 2 3
1.875>>>
maxBound :: SFixed 2 3
1.875
When used in a polymorphic setting, use the following Constraint synonyms for less verbose type signatures:
fracShift :: KnownNat frac => Fixed rep int frac -> Int Source
Get the position of the virtual point
of a Fixed
-point
number
Constraint synonyms
Writing polymorphic functions over fixed point numbers can be a potentially verbose due to the many class constraints induced by the functions and operators of this module.
Writing a simple multiply-and-accumulate function can already give rise to many lines of constraints:
mac :: (KnownNat
frac ,KnownNat
(frac + frac) ,KnownNat
(int + frac) ,KnownNat
(1 + (int + frac)) ,KnownNat
((int + frac) + (int + frac)) , ((int + int) + (frac + frac)) ~ ((int + frac) + (int + frac)) ) =>SFixed
int frac ->SFixed
int frac ->SFixed
int frac ->SFixed
int frac mac s x y = s + (x * y)
But with constraint synonyms, you can write the type signature like this:
mac1 ::NumSFixedC
int frac =>SFixed
int frac ->SFixed
int frac ->SFixed
int frac ->SFixed
int frac mac1 s x y = s + (x * y)
Where NumSFixedC
refers to the Constraints
needed by the operators of
the Num
class for the SFixed
datatype.
Although the number of constraints for the mac
function defined earlier might
be considered small, here is an "this way lies madness" example where you
really want to use constraint kinds:
mac2 :: (KnownNat
frac1 ,KnownNat
frac2 ,KnownNat
frac3 ,KnownNat
(Max frac1 frac2) ,KnownNat
(int1 + frac1) ,KnownNat
(int2 + frac2) ,KnownNat
(int3 + frac3) ,KnownNat
(frac1 + frac2) ,KnownNat
(Max (frac1 + frac2) frac3) ,KnownNat
(((int1 + int2) + (frac1 + frac2)) + (int3 + frac3)) ,KnownNat
((int1 + int2) + (frac1 + frac2)) ,KnownNat
(1 + Max (int1 + frac1) (int2 + frac2)) ,KnownNat
(1 + Max (int1 + int2) int3 + Max (frac1 + frac2) frac3) ,KnownNat
((1 + Max int1 int2) + Max frac1 frac2) ,KnownNat
((1 + Max ((int1 + int2) + (frac1 + frac2)) (int3 + frac3))) , ((int1 + frac1) + (int2 + frac2)) ~ ((int1 + int2) + (frac1 + frac2)) , (((int1 + int2) + int3) + ((frac1 + frac2) + frac3)) ~ (((int1 + int2) + (frac1 + frac2)) + (int3 + frac3)) ) =>SFixed
int1 frac1 ->SFixed
int2 frac2 ->SFixed
int3 frac3 ->SFixed
(1 + Max (int1 + int2) int3) (Max (frac1 + frac2) frac3) mac2 x y s = (x `times` y) `plus` s
Which, with the proper constraint kinds can be reduced to:
mac3 :: (ENumSFixedC
int1 frac1 int2 frac2 ,ENumSFixedC
(int1 + int2) (frac1 + frac2) int3 frac3 ) =>SFixed
int1 frac1 ->SFixed
int2 frac2 ->SFixed
int3 frac3 ->SFixed
(1 + Max (int1 + int2) int3) (Max (frac1 + frac2) frac3) mac3 x y s = (x `times` y) `plus` s
Constraint synonyms for SFixed
type NumSFixedC int frac = (KnownNat frac, KnownNat (frac + frac), KnownNat (int + frac), KnownNat (1 + (int + frac)), KnownNat ((int + frac) + (int + frac)), ((int + int) + (frac + frac)) ~ ((int + frac) + (int + frac))) Source
type ENumSFixedC int1 frac1 int2 frac2 = (KnownNat frac1, KnownNat frac2, KnownNat (Max frac1 frac2), KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat ((int1 + int2) + (frac1 + frac2)), KnownNat (1 + Max (int1 + frac1) (int2 + frac2)), KnownNat ((1 + Max int1 int2) + Max frac1 frac2), ((int1 + frac1) + (int2 + frac2)) ~ ((int1 + int2) + (frac1 + frac2))) Source
Constraint for the ExtendingNum
instance of SFixed
type FracSFixedC int frac = (NumSFixedC int frac, KnownNat int, KnownNat (((int + frac) + 1) + (int + frac))) Source
Constraint for the Fractional
instance of SFixed
type ResizeSFC int1 frac1 int2 frac2 = (KnownNat frac1, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2)) Source
type DivideSC int1 frac1 int2 frac2 = (KnownNat int2, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat (((int1 + frac2) + 1) + (int2 + frac1))) Source
Constraint synonyms for UFixed
type NumUFixedC int frac = NumSFixedC int frac Source
type ENumUFixedC int1 frac1 int2 frac2 = ENumSFixedC int1 frac1 int2 frac2 Source
Constraint for the ExtendingNum
instance of UFixed
type FracUFixedC int frac = FracSFixedC int frac Source
Constraint for the Fractional
instance of UFixed
Constraint synonyms for Fixed
wrapper
type NumFixedC rep int frac = (SaturatingNum (rep (int + frac)), ExtendingNum (rep (int + frac)) (rep (int + frac)), ResizeFC rep (int + int) (frac + frac) int frac, MResult (rep (int + frac)) (rep (int + frac)) ~ rep ((int + int) + (frac + frac))) Source
type ENumFixedC rep int1 frac1 int2 frac2 = (ResizeFC rep int1 frac1 (1 + Max int1 int2) (Max frac1 frac2), ResizeFC rep int2 frac2 (1 + Max int1 int2) (Max frac1 frac2), Bounded (rep ((1 + Max int1 int2) + Max frac1 frac2)), Num (rep ((1 + Max int1 int2) + Max frac1 frac2)), ExtendingNum (rep (int1 + frac1)) (rep (int2 + frac2)), MResult (rep (int1 + frac1)) (rep (int2 + frac2)) ~ rep ((int1 + int2) + (frac1 + frac2))) Source
Constraint for the ExtendingNum
instance of Fixed
type FracFixedC rep int frac = (NumFixedC rep int frac, DivideC rep int frac int frac, Integral (rep (int + frac))) Source
Constraint for the Fractional
instance of Fixed
type ResizeFC rep int1 frac1 int2 frac2 = (Resize rep, Ord (rep (int1 + frac1)), Num (rep (int1 + frac1)), Bits (rep (int1 + frac1)), Bits (rep (int2 + frac2)), KnownNat frac1, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2)) Source
Constraint for the resizeF
function
type DivideC rep int1 frac1 int2 frac2 = (Resize rep, Integral (rep (((int1 + frac2) + 1) + (int2 + frac1))), Bits (rep (((int1 + frac2) + 1) + (int2 + frac1))), KnownNat int2, KnownNat frac2, KnownNat (int1 + frac1), KnownNat (int2 + frac2), KnownNat (((int1 + frac2) + 1) + (int2 + frac1))) Source
Constraint for the divide
function
Proxy
asRepProxy :: Fixed rep int frac -> Proxy rep Source