; Prog8 definitions for floating point handling on the VirtualMachine %option enable_floats, ignore_unused floats { const float π = 3.141592653589793 const float PI = π const float TWOPI = 2*π sub print(float value) { ; ---- prints the floating point value (without a newline and no leading spaces). %ir {{ loadm.f fr65535,floats.print.value syscall 15 (fr65535.f) return }} } sub tostr(float value) -> str { ; ---- converts the floating point value to a string (no leading spaces) str @shared buffer=" "*20 %ir {{ load.w r65535,floats.tostr.buffer loadm.f fr65535,floats.tostr.value syscall 34 (r65535.w, fr65535.f) load.w r0,floats.tostr.buffer returnr.w r0 }} } sub parse(str value) -> float { ; -- parse a string value of a number to float %ir {{ loadm.w r65535,floats.parse.value syscall 32 (r65535.w): fr0.f returnr.f fr0 }} } sub pow(float value, float power) -> float { %ir {{ loadm.f fr0,floats.pow.value loadm.f fr1,floats.pow.power fpow.f fr0,fr1 returnr.f fr0 }} } sub sin(float angle) -> float { %ir {{ loadm.f fr0,floats.sin.angle fsin.f fr0,fr0 returnr.f fr0 }} } sub cos(float angle) -> float { %ir {{ loadm.f fr0,floats.cos.angle fcos.f fr0,fr0 returnr.f fr0 }} } sub tan(float value) -> float { %ir {{ loadm.f fr0,floats.tan.value ftan.f fr0,fr0 returnr.f fr0 }} } sub atan(float value) -> float { %ir {{ loadm.f fr0,floats.atan.value fatan.f fr0,fr0 returnr.f fr0 }} } ; two-argument arctangent that returns an angle in the correct quadrant ; for the signs of x and y, normalized to the range [0, 2π] sub atan2(float y, float x) -> float { float atn = atan(y / x) if x < 0 atn += π if atn < 0 atn += 2*π return atn } ; reciprocal functions sub secant(float value) -> float { return 1.0 / cos(value) } sub csc(float value) -> float { return 1.0 / sin(value) } sub cot(float value) -> float { return 1.0 / tan(value) } sub ln(float value) -> float { %ir {{ loadm.f fr0,floats.ln.value fln.f fr0,fr0 returnr.f fr0 }} } sub log2(float value) -> float { %ir {{ loadm.f fr0,floats.log2.value flog.f fr0,fr0 returnr.f fr0 }} } sub rad(float angle) -> float { ; -- convert degrees to radians (d * pi / 180) return angle * PI / 180.0 } sub deg(float angle) -> float { ; -- convert radians to degrees (d * (1/ pi * 180)) return angle * 180.0 / PI } sub round(float value) -> float { %ir {{ loadm.f fr0,floats.round.value fround.f fr0,fr0 returnr.f fr0 }} } sub floor(float value) -> float { %ir {{ loadm.f fr0,floats.floor.value ffloor.f fr0,fr0 returnr.f fr0 }} } sub ceil(float value) -> float { ; -- ceil: tr = int(f); if tr==f -> return else return tr+1 %ir {{ loadm.f fr0,floats.ceil.value fceil.f fr0,fr0 returnr.f fr0 }} } sub rnd() -> float { %ir {{ syscall 22 () : fr0.f returnr.f fr0 }} } sub rndseed(float seed) { %ir {{ loadm.f fr65535,floats.rndseed.seed syscall 19 (fr65535.f) return }} } sub minf(float f1, float f2) -> float { if f1 float { if f1>f2 return f1 return f2 } sub clampf(float value, float minimum, float maximum) -> float { if value float { return value } sub push(float value) { ; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works %ir {{ loadm.f fr65535,floats.push.value push.f fr65535 }} } sub pop() -> float { ; note: this *should* be inlined, however since the VM has separate program counter and value stacks, this also works %ir {{ pop.f fr65535 returnr.f fr65535 }} } }