Talk:Trigonometric functions

From Rosetta Code

Why are the last four pairs of numbers different for the ada example? The program was to use the same angle in degrees and radians so as long as the function is set for degrees or radians it should give the same number. --Mwn3d 07:14, 8 January 2008 (MST)

There is no error. 45 degrees is the same angle as 0.7854 (Pi/4) radians. A function set for radians cannot return degrees, and vice versa.--Waldorf 21:31, 8 January 2008 (MST)
Sorry. I think I was confused because the last two (arccot) seem to be exactly the same line of code. Am I crazy? --Mwn3d 21:36, 8 January 2008 (MST)
Theyŕe not exactly the same, but youŕe not crazy either. I think the line before New_Line; was intended to be
<code.Put(Item => Arccot(X => Cot(Angle_Radians, Radians_Cycle), Cycle => Radians_Cycle), Aft => 5, Exp => 0);
but what exists at present is not that. --TBH 22:16, 8 January 2008 (MST)

The Java example also seems to not fit the requirements for arcsin, arccos, and arctan. --TBH 11:16, 9 January 2008 (MST)

When I made the task I forgot that the arc functions return angles. Since they don't take an angle as an argument, I changed the Java example recently so that each function would print its answer in radians and degrees (even though they all start with different angles to get their arguments). I tried to make it more like the Ada example.--Mwn3d 11:38, 9 January 2008 (MST)
Ah! I had not noticed the clarified requirements. Now that I understand the requirements, I see that the answers are good for both the Ada and Java examples. The Perl code still needs fixing. The Ada code still has what seems to be an error, as I mentioned yesterday, but it does not affect the output. I've corrected the J code. --TBH 19:30, 9 January 2008 (MST)

odd formatting

I was trying to add code for IDL, but the "pre" tag doesn't seem to work quite like I expected. Can someone clarify?

Mediawiki's way of handling "pre" is broken. Try surrounding the "pre" block with <nowiki>/</nowiki>. --Short Circuit 01:00, 2 May 2008 (MDT)


Notes on precise sin implemented in Rexx

One of THE features of Rexx is the virtually unlimited numeric precision. Now if you want to get sin(0.1) with 30 precise digits (for whatever reason)

With Numeric Digits 30 sin as implemented in REXX trigonometric functions yields

  0.0998334166468281523068141984103

The implementation of sin in ooRexx' rxmath function yields

  0.09983341664682816   (this is restricted to 16 digits!)

when the precise value (50 digits) is

  0.099833416646828152306814198410622026989915388017978

which should be rounded to

  0.0998334166468281523068141984106

so both implementations above have an incorrect last digit

A possible remedy is to compute the function with a higher precision and then round the result to the desired one

ps=0.09983341664682815230681419841062199
   0.0998334166468281523068141984106

These lines come from

pSIN: procedure
/* Calculate sin(x) to the specified precision */
parse arg X, P
Numeric Digits (p+2)
ps=sin(x)
Say 'ps='ps
Numeric Digits p
Say '   '||(ps+0)
Return ps+0

--Walterpachl 19:43, 22 June 2012 (UTC)

Of course the Rexx implementation of sin could compute tthis higher precision and round it upon returning the value

That's what the REXX program shows. It adds 10 digits to the number of digits (precision) you want to see in the output.
Also, I long ago discovered that most trig and hyperbolic functions of this type usually require at least four extra (decimal) digits to be used (but only for some values that are near asymptotic points and others near multiples or fractions of pi. So I added one more digits to be on the safe side. Since then, I made the addition to an even five for a few hyperbolic functions and then did the same to the trig functions, but used ten here (on Rosetta Code) for safety's sake. -- Gerard Schildberger 20:55, 22 June 2012 (UTC)

I discussed this topic 10 years ago on Vladimir Zabrovsky's Album of (Rexx) algorithms which contains a wealth of code.

Did you change the REXX variable SHOWDIGS to 30? If so, I don't receive the same results you post. I assume you've must have cut and pasted from your own copy of the REXX program as the output format is much different. I would like to know what your results are for the REXX example as shown in Rosetta Code.


I get (for SHOWDIGS=30):

              rads= 0.1                              sin= 0.099833416646828152306814198    cos= 0.995004165278025766095561987    tan= 0.100334672085450545058080045

and the output (for SHOWDIGS=35):


              rads= 0.1                                   sin= 0.09983341664682815230681419841062    cos= 0.99500416527802576609556198780387    tan= 0.10033467208545054505808004578111

both of which required a modification to the REXX program; the code changes are: <lang rexx>/*REXX program demonstrates some common trig functions (30 digits shown)*/ showdigs=30 /*show only ten digits of number.*/ numeric digits showdigs+10 /*DIGITS default is 9, but use */

                                      /*extra digs to prevent rounding.*/

j=.1 /*just do 1/10 of a radian. for a special run. */

 stuff = '    '           '         rads='show(    (j)),
                                 '   sin='show(sin(j)),
                                 '   cos='show(cos(J))
                                           /*don't let  TAN  go postal.*/
 if abs(j)\==90 then stuff=stuff '   tan='show(tan(j))
 say stuff
.
.
.</lang>

This isn't probably the best forum to discuss these types of code (result) minutia when code is taken out of context or the modified code or driver code isn't shown to verify your results. I can be contacted via E-mail to iron out these details before large amounts of chatter are posted. -- Gerard Schildberger 20:55, 22 June 2012 (UTC)


It IS! I wanted to point out a problem and its solution. I don't think people want to understand the huge driver and its details (SHOWDIGS) but rather want to use the functions offered for their task.

---

The huge driver is mainly two statements with eight more to invoke the functions

<lang rexx>showdigs=30 /*show only 30 digits of number. */ numeric digits showdigs+10</lang> In my other "trig/hyperbolic/math" subroutine (not included here), I have 175 different functions, and
adding the REXX statements to bump the precision and re-nonormalize the result for each of the those
functions would be to burdensome. In most likehood, the re-normaliztion would be a waste of time if
the invocation program is performing a series of SIN calls, as indeed, the Rosetta Code example does.
The small program (here on Rosetta Code) only has 18 internal functions, and even that small number
would add a lot of code.
This type of REXX code (bumping the precision, re-normalizing) can't be consoliated because of the
manner in which REXX honors numeric digits between subroutine calls, so it's impossible to use a REXX
subroutine to avoid the repetitious code. Making 175 unique subroutines is one way of solving that problem,
but that's only a small fraction (well, ok, 1.2%) of the the total number of functions that my (written
elsewhere) trig/hyperbolic/math package has, but clearly, one can see the problem with adding that large a
number of external functions.
There is another problem with function name collision, which is another topic for another time.
So instead, I did what was suggested in the (prologue) commentary, that is: to increase the precision
higher than you need, and just use what precision you need from that time on. I added whitespace
around that part of the comments so you can more easily see what I said. If you want to use the SIN
SIN function and ignore the prologue (as far as intent), then you'll get what you programmed for.
This is basic REXX programming.
Your own code acknowledges that you need more precision than what you want, so the proglogue for the
REXX example does that with the showdigs variable, as the section and REXX code comments clearly
state. -- Gerard Schildberger 21:23, 23 June 2012 (UTC)

