Skip to content

Instantly share code, notes, and snippets.

@SMT50001
Last active March 16, 2023 19:12
Show Gist options
  • Save SMT50001/9998844c15a6e5ade5aa43dfa78ba592 to your computer and use it in GitHub Desktop.
Save SMT50001/9998844c15a6e5ade5aa43dfa78ba592 to your computer and use it in GitHub Desktop.
Initial draft of fixed-point math library
import math
export math
{.push inline.}
when defined(release) and not defined(vfixpExplicitChecks):
{.push noinit, checks: off.}
template genFixpType*(gname, btyp: untyped, tsize, tfraction: int, upscaleto: typedesc) =
when tsize notin [16, 32]:
{.error: "Unsupported variable size".}
when tfraction >= tsize:
{.error: "Fraction is too big".}
type `btyp tsize F tfraction` * {.inject.} = distinct `gname tsize`
const
typeInteger = tsize - tfraction
typeFraction = tfraction
proc `+`*(x, y: `btyp tsize F tfraction`): `btyp tsize F tfraction` {.borrow.}
proc `-`*(x, y: `btyp tsize F tfraction`): `btyp tsize F tfraction` {.borrow.}
proc `==`*(x, y: `btyp tsize F tfraction`): bool {.borrow.}
proc `<`*(x, y: `btyp tsize F tfraction`): bool {.borrow.}
proc `<=`*(x, y: `btyp tsize F tfraction`): bool {.borrow.}
proc `*`*(x, y: `btyp tsize F tfraction`): `btyp tsize F tfraction` =
when low(`gname tsize`) < 0 :
let product = upscaleto(x) * upscaleto( y)
`btyp tsize F tfraction`((abs(product) shr typeFraction) * sgn(product))
else:
`btyp tsize F tfraction`((upscaleto(x) * upscaleto( y)) shr typeFraction)
proc `div`*(x, y: `btyp tsize F tfraction`): `btyp tsize F tfraction` =
when low(`gname tsize`) < 0 :
`btyp tsize F tfraction`((abs(upscaleto(x)) shl typeFraction) div upscaleto(y) * sgn(upscaleto(x)))
else:
`btyp tsize F tfraction`((upscaleto(x) shl typeFraction) div upscaleto(y))
proc `/`*(x, y: `btyp tsize F tfraction`): `btyp tsize F tfraction` = x div y
proc `to btyp tsize`*(x: `btyp tsize F tfraction`): `gname tsize` =
`gname tsize`(x) div (1 shl typeFraction)
proc toFloat*(x: `btyp tsize F tfraction`): float =
float(x) / float(1 shl typeFraction)
proc `to btyp tsize F tfraction`*[T: SomeNumber](x: T): `btyp tsize F tfraction` =
`btyp tsize F tfraction`(x * T(1 shl typeFraction))
proc `gname tsize f tfraction`*(integer: `gname tsize`, fractional: `uint tsize`): `btyp tsize F tfraction` =
# doesn't work yet
when not defined(release):
assert(integer*gname(sgn(integer)) < gname(1 shl typeInteger))
assert(fractional < `uint tsize`(1 shl typeFraction))
let
one = `gname tsize`(1 shl typeFraction)
frac = (`gname tsize`(fractional))
var fracSetBits = tsize
while frac shr (fracSetBits - 1) != 1: dec fracSetBits
`btyp tsize F tfraction` (`gname tsize`(integer) * one + frac shl (typeFraction - fracSetBits))
proc sqrt*(x: `btyp tsize F tfraction`): `btyp tsize F tfraction` =
# doesn't work yet
when (not defined(release)) and (low(`gname tsize`) < 0) :
assert( `gname tsize`(x) > 0)
var
temp: `gname tsize`
rslt: `gname tsize`
divisor: `gname tsize` = `gname tsize`(x)
rslt = `gname tsize`(x)
while true:
temp = `gname tsize`(x) div divisor + divisor
divisor = temp shr 1
divisor += temp and 1
if rslt > divisor:
rslt = divisor
else:
result = `btyp tsize F tfraction`(rslt)
break
proc `$`*(x: `btyp tsize F tfraction`): string =
let
ntg = `gname tsize`(x) div gname(2^typeFraction)
fra = `gname tsize`(x) shl typeInteger shr typeInteger
one = 1'u64 shl typeFraction
$ntg & "." & $(uint64(fra) * 10000000000'u64 div one )
genFixpType(int, Int, 32, 16, int64)
genFixpType(uint, Uint, 32, 16, uint64)
genFixpType(int, Int, 32, 8, int64)
genFixpType(uint, Uint, 32, 8, uint64)
when isMainModule:
echo $(uint32f8(12, 5) + uint32f8(4, 1))
echo $(toUint32F8(12.5) + toUint32F8(4.0))
when defined(release) and not defined(vfixpExplicitChecks):
{.pop.}
{.pop.}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment