Just for the fun of it, and to prove it can be done, I finished an AVR assembly routine to calculate sin(x) results in 24 bits (3 bytes) with one bit of error. The input angle is in degrees with one decimal digit, from 000 to 900 (0~90.0) for the first quadrant only. It uses less than 210 AVR instructions and runs on average of 212 microseconds, varying from 211us (angle=001) to 213us (angle=899).
It took several days to do it all, more than 10 days (free hours) just thinking about the best algorithm for the calculation, considering the AVR microcontroller, no floating point, eliminating all possible divisions. What took more time was to make the right step-up values for integers, to have good precision it needs to step-up values of 1e-8 to binary integers 2^28 or more. Once all the errors culprits of precision and rounding up were found, increased their calculation resolution by extra 2^8 or 2^16, the best results were met. I first simulated all the calculations on Excel taking care of having all values as Int(x) or Round(x,0) to represent exactly the AVR core processing.
For example, in the algorithm the angle must be in Radians, the input is in Degrees to facilitate for the user. To convert Degrees to Radians the trivial formula is rad=degrees*PI/180, it seems nice and easy, but it is not, PI is an infinite number - if using few digits it will create errors at the output, division by 180 requires AVR bit manipulation since it has no division instruction, and more than that, the result would require floating point since involves numbers far below integer 1. For example, Radian of 1° (degree) is 0.017453293. Since PI and 180 are constants, why not reverse this thing for simple multiplication? PI/180 = 0.017453293, multiply it by 2^32 and it results as a constant 74961320 (0x0477D1A8), multiply this number by your angle in degrees, lets say 900 for 90° and shift it 4 bits right (÷16) to obtain 4216574250 (0xFB53D12A), that is the radians of the 90° with 2^28 expansion, fit in 4 bytes, without a single division (except the 4 bit shift right). In a way, the error included in such trick is smaller than 2^-27.
So, all further calculations need to remember it is 2^28 higher and taken care of it. You need to divide the on-the-go results by 16, 256 or even 65536 just to avoid it use unnecessary growing hunger bytes that would not help resolution. That was a painstaking job, just finding the minimum quantity of bits in each calculation results, keeping the results precision around 24 bits. Each one of the several calculations where done in try/error with higher or lower bits count in the Excel flow, watching the overall quantity of error bits at the result in a graph showing 0-90° with a macro running the code 900 times, once per tenth of a degree. That "visual" Excel approach was a tool I created, helped a lot to find the best solution for every single part of the code.
For example, rounding up this particular calculation result 13248737.51 to 13248738 or just lose the "0.51" decimals, how much it will affect the final result precision for all the 900 input angles (00.1 ~ 90.0) tests?
I was able to keep the animal contained within 32 bits (4 bytes) on every calculation, and ended up with the magic to obtain precision within 23 bits of the result. When checking the whole 3 bytes of the result, the error is ±1 LSB, outstanding.
The user may grab one, two or three bytes from the result for its own requirements of precision. Of course, if just one byte is enough I would recommend to use a single 256 bytes sin table and use AVR 'LPM' instruction to grab it.
Once I had the Excel sequence running smooth and neat, the final translation from Excel to AVR assembly took less than 2 hours, as usual you should think more first, work less later.
At that time I was able to squeeze yet more and reduce registers usage. The actual (not final) code uses around 205 instructions (~410 bytes), runs a sin(x) calculation in average of 212us, clock at 16MHz. At that speed it can calculate 4700+ sin(x) per second. Not being important, but it can run a precise sinewave up to 4700Hz with 23 bits of precision and resolution, without any lookup tables.
The base algorithm is based on Taylor series for sin(x), but modified a lot to fit my intentions with the AVR microcontroller and precision in mind.
Even that using a 2700 bytes table (900 entries * 3 bytes) would be speed attractive, what is the fun or learning experience on that? Of course, CORDIC approach was also considered, maybe later, the point here is to squeeze Taylor into the AVR core and take water from a dry rock.
I wonder if Arduino "sin(78.9°)" can run Processing (C++) with 23 bits of precision in less than 212us and the necessary code smaller than 205 instructions. May be if C++ uses CORDIC. Arduino sketches can import assembly code.
Makes no sense to post the code here, later I will edit this post to include a weblink to it, possibly on my blog at this url. The blog is mostly in portuguese.
This hobby-no-money venture was interesting, pushing the limits of the AVR engine of almost 16MIPS at 16MHz, without division instruction, multiplication only in 8x8 bits. It allows to calculate sin(x), cos(x) [=sin(900-x)] and tan(x) [=sin(x)/sin(900-x)].
Above it all, this helped to keep my 63 years old brain polished and oiled. When teenagers say the 'old people' know sh*nothing about technology, I answer "think again, who do you think created the bases for everything you enjoy today?".
Cheers