I did not modify anything! Just took sin (and the routines used by it) out of the rosetta-box and used it in my program as follows:

Numeric Digits 30
Say sin(0.1)
Numeric Digits 32
Say sin(0.1)
Exit
/******* procedures ex REXX trigonometric functions ***************************/
sin: procedure; arg x;  x=r2r(x);  numeric fuzz min(5,digits()-3)
                if abs(x)=pi() then return 0;   return .sinCos(x,x,1)
.sinCos: parse arg z 1 p,_,i;  x=x*x
         do k=2 by 2; _=-_*x/(k*(k+i));z=z+_;if z=p then leave;p=z;end; return z
r2r:   return arg(1)//(2*pi())         /*normalize radians?1 unit circle*/
pi: return,                            /*a bit of overkill,  but hey !! */
3.1415926535897932384626433832795028841971693993751058209749445923078164062862

The output is

0.0998334166468281523068141984103
0.099833416646828152306814198410619

What I want is that the first call gives me the 30 correct digits. This can be done by internally (in sin) raise the precision and return theresult rounded to the desired precision.

Note that external funtions don't inherit the caller's precision, so having an extra (optional) argument p is an option. Also the possiblity of x in sin(x) is radians or degrees is a useful extension implemented in the ooRexx function package. --Walterpachl 07:13, 23 June 2012 (UTC)


To not only ask for solutions, here is my version of sin according to my specs:

SIN: procedure
/**********************************************************************
* Return the value of sine in the inherited or specified precision
* a the argument in rad or degrees
* u unit of a ('R', blank. or not specified: radians)
*             ('D' degrees)
* p the desired precision of the result
* If not specified: The digits() of the caller (when internai procedure
*                   9, The default when external procedure
* 23.06.2012 Walter Pachl
**********************************************************************/
parse arg a,u,p
if P="" then                           /* p not specified            */
  P=digits()                           /* use digits of caller or 9  */
numeric digits (p+4)                   /* increase precision         */
pi=pi()
Select
  When u=' ' Then x=a                  /* not specified: radians     */
  When u='R' Then x=a                  /* radians                    */
  When u='D' Then                      /* degrees                    */
    x=a*pi/180                         /* convert to radians         */
  Otherwise Do
    Say 'Invalid second argument to sin ('u'),'
    Say 'must be R, D, or blank.'
    Signal Syntax
    End
  End
x=abs(x)                               /* sign considered later      */
f=1                                    /* factorial seed             */
term=x                                 /* first term                 */
Sum=x                                  /* first value                */
x2=x**2                                /* loop invariant x-square    */
do i=3 by 2                            /* now work the series        */
  f=i*(i-1)                            /* next factorial part        */
  term=-term*x2/f                      /* next term                  */
  NewSum=Sum+Term                      /* new value                  */
  If NewSum=Sum Then Leave             /* convergence reached        */
  Sum=NewSum                           /* remember the value         */
  End
Numeric Digits p                       /* switch to desired precision*/
Return sign(a)*(Sum+0)                 /* return rounded result      */
                                  /* considering the argument's sign */
PI: Return '3.14159265358979323846264338327950288419'||,
           '7169399375105820974944592307816406286208'||,
           '9986280348253421170679821480865132823066'||,
           '4709384460955058223172535940812848111745'||,
           '028410270193852110555964462294895493038196'

--Walterpachl 18:08, 23 June 2012 (UTC)