Research-Stack/0-Core-Formalism/lean/external/OTOM/FixedPoint.lean

116 lines
2.9 KiB
Text

namespace Semantics
/--
Q16.16 fixed-point representation.
- 32-bit unsigned integer interpreted as signed 16.16 fixed point.
- 0x00010000 = 1.0
- 0xFFFFFFFF = -0.000015 (or used as sentinel for infinity/illegal)
- Range: [-32768.0, 32767.999985]
- Resolution: 1/65536 ≈ 0.000015
All arithmetic uses 64-bit intermediates to prevent overflow,
then truncates back to 32 bits.
-/
structure Q16_16 where
val : UInt32
deriving Repr, DecidableEq, BEq, Inhabited
namespace Q16_16
def zero : Q16_16 := ⟨0x00000000⟩
def one : Q16_16 := ⟨0x00010000⟩
def infinity : Q16_16 := ⟨0xFFFFFFFF⟩
@[inline]
def ofInt (n : Int) : Q16_16 :=
⟨UInt32.ofInt (n * 65536)⟩
@[inline]
def toInt (q : Q16_16) : Int :=
Int.ofNat (q.val.toUInt64 : UInt64).toNat - (if q.val ≥ 0x80000000 then 0x100000000 else 0)
@[inline]
def toFloat (q : Q16_16) : Float :=
Float.ofInt (toInt q) / 65536.0
@[inline]
def ofFloat (f : Float) : Q16_16 :=
if f.isNaN || f ≥ 32768.0 then infinity
else if f ≤ -32768.0 then ⟨0x80000000⟩
else ⟨(f * 65536.0).floor.toUInt32⟩
@[inline]
def add (a b : Q16_16) : Q16_16 := ⟨(a.val.toUInt64 + b.val.toUInt64).toUInt32⟩
@[inline]
def sub (a b : Q16_16) : Q16_16 := ⟨(a.val.toUInt64 - b.val.toUInt64).toUInt32⟩
@[inline]
def mul (a b : Q16_16) : Q16_16 :=
⟨(a.val.toUInt64 * b.val.toUInt64 >>> 16).toUInt32⟩
@[inline]
def div (a b : Q16_16) : Q16_16 :=
if b.val == 0 then infinity
else ⟨(a.val.toUInt64 <<< 16 / b.val.toUInt64).toUInt32⟩
@[inline]
def abs (q : Q16_16) : Q16_16 :=
if q.val == 0x80000000 then ⟨0x80000000⟩
else ⟨(if q.val ≥ 0x80000000 then UInt32.ofInt (-Int.ofNat q.val.toNat) else q.val)⟩
@[inline]
def max (a b : Q16_16) : Q16_16 :=
⟨if a.val ≥ b.val then a.val else b.val⟩
@[inline]
def min (a b : Q16_16) : Q16_16 :=
⟨if a.val ≤ b.val then a.val else b.val⟩
@[inline]
def neg (q : Q16_16) : Q16_16 := ⟨UInt32.ofInt (-q.toInt)⟩
@[inline]
def sqrt (q : Q16_16) : Q16_16 :=
if q.val == 0 then zero
else
let f := toFloat q
if f ≤ 0.0 then zero
else ofFloat (Float.sqrt f)
@[inline]
def pow (a b : Q16_16) : Q16_16 :=
ofFloat (Float.pow (toFloat a) (toFloat b))
@[inline]
def sin (q : Q16_16) : Q16_16 :=
ofFloat (Float.sin (toFloat q))
@[inline]
def gt (a b : Q16_16) : Bool := a.toInt > b.toInt
@[inline]
def lt (a b : Q16_16) : Bool := a.toInt < b.toInt
@[inline]
def le (a b : Q16_16) : Bool := a.toInt ≤ b.toInt
@[inline]
def ge (a b : Q16_16) : Bool := a.toInt ≥ b.toInt
-- Typeclass instances for comparison operators
instance : LE Q16_16 where
le a b := a.toInt ≤ b.toInt
instance : LT Q16_16 where
lt a b := a.toInt < b.toInt
instance : DecidableRel (fun a b : Q16_16 => a ≤ b) :=
fun a b => inferInstanceAs (Decidable (a.toInt ≤ b.toInt))
instance : DecidableRel (fun a b : Q16_16 => a < b) :=
fun a b => inferInstanceAs (Decidable (a.toInt < b.toInt))
end Q16_16
end Semantics