Approximation of Sine function in Integer Forth
|
03-12-2022, 04:25 PM
(This post was last modified: 03-13-2022 10:51 AM by Martin Hepperle.)
Post: #1
|
|||
|
|||
Approximation of Sine function in Integer Forth
Recently I wanted to demonstrate a MS-DOS driver for plotting HPGL on a VGA screen.
To show how this driver could be used from any programming language I selected Forth as one example. The classical Forth implementations, like figForth did not support floating point calculations. Thus, everything has to be done with Integers, in my case in the range +/-32767. HPGL works nicely with integers as it defines its device units as 0.25 mm per unit. In order to generate some interesting plots with circles and spirals, I wanted to have an approximation of the trigonometric sine and cosine functions. As I had to stick with integers, I decided to scale the sine by a factor of 1000. So the approximation produces values in [-1000...+1000]. The input should be the angle in degrees, so that the angular resolution would be 1 degree. The restriction to signed 16-bit integers generally limits polynomial terms to powers of two and all integer divisions truncate. The often used power series around zero needs at least powers of 3 to produce reasonable accuracy over the range [0 to 90] degrees. First I tried a simple parabolic curve covering the range [0 to 180] degrees, which worked, but circles looked more like well rounded rectangles. In a second attempt I generated series expansions at the center point of four intervals over the range [0 to 90] degrees. While this requires tests for the interval, it is still reasonable fast. Some manual tweaking of the equations to the restriction of integer arithmetic produced a quite acceptable approximation. The attached PDF document shows my current set of equations and their deviation from the sine function as well as their implementation in Forth and RPL. Note: I am not looking just for a circle generator (there are a few integer algorithms for digital raster devices), but for the trigonometric functions for general applications. Maybe there is another more elegant or more accurate approach? Martin [edit: programs adapted to match equations below graph] [edit: added Garth's solution to the graph and page 2] |
|||
03-12-2022, 08:36 PM
(This post was last modified: 03-12-2022 11:08 PM by Thomas Klemm.)
Post: #2
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-12-2022 04:25 PM)Martin Hepperle Wrote: Maybe there is another more elegant or more accurate approach? You could use Bhaskara's Sine and Cosine Approximations. They are accurate to about 1‰. Functions in Python Code: def sin(x): Plot the Difference Code: import matplotlib.pyplot as plt Sine Code: plt.plot(x, sin(x) - 1000 * np.sin(np.radians(x)), 'b') Cosine Code: plt.plot(x, cos(x) - 1000 * np.cos(np.radians(x)), 'r') Cheers Thomas |
|||
03-12-2022, 09:46 PM
Post: #3
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
Here's some stuff I did many years ago in 16-bit Forth. Hopefully I correctly converted all the special characters from the DOS/ANSI character set.
A 16-bit circle works out nicely, scaling 360° to be exactly 65,536 counts, with 1 lsb being .00549316°, or .32959 arc-minutes, or 19.7754 arc-seconds. The MOD function doesn't even come up, as there's no need for it. 359° plus 2° is still 1°, and 45° minus 90° is still -45° or 315°. You can consider it signed or unsigned, either way. 90° is represented by $4000, 180° is represented by $8000, and 270° or -90° is represented by $C000. A radian is represented by $28BE. When you take the sin or cos, the output range will be ±1, which, for best resolution, we can scale to as high as ±$7FFF or $8000 depending on how you want to work the trapping (since you can't get +$8000 in a 16-bit signed number). There's a Wikipedia article on binary angular measure (BAM) and "brads" (binary radians) here, and Jack Crenshaw addresses it in chapter 5 of his fine book "Math Toolkit for Real-Time Programming." Code:
http://WilsonMinesCo.com (Lots of HP-41 links at the bottom of the links page, at http://wilsonminesco.com/links.html#hp41 ) |
|||
03-13-2022, 10:00 AM
(This post was last modified: 03-13-2022 10:53 AM by Martin Hepperle.)
Post: #4
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
Thank you for your comments!
For starting, I have implemented Garth's Forth code and added the result to the deviation plot. The overall deviation is much lower than my piecewise approximation but due to exploiting the full range for scaling, Garth's result is also much smoother. [edit: the attachment in my initial post was updated accordingly] [the only change I made to Garth's code was to replace -1 SHIFT by 1 RSHIFT in the word U*/_RND as my Forth only has RSHIFT and LSHIFT] Martin |
|||
03-13-2022, 12:56 PM
Post: #5
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-13-2022 10:00 AM)Martin Hepperle Wrote: the attachment in my initial post was updated accordingly Not sure if I interpret the new red line correctly but it looks as if you used the sin45 function. At least a difference of more than 5 for 90° suggests this. (03-12-2022 09:46 PM)Garth Wilson Wrote: Even a little above 45°, the accuracy is lost very quickly! I recommend to use the sin90 function instead. |
|||
03-13-2022, 08:00 PM
(This post was last modified: 03-13-2022 08:00 PM by Garth Wilson.)
Post: #6
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-13-2022 12:56 PM)Thomas Klemm Wrote:(03-12-2022 09:46 PM)Garth Wilson Wrote: Even a little above 45°, the accuracy is lost very quickly! Note that my sin90 and cos90 use the cos45 and sin45 (respectively) to get the desired accuracy above 45 degrees. Then the SIN and COS functions are usually accurate to all 16 bits, and the few times they're off, it's only by one lsb, and even then, it's always in the same direction, ie, high. http://WilsonMinesCo.com (Lots of HP-41 links at the bottom of the links page, at http://wilsonminesco.com/links.html#hp41 ) |
|||
03-14-2022, 12:15 AM
Post: #7
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
Considered a table lookup? Range reduce to forty-five degrees, look up the table, possibly do a linear interpolation between table values.
|
|||
03-14-2022, 01:16 PM
(This post was last modified: 03-14-2022 01:17 PM by Martin Hepperle.)
Post: #8
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
For my purpose, Garth's solution is very usable and "good enough" (famous last words ;-)).
It also fits nicely on a single Forth screen, has only a small memory footprint and takes about the same time as my initial, poor approximation. I don't need "absolute" accuracy - in this case I would probably consider something like Cordic and a floating point number representation. In the first update of my PDF document I had Garth's solution overlaid with wrong scaling on the horizontal axis, mapping 0...360 deg to my scale of 0...90 deg. I noticed my mistake and had corrected the document half an hour later, so maybe Thomas downloaded the incorrect, intermediate version? Martin |
|||
03-14-2022, 02:51 PM
Post: #9
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth | |||
03-14-2022, 05:58 PM
Post: #10
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-12-2022 04:25 PM)Martin Hepperle Wrote: Maybe there is another more elegant or more accurate approach? There is an example of transcendential functions calculation in the Lesson 12 of Dr. C.H. Ting collection with the refference to original article in Forth Dimension Volume 04 Issue 1. Many more to learn from Dr. Ting about Forth if you are interested including nice Win32Forth. KR Pavel |
|||
03-14-2022, 10:39 PM
Post: #11
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-14-2022 05:58 PM)pavel nemec cz Wrote: There is an example of transcendental functions calculation … This was an interesting read. Thanks for sharing. (03-14-2022 12:15 AM)Paul Dale Wrote: Considered a table lookup? In the linked document Forth Dimensions we can also find an article on page 6: Fixed-Point Trig by Table Lookup |
|||
03-15-2022, 01:15 PM
(This post was last modified: 03-15-2022 01:16 PM by Martin Hepperle.)
Post: #12
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
Thank you for the reference to Forth Dimensions - these old issues contain a lot of useful information and tips and tricks. I had forgotten to look through them again.
The issue V4N1 is indeed interesting as it also shows a pure Forth implementation of Floating Point numbers, which demonstrates how large such an implementatio0n becomes when you use no assembler or coprocessor. BTW: This web page has an index of articles in V1 to V6 of Forth Dimensions and direct links to the issues in PDF. Martin |
|||
03-15-2022, 08:30 PM
Post: #13
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
(03-15-2022 01:15 PM)Martin Hepperle Wrote: BTW: This web page has an index of articles in V1 to V6 of Forth Dimensions and direct links to the issues in PDF. Thanks, great reference! |
|||
03-23-2022, 08:07 AM
Post: #14
|
|||
|
|||
RE: Approximation of Sine function in Integer Forth
Some time ago I had to draw a simple ascii-circle for some kind of "clock project" for an Arduino. The primary goal (on Arduinos) is to write codes with small footprint and sufficient precision. I used some kind of lookup table with 16 bytes only to calculate rough values for sine (and cosine).
Maybe this code snippet can give you another idea? You can save the division (/ 200) by expanding (and/or recalculating) the byte values to int values. Code:
Regards deetee |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 3 Guest(s)