Trigonometric functions: Difference between revisions
Content added Content deleted
(Replaced "radians" and "degrees" procs with "degTorRad" and "radToDeg" which are now provided by the module "math". Changed output formatting. Added output section.) |
(Added Quackery.) |
||
Line 4,054: | Line 4,054: | ||
Arctangent: 0.7853981633974483 45.0 |
Arctangent: 0.7853981633974483 45.0 |
||
>>> </lang> |
>>> </lang> |
||
=={{header|Quackery}}== |
|||
<code>v**</code> is defined at [[Exponentiation operator#Quackery]]. |
|||
'''Please note''', the code presented here is sufficient to the task, but is not a practical implementation for the reasons discussed below. The intent of this entry is to invite discussion on the subject of Padé Approximants, the method used here. To that end I have opened a section on the subject in the Discussion page of this task, and invite you to contribute to it if you have useful knowledge of Padé Approximants. |
|||
Full disclosure - I am not a mathematician, I am an amateur programmer who has recently heard of Padé Approximants and is desirous of learning more, as they look to be a useful tool, but not a panacea. |
|||
A search of Rosetta Code at the time of writing (14 July 2021) finds no references to Padé or Pade on the site. A more general search of the Internet turns up such phrases as "is the "best" approximation of a function by a rational function of given order" and "The unreasonable effectiveness of Pade approximation", which piqued my interest. Generally there are scholarly papers in the subject that whoosh right over my head, and very little at the "pop-maths" level, i.e. no videos by my go-to YouTube channels - numberphile/computerphile, 3blue1brown, mythologer. |
|||
In the absence of sources pitched at my level, this is the methodology I have developed to create this code. |
|||
''Step 1''. Use Wolfram Alpha to find Padé Approximants for a function. Here is the relevant documentation for Mathematica, which also applies to Wolfram Alpha. Link: [https://reference.wolfram.com/language/ref/PadeApproximant.html PadeApproximant]. |
|||
Here are the inputs to Wolfram Alpha used in generating this Quackery code. [https://www.wolframalpha.com/input/?i=PadeApproximant%5BSin%5Bx%5D%2C+%7Bx%2C+0%2C+%7B6%2C6%7D%7D%5D sin], [https://www.wolframalpha.com/input/?i=PadeApproximant%5Bcos%5Bx%5D%2C+%7Bx%2C+0%2C+%7B7%2C7%7D%7D%5D cos], [https://www.wolframalpha.com/input/?i=PadeApproximant%5Barccos%5Bx%5D%2C+%7Bx%2C+0%2C+%7B6%2C6%7D%7D%5D tan], [https://www.wolframalpha.com/input/?i=PadeApproximant%5Barcsin%5Bx%5D%2C+%7Bx%2C+0%2C+%7B6%2C6%7D%7D%5D arcsin], [https://www.wolframalpha.com/input/?i=PadeApproximant%5Barccos%5Bx%5D%2C+%7Bx%2C+0%2C+%7B6%2C6%7D%7D%5D+%29 arccos], and [https://www.wolframalpha.com/input/?i=PadeApproximant%5Barctan%5Bx%5D%2C+%7Bx%2C+0%2C+%7B7%2C7%7D%7D%5D arctan]. |
|||
Note that the exact result for <code>arccos</code> includes several instances of the irrational number π, which is not ideal given that the intent is to generate a rational approximation, so instead I used the identity arccos(x)=π/2-arcsin(x), which Wolfram Alpha lists amongst the "Alternate forms", reducing the number of uses of π to one. |
|||
''Step 2''. Use GeoGebra to see the range of arguments over which the Padé approximant is valid, and to identify the range in which it will return values correct to a given number of decimal places. In each of the following examples, function <code>f</code> is a Padé Approximant, function <code>g</code> is the function that <code>f</code> is approximating, and function <code>h</code> is the difference between <code>f</code> and <code>g</code>, multiplied by <code>10^n</code>, where <code>n</code> can be varied with a slider. Where the <code>h</code> line is very close to zero, the approximation will be good to <code>n</code> decimal places. |
|||
Your attention is drawn to the task output for <code>arccos</code>, which is only good to a couple of decimal places for the argument passed to it. This is explained by the corresponding graph in Geogebra, where we can see that the argument is outside the safe (i.e. <code>h</code> is close to zero) range for anything other than very small values of <code>n</code>. |
|||
Geogebra graphs for the functions defined in this task: [https://www.geogebra.org/m/nygvcs2s sin], [https://www.geogebra.org/m/q3myjbfd cos], [https://www.geogebra.org/m/fsdfzzfs tan], [https://www.geogebra.org/m/n6jctj7c arcsin], [https://www.geogebra.org/m/kkrhjksu arccos], [https://www.geogebra.org/m/ge4qpppf arctan]. |
|||
''Step 3''. Iterate over steps 1 and 2 until you find appropriate Padé Approximants for the task at hand, or conclude that none exist. Assuming the former; |
|||
''Step 4''. Code in a suitable language (i.e. probably not Quackery - efficiency was not a design criterion for Quackery, the language is intended to be the simplest possible introduction to Concatenative/Stack based programming, and is consequently suitable for hobbyist and educational use only) with any obvious optimisations, and use symmetries and identities of the function to extend the range of arguments that can be passed to it. (Not done here - the code serves solely to demonstrate the one-to-one correspondence between a proof-of-concept coding and the formula returned by Wolfram Alpha.) |
|||
Note also that the approximation of π/2 is good to 40 decimal places. This is intentional overkill, so that I can be sure that it is not the cause of any inaccuracies. Reducing the size of the numerator and denomination to more sensible values would be part of the optimisation process. |
|||
<lang Quackery> [ $" bigrat.qky' loadfile ] now! |
|||
[ 2646693125139304345 |
|||
1684937174853026414 ] is pi/2 ( --> n/d ) |
|||
[ 2dup |
|||
2dup 3 v** 2363 18183 v* v- |
|||
2over 5 v** 12671 4363920 v* v+ |
|||
2swap 1 1 |
|||
2over 2 v** 445 12122 v* v+ |
|||
2over 4 v** 601 872784 v* v+ |
|||
2swap 6 v** 121 16662240 v* v+ |
|||
v/ ] is sin ( n/d --> n/d ) |
|||
[ 1 1 |
|||
2over 2 v** 3665 7788 v* v- |
|||
2over 4 v** 711 25960 v* v+ |
|||
2over 6 v** 2923 7850304 v* v- |
|||
2swap 1 1 |
|||
2over 2 v** 229 7788 v* v+ |
|||
2over 4 v** 1 2360 v* v+ |
|||
2swap 6 v** 127 39251520 v* v+ |
|||
v/ ] is cos ( n/d --> n/d ) |
|||
[ 2dup |
|||
2dup 3 v** 5 39 v* v- |
|||
2over 5 v** 2 715 v* v+ |
|||
2over 7 v** 1 135135 v* v- |
|||
2swap 1 1 |
|||
2over 2 v** 6 13 v* v- |
|||
2over 4 v** 10 429 v* v+ |
|||
2swap 6 v** 4 19305 v* v- |
|||
v/ ] is tan ( n/d --> n/d ) |
|||
[ 2dup |
|||
2dup 3 v** 2318543 2278617 v* v- |
|||
2over 5 v** 12022609 60763120 v* v+ |
|||
2swap 1 1 |
|||
2over 2 v** 1798875 1519078 v* v- |
|||
2over 4 v** 3891575 12152624 v* v+ |
|||
2swap 6 v** 4695545 510410208 v* v- |
|||
v/ ] is arcsin ( n/d --> n/d ) |
|||
[ pi/2 2swap arcsin v- ] is arccos ( n/d --> n/d ) |
|||
[ 2dup |
|||
2dup 3 v** 50 39 v* v+ |
|||
2over 5 v** 283 715 v* v+ |
|||
2over 7 v** 256 15015 v* v+ |
|||
2swap 1 1 |
|||
2over 2 v** 21 13 v* v+ |
|||
2over 4 v** 105 143 v* v+ |
|||
2swap 6 v** 35 429 v* v+ |
|||
v/ ] is arctan ( n/d --> n/d ) |
|||
[ pi/2 v* 90 1 v/ ] is deg->rad ( n/d --> n/d ) |
|||
[ pi/2 v/ 90 1 v* ] is rad->deg ( n/d --> n/d ) |
|||
say "With an argument of 0.5 radians" |
|||
cr cr |
|||
$ "0.5" $->v drop |
|||
sin |
|||
say "Sin approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.47942553860420300027..." |
|||
cr cr |
|||
$ "0.5" $->v drop |
|||
cos |
|||
say "Cos approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.87758256189037271611..." |
|||
cr cr |
|||
$ "0.5" $->v drop |
|||
tan |
|||
say "Tan approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.54630248984379051325..." |
|||
cr cr cr |
|||
say "To radians, using approximated values from previous computations" |
|||
cr cr |
|||
$ "0.47942553860423933121" $->v drop |
|||
arcsin |
|||
say "Arcsin approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.5" |
|||
cr cr |
|||
$ "0.87758256189037190908" $->v drop |
|||
arccos |
|||
say "Arccos approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.5" |
|||
cr cr |
|||
$ "0.54630248984379037103" $->v drop |
|||
arctan |
|||
say "Arctan approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.5" |
|||
cr cr cr |
|||
say "0.5 radians is approx 28.64788976 degrees" cr |
|||
cr |
|||
$ "28.64788976" $->v drop |
|||
deg->rad sin |
|||
say "Sin approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.47942553865718102604..." |
|||
cr cr |
|||
$ "28.64788976" $->v drop |
|||
deg->rad cos |
|||
say "Cos approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.87758256186143068872..." |
|||
cr cr |
|||
$ "28.64788976" $->v drop |
|||
deg->rad tan |
|||
say "Tan approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 0.54630248992217530618..." |
|||
cr cr cr |
|||
say "To degrees, using approximated values from previous computations" |
|||
cr cr |
|||
$ "0.47942553865721735699" $->v drop |
|||
arcsin rad->deg |
|||
say "Arcsin approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 28.64788976..." |
|||
cr cr |
|||
$ "0.87758256186142988169" $->v drop |
|||
arccos rad->deg |
|||
say "Arccos approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 28.64788976..." |
|||
cr cr |
|||
$ "0.54630248992217516396" $->v drop |
|||
arctan rad->deg |
|||
say "Arctan approximation: " 20 point$ echo$ cr |
|||
say " Actual value: 28.64788976..."</lang> |
|||
{{out}} |
|||
<pre>With an argument of 0.5 radians |
|||
Sin approximation: 0.47942553860423933121 |
|||
Actual value: 0.47942553860420300027... |
|||
Cos approximation: 0.87758256189037190908 |
|||
Actual value: 0.87758256189037271611... |
|||
Tan approximation: 0.54630248984379037103 |
|||
Actual value: 0.54630248984379051325... |
|||
To radians, using approximated values from previous computations |
|||
Arcsin approximation: 0.49999997409078633068 |
|||
Actual value: 0.5 |
|||
Arccos approximation: 0.50090902435100642663 |
|||
Actual value: 0.5 |
|||
Arctan approximation: 0.50000000390223900073 |
|||
Actual value: 0.5 |
|||
0.5 radians is approx 28.64788976 degrees |
|||
Sin approximation: 0.47942553865721735699 |
|||
Actual value: 0.47942553865718102604... |
|||
Cos approximation: 0.87758256186142988169 |
|||
Actual value: 0.87758256186143068872... |
|||
Tan approximation: 0.54630248992217516396 |
|||
Actual value: 0.54630248992217530618... |
|||
To degrees, using approximated values from previous computations |
|||
Arcsin approximation: 28.64788827551140385372 |
|||
Actual value: 28.64788976... |
|||
Arccos approximation: 28.69997301874556855873 |
|||
Actual value: 28.64788976... |
|||
Arctan approximation: 28.64788998358182581534 |
|||
Actual value: 28.64788976... |
|||
Stack empty. |
|||
</pre> |
|||
=={{header|R}}== |
=={{header|R}}== |