256
ASM / Re: [z80] Floating Point Routines
« on: January 14, 2019, 02:40:17 pm »
x-post
I have been focusing on the single-precision floats this past week or so. I rewrote or re-worked a lot of routines. I got rid of most of the tables by switching to a polynomial approximation for the 2^x routine (thanks to the Sollya program!) and using the B-G algorithm to compute lnSingle. It turned out to be faster this way, anyways.
I implemented sine, cosine, and tangent, the first two, again, using minimax polynomial approximation. I optimized the square-root routine (much faster but a few bytes bigger). I re-implemented the B-G algorithm using math optimizations I came up with a few months ago. I opted for two B-G implementations-- one for lnSingle which requires only 1 iteration for single precision, and one for the inverse trig and hyperbolic functions which needs 2 iterations. For anybody looking to save on size, you can just use the second B-G routine for natural logarithm. It will be a little slower, but it'll work just fine (maybe even give you an extra half-bit of precision
).
I included the Python program that I use for converting numbers to my single precision format. You can use it to convert a single float or a bunch of them. I also included a Python tool I made for computing more efficient coefficients in the B-G algorithm, but that'll only be useful to me and maybe a handful of other people. It's there on the off chance somebody stumbles across my project looking for a B-G implementation.
The single precision floats are largely complete in that I can't think of any other functions that I want to add. There is still work to be done on range reduction and verification, as well as bug fixes and more extensive testing.
Here is a current screenshot of some of the routines and their outputs:

The current list of single-precision routines:
I have been focusing on the single-precision floats this past week or so. I rewrote or re-worked a lot of routines. I got rid of most of the tables by switching to a polynomial approximation for the 2^x routine (thanks to the Sollya program!) and using the B-G algorithm to compute lnSingle. It turned out to be faster this way, anyways.
I implemented sine, cosine, and tangent, the first two, again, using minimax polynomial approximation. I optimized the square-root routine (much faster but a few bytes bigger). I re-implemented the B-G algorithm using math optimizations I came up with a few months ago. I opted for two B-G implementations-- one for lnSingle which requires only 1 iteration for single precision, and one for the inverse trig and hyperbolic functions which needs 2 iterations. For anybody looking to save on size, you can just use the second B-G routine for natural logarithm. It will be a little slower, but it'll work just fine (maybe even give you an extra half-bit of precision

I included the Python program that I use for converting numbers to my single precision format. You can use it to convert a single float or a bunch of them. I also included a Python tool I made for computing more efficient coefficients in the B-G algorithm, but that'll only be useful to me and maybe a handful of other people. It's there on the off chance somebody stumbles across my project looking for a B-G implementation.
The single precision floats are largely complete in that I can't think of any other functions that I want to add. There is still work to be done on range reduction and verification, as well as bug fixes and more extensive testing.
Here is a current screenshot of some of the routines and their outputs:

The current list of single-precision routines:
Code: [Select]
Basic arithmetic:
absSingle |x| -> z Computes the absolute value
addSingle x+y -> z
ameanSingle (x+y)/2 -> z. Arithmetic mean of two numbers.
cmpSingle cmp(x,y) Compare two numbers. Output is in the flags register!
rsubSingle y-x -> z
subSingle x-y -> z
divSingle x/y -> z
invSingle 1/x -> z
mulSingle x*y -> z
negSingle -x -> z
sqrtSingle sqrt(x*y) -> z
geomeanSingle sqrt(x*y) -> z
Logs, Exponentials, Powers
expSingle e^x -> z
pow2Single 2^x -> z
pow10Single 10^x-> z
powSingle y^x -> z
lgSingle log2(x) -> z
lnSingle ln(x) -> z
log10Single log10(x) -> z
logSingle log_y(x) -> z
Trig, Hyperbolic, and their Inverses
acoshSingle acosh(x) -> z
acosSingle acos(x) -> z
asinhSingle asinh(x) -> z
asinSingle asin(x) -> z
atanhSingle atanh(x) -> z
atanSingle atan(x) -> z
coshSingle cosh(x) -> z
cosSingle cos(x) -> z
sinhSingle sinh(x) -> z
sinSingle sin(x) -> z
tanhSingle tanh(x) -> z
tanSingle tan(x) -> z
Special-Purpose Used by various internal functions, or optimized for special cases
bg2iSingle 1/BG(x,y) -> z Fewer iterations, but enough to be suitable for ln(x). Kind of a special-purpose routine
bgiSingle 1/BG(x,y) -> z More iterations, general-purpose, needed for the inverse trig and hyperbolics
div255Single x/255 -> z
div85Single x/85 -> z
div51Single x/51 -> z
div17Single x/17 -> z
div15Single x/15 -> z
div5Single x/5 -> z
div3Single x/3 -> z
mul10Single x*10 -> z
mulSingle_p375 x*0.375 -> z Used in bg2iSingle. x*(3/8)
mulSingle_p34375 x*0.34375-> z Used in bgiSingle. x*(11/32)
mulSingle_p041015625 x*0.041015625-> z Used in bgiSingle. x*(21/512)
Miscellaneous and Utility
randSingle rand -> z
single2str str(x) -> z Convert a single to a null-terminated string, with formatting
single2TI tifloat(x) -> z Converts a single to a TI-float. Useful for interacting with the TI-OS
ti2single single(tifloat x)->z Converts a TI-float to a single. Useful for interacting with the TI-OS
single2char Honestly, I forgot what it does, but I use it in some string routines. probably converts to a uint8
pushpop pushes the main registers to the stack and sets up a routine so that when your code exits, it restores registers. Replaces manually surrounding code with push...pop