%= = = = = = = = = = = = = T R I G O N O M E T R Y . T E X = = = = = = = = = %%% Trigonometry.TeX: (as published in TeXhax Digest, September 1989) %%% Philip Taylor, Royal Holloway and Bedford New College, University of London %%% Routines to calculate the sine of an angle expressed in radians. %%% So far as I can tell, the results are accurate to four places %%% of decimals, for arguments in the range -pi/2 .. pi/2, except %%% for `ridiculously small' arguments, which cannot be accurately represented. %%% The routines for cosine and tangent are left to the reader ... %%% After a call to \Sin (), the result is available for typesetting %%% or boxing, and may also be extracted from the control-sequence \sine. %%% Grouping is used to hide most things, but the following csnames are %%% globally defined: %%% \nodimen, \n@dimen, \product, \sine, \term, \t@rm, \Term \newif \ifdebug %%% turn me on to see TeX hard at work ... \def \term #1{{x^{#1} \over #1!}} The power series expansion for $\sin$ is: $$ \sin x = x - \term3 + \term5 - \term7 + \cdots$$ \indent and for $\cos$ is: $$ \cos x = 1 - \term2 + \term4 - \term6 + \cdots$$ \let \then = \relax \chardef \letter = 11 \chardef \other = 12 \def \radian {pt } \let \radians = \radian \let \dimensionlessunit = \radian \let \dimensionlessunits = \dimensionlessunit \def \internalunit {sp } \let \internalunits = \internalunit \newif \ifstillconverging \def \Message #1{\ifdebug \then \message {#1} \fi} { %%% Things that need abnormal catcodes %%% \catcode `\@ = \letter \gdef \nodimen {\expandafter \n@dimen \the \dimen} \gdef \term #1 #2 #3% {\edef \t@ {\the #1}%%% freeze parameter 1 (count, by value) \edef \t@@ {\expandafter \n@dimen \the #2\radian}% %%% freeze parameter 2 (dimen, by value) \t@rm {\t@} {\t@@} {#3}% } \gdef \t@rm #1 #2 #3% {{% \count 0 = 0 \dimen 0 = 1 \dimensionlessunit \dimen 2 = #2\relax \Message {Calculating term #1 of \nodimen 2}% \loop \ifnum \count 0 < #1 \then \advance \count 0 by 1 \Message {Iteration \the \count 0 \space}% \Multiply \dimen 0 by {\dimen 2}% \Message {After multiplication, term = \nodimen 0}% \Divide \dimen 0 by {\count 0}% \Message {After division, term = \nodimen 0}% \repeat \Message {Final value for term #1 of \nodimen 2 \space is \nodimen 0}% \xdef \Term {#3 = \nodimen 0 \radians}% \aftergroup \Term }} \catcode `\p = \other \catcode `\t = \other \gdef \n@dimen #1pt{#1} %%% throw away the ``pt'' } \def \Divide #1by #2{\divide #1 by #2} %%% just a synonym \def \Multiply #1by #2%%% allows division of a dimen by a dimen {{%%% should really freeze parameter 2 (dimen, passed by value) \count 0 = #1\relax \count 2 = #2\relax \count 4 = 65536 \Message {Before scaling, count 0 = \the \count 0 \space and count 2 = \the \count 2}% \ifnum \count 0 > 32767 %%% do our best to avoid overflow \then \divide \count 0 by 4 \divide \count 4 by 4 \else \ifnum \count 0 < -32767 \then \divide \count 0 by 4 \divide \count 4 by 4 \else \fi \fi \ifnum \count 2 > 32767 %%% while retaining reasonable accuracy \then \divide \count 2 by 4 \divide \count 4 by 4 \else \ifnum \count 2 < -32767 \then \divide \count 2 by 4 \divide \count 4 by 4 \else \fi \fi \multiply \count 0 by \count 2 \divide \count 0 by \count 4 \xdef \product {#1 = \the \count 0 \internalunits}% \aftergroup \product }} \def \Sin (#1)% {{% \dimen 0 = #1 \radian \dimen 2 = 3.1415926535897963 \radian %%% a well-known constant \divide \dimen 2 by 2 %%% we only deal with -pi/2 : pi/2 \ifdim \dimen 0 > \dimen 2 \then \message {Sin: argument (\nodimen 0) too large --- use range reduction}% \xdef \sine {}% \else \ifdim \dimen 0 < - \dimen 2 \then \message {Sin: argument (\nodimen 0) too large --- use range reduction}% \xdef \sine {}% \else \Message {Sin: calculating Sin of \nodimen 0}% \count 0 = 1 %%% see power-series expansion for sine \dimen 2 = 1 \radian %%% ditto \dimen 4 = 0 \radian %%% ditto \loop \ifnum \dimen 2 = 0 %%% then we've done \then \stillconvergingfalse \else \stillconvergingtrue \fi \ifstillconverging %%% then calculate next term \then \term {\count 0} {\dimen 0} {\dimen 2}% \advance \count 0 by 2 \count 2 = \count 0 \divide \count 2 by 2 \ifodd \count 2 %%% signs alternate \then \advance \dimen 4 by \dimen 2 \else \advance \dimen 4 by -\dimen 2 \fi \repeat \xdef \sine {\nodimen 4}% \fi \fi \aftergroup \sine }} %%% What follows is just a demonstration of the \Sin function $$ \def \rule {\noalign {\hrule}} \def \SIN (#1){&&\Sin (#1)&\cr\noalign{\message {The sine of #1 is \sine}}} \mathcode `\- = 32768 %%% just a bodge to improve alignment \let \minus = - \begingroup \catcode `\- = \active \gdef -{\llap{\minus}} \endgroup \vbox {\offinterlineskip \halign {\vrule #& \qquad \hfil $#$ & \vrule # & \qquad $#$ \hfil & \vrule # \strut \cr \rule &\omit {\hfil $x$ \hfil} && \omit {\hfil $\sin x$ \hfil} & \cr \rule \SIN (-1.6) \SIN (-1.5) \SIN (-1.4) \SIN (-1.3) \SIN (-1.2) \SIN (-1.1) \SIN (-1.0) \SIN (-0.9) \SIN (-0.8) \SIN (-0.7) \SIN (-0.6) \SIN (-0.5) \SIN (-0.4) \SIN (-0.3) \SIN (-0.2) \SIN (-0.1) \SIN (-0.01) \SIN (-0.001) \SIN (-0.0001) \SIN (0) \SIN (0.0001) \SIN (0.001) \SIN (0.01) \SIN (0.1) \SIN (0.2) \SIN (0.3) \SIN (0.4) \SIN (0.5) \SIN (0.6) \SIN (0.7) \SIN (0.8) \SIN (0.9) \SIN (1.0) \SIN (1.1) \SIN (1.2) \SIN (1.3) \SIN (1.4) \SIN (1.5) \SIN (1.6) \rule} } $$ \end