File indexing completed on 2024-05-12 05:55:15

0001 /* floattrig.c: trigonometry functions, based on floatnum. */
0002 /*
0003     Copyright (C) 2007, 2008 Wolf Lammen.
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License , or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; see the file COPYING.  If not, write to:
0017 
0018       The Free Software Foundation, Inc.
0019       59 Temple Place, Suite 330
0020       Boston, MA 02111-1307 USA.
0021 
0022 
0023     You may contact the author by:
0024        e-mail:  ookami1 <at> gmx <dot> de
0025        mail:  Wolf Lammen
0026               Oertzweg 45
0027               22307 Hamburg
0028               Germany
0029 
0030 *************************************************************************/
0031 
0032 #include "floattrig.h"
0033 #include "floatseries.h"
0034 #include "floatconst.h"
0035 #include "floatcommon.h"
0036 
0037 /* evaluates arctan x for |x| <= 1
0038    relative error for a 100 digit result is 6e-100 */
0039 void
0040 _arctanlt1(
0041   floatnum x,
0042   int digits)
0043 {
0044   floatstruct tmp;
0045   int reductions;
0046 
0047   if (float_iszero(x))
0048     return;
0049   float_create(&tmp);
0050   reductions = 0;
0051   while(float_getexponent(x) >= -2)
0052   {
0053     float_mul(&tmp, x, x, digits);
0054     float_add(&tmp, &tmp, &c1, digits+2);
0055     float_sqrt(&tmp, digits);
0056     float_add(&tmp, &tmp, &c1, digits+1);
0057     float_div(x, x, &tmp, digits);
0058     ++reductions;
0059   }
0060   arctannear0(x, digits);
0061   for (;reductions-- > 0;)
0062     float_add(x, x, x, digits+1);
0063   float_free(&tmp);
0064 }
0065 
0066 /* evaluates arctan x for all x. The result is in the
0067    range -pi/2 < result < pi/2
0068    relative error for a 100 digit result is 9e-100 */
0069 void
0070 _arctan(
0071   floatnum x,
0072   int digits)
0073 {
0074   signed char sgn;
0075 
0076   if (float_abscmp(x, &c1) > 0)
0077   {
0078     sgn = float_getsign(x);
0079     float_abs(x);
0080     float_reciprocal(x, digits);
0081     _arctanlt1(x, digits);
0082     float_sub(x, &cPiDiv2, x, digits+1);
0083     float_setsign(x, sgn);
0084   }
0085   else
0086     _arctanlt1(x, digits);
0087 }
0088 
0089 /* evaluates arccos(1+x) for -0.5 <= x <= 0
0090    arccos(1+x) = arctan(sqrt(-x*(2+x))/(1+x))
0091    the relative error of a 100 digit result is < 5e-100 */
0092 void
0093 _arccosxplus1lt0_5(
0094   floatnum x,
0095   int digits)
0096 {
0097   floatstruct tmp;
0098 
0099   float_create(&tmp);
0100   float_add(&tmp, x, &c2, digits+1);
0101   float_mul(x, x, &tmp, digits+1);
0102   float_setsign(x, 1);
0103   float_sqrt(x, digits);
0104   float_sub(&tmp, &tmp, &c1, digits);
0105   float_div(x, x, &tmp, digits+1);
0106   _arctan(x, digits);
0107   float_free(&tmp);
0108 }
0109 
0110 /* evaluates arcsin x for -0.5 <= x <= 0.5
0111    arcsin x = arctan(x/sqrt(1-x*x))
0112    the relative error of a 100 digit result is < 5e-100 */
0113 void
0114 _arcsinlt0_5(
0115   floatnum x,
0116   int digits)
0117 {
0118   floatstruct tmp;
0119 
0120   if (2*float_getexponent(x) < -digits)
0121     return;
0122   float_create(&tmp);
0123   float_mul(&tmp, x, x, digits);
0124   float_sub(&tmp, &c1, &tmp, digits);
0125   float_sqrt(&tmp, digits);
0126   float_div(x, x, &tmp, digits+1);
0127   _arctanlt1(x, digits);
0128   float_free(&tmp);
0129 }
0130 
0131 /* evaluates arccos x for -1 <= x <= 1.
0132    The result is in the range 0 <= result <= pi.
0133    The relative error for a 100 digit result is < 5e-100 */
0134 void
0135 _arccos(
0136   floatnum x,
0137   int digits)
0138 {
0139   signed char sgn;
0140 
0141   sgn = float_getsign(x);
0142   float_abs(x);
0143   if (float_cmp(x, &c1Div2) > 0)
0144   {
0145     float_sub(x, x, &c1, digits+1);
0146     _arccosxplus1lt0_5(x, digits);
0147   }
0148   else
0149   {
0150     _arcsinlt0_5(x, digits);
0151     float_sub(x, &cPiDiv2, x, digits+1);
0152   }
0153   if (sgn < 0)
0154     float_sub(x, &cPi, x, digits+1);
0155 }
0156 
0157 /* evaluates arccos (1+x) for -2 <= x <= 0.
0158    The result is in the range 0 <= x <= pi */
0159 void
0160 _arccosxplus1(
0161   floatnum x,
0162   int digits)
0163 {
0164   if (float_abscmp(x, &c1Div2) <= 0)
0165     _arccosxplus1lt0_5(x, digits);
0166   else
0167   {
0168     float_add(x, x, &c1, digits);
0169     _arccos(x, digits);
0170   }
0171 }
0172 
0173 /* evaluates arcsin x for -1 <= x <= 1.
0174    The result is in the range -pi/2 <= result <= pi/2 
0175    The relative error for a 100 digit result is < 8e-100 */
0176 void
0177 _arcsin(
0178   floatnum x,
0179   int digits)
0180 {
0181   signed char sgn;
0182 
0183   if (float_abscmp(x, &c1Div2) <= 0)
0184     _arcsinlt0_5(x, digits);
0185   else
0186   {
0187     sgn = float_getsign(x);
0188     float_abs(x);
0189     _arccos(x, digits);
0190     float_sub(x, &cPiDiv2, x, digits);
0191     float_setsign(x, sgn);
0192   }
0193 }
0194 
0195 /* evaluates cos x - 1 for x < |pi/4|
0196    relative error for 100 digit results is < 5e-100 */
0197 
0198 char
0199 _cosminus1ltPiDiv4(
0200   floatnum x,
0201   int digits)
0202 {
0203   floatstruct tmp;
0204   int reductions;
0205 
0206   if (float_iszero(x))
0207     return 1;
0208   float_abs(x);
0209   reductions = 0;
0210   while(float_getexponent(x) >= -2)
0211   {
0212     float_mul(x, x, &c1Div2, digits+1);
0213     ++reductions;
0214   }
0215   if (!cosminus1near0(x, digits) && reductions == 0)
0216     return !float_iszero(x);
0217   float_create(&tmp);
0218   for(; reductions-- > 0;)
0219   {
0220     float_mul(&tmp, x, x, digits);
0221     float_add(x, x, x, digits+2);
0222     float_add(x, x, &tmp, digits+2);
0223     float_add(x, x, x, digits+2);
0224   }
0225   float_free(&tmp);
0226   return 1;
0227 }
0228 
0229 /* evaluate sin x for |x| <= pi/4,
0230    using |sin x| = sqrt((1-cos x)*(2 + cos x-1)) 
0231    relative error for 100 digit results is < 6e-100*/
0232 void
0233 _sinltPiDiv4(
0234   floatnum x,
0235   int digits)
0236 {
0237   floatstruct tmp;
0238   signed char sgn;
0239 
0240   if (2*float_getexponent(x)+2 < -digits)
0241     /* for small x: sin x approx.== x */
0242     return;
0243   float_create(&tmp);
0244   sgn = float_getsign(x);
0245   _cosminus1ltPiDiv4(x, digits);
0246   float_add(&tmp, x, &c2, digits+1);
0247   float_mul(x, x, &tmp, digits+1);
0248   float_abs(x);
0249   float_sqrt(x, digits);
0250   float_setsign(x, sgn);
0251   float_free(&tmp);
0252 }
0253 
0254 /* evaluates tan x for |x| <= pi/4.
0255    The relative error for a 100 digit result is < 6e-100 */
0256 
0257 void
0258 _tanltPiDiv4(
0259   floatnum x,
0260   int digits)
0261 {
0262   floatstruct tmp;
0263   signed char sgn;
0264 
0265   if (2*float_getexponent(x)+2 < -digits)
0266     /* for small x: tan x approx.== x */
0267     return;
0268   float_create(&tmp);
0269   sgn = float_getsign(x);
0270   _cosminus1ltPiDiv4(x, digits);
0271   float_add(&tmp, x, &c2, digits+1);
0272   float_mul(x, x, &tmp, digits+1);
0273   float_abs(x);
0274   float_sqrt(x, digits);
0275   float_sub(&tmp, &tmp, &c1, digits);
0276   float_div(x, x, &tmp, digits+1);
0277   float_setsign(x, sgn);
0278   float_free(&tmp);
0279 }
0280 
0281 /* evaluates cos x for |x| <= pi */
0282 
0283 void
0284 _cos(
0285   floatnum x,
0286   int digits)
0287 {
0288   signed char sgn;
0289 
0290   float_abs(x);
0291   sgn = 1;
0292   if (float_cmp(x, &cPiDiv2) > 0)
0293   {
0294     sgn = -1;
0295     float_sub(x, &cPi, x, digits+1);
0296   }
0297   if (float_cmp(x, &cPiDiv4) <= 0)
0298   {
0299     if (2*float_getexponent(x)+2 < - digits)
0300       float_setzero(x);
0301     else
0302       _cosminus1ltPiDiv4(x, digits);
0303     float_add(x, x, &c1, digits);
0304   }
0305   else
0306   {
0307     float_sub(x, &cPiDiv2, x, digits+1);
0308     _sinltPiDiv4(x, digits);
0309   }
0310   float_setsign(x, sgn);
0311 }
0312 
0313 /* evaluates cos x - 1 for |x| <= pi.
0314    This function may underflow, which
0315    is indicated by the return value 0 */
0316 char
0317 _cosminus1(
0318   floatnum x,
0319   int digits)
0320 {
0321   float_abs(x);
0322   if (float_cmp(x, &cPiDiv4) <= 0)
0323     return _cosminus1ltPiDiv4(x, digits);
0324   _cos(x, digits);
0325   float_sub(x, x, &c1, digits);
0326   return 1;
0327 }
0328 
0329 /* evaluates sin x for |x| <= pi. */
0330 void
0331 _sin(
0332   floatnum x,
0333   int digits)
0334 {
0335   signed char sgn;
0336 
0337   sgn = float_getsign(x);
0338   float_abs(x);
0339   if (float_cmp(x, &cPiDiv2) > 0)
0340     float_sub(x, &cPi, x, digits+1);
0341   if (float_cmp(x, &cPiDiv4) <= 0)
0342     _sinltPiDiv4(x, digits);
0343   else
0344   {
0345     float_sub(x, &cPiDiv2, x, digits+1);
0346     if (2*float_getexponent(x)+2 < - digits)
0347       float_setzero(x);
0348     else
0349       _cosminus1ltPiDiv4(x, digits);
0350     float_add(x, x, &c1, digits);
0351   }
0352   float_setsign(x, sgn);
0353 }
0354 
0355 /* evaluates tan x for |x| <= pi.
0356    A return value of 0 indicates
0357    that x = +/- pi/2 within
0358    small tolerances, so that tan x
0359    cannot be reliable computed */
0360 char
0361 _tan(
0362   floatnum x,
0363   int digits)
0364 {
0365   signed char sgn;
0366 
0367   sgn = float_getsign(x);
0368   float_abs(x);
0369   if (float_cmp(x, &cPiDiv2) > 0)
0370   {
0371     float_sub(x, &cPi, x, digits+1);
0372     sgn = -sgn;
0373   }
0374   if (float_cmp(x, &cPiDiv4) <= 0)
0375     _tanltPiDiv4(x, digits);
0376   else
0377   {
0378     float_sub(x, &cPiDiv2, x, digits+1);
0379     if (float_iszero(x) || float_getexponent(x) < -digits)
0380       return 0;
0381     _tanltPiDiv4(x, digits);
0382     float_reciprocal(x, digits);
0383   }
0384   float_setsign(x, sgn);
0385   return 1;
0386 }
0387 
0388 char
0389 _trigreduce(
0390   floatnum x,
0391   int digits)
0392 {
0393   floatstruct tmp;
0394   int expx, save;
0395   signed char sgn;
0396   char odd;
0397 
0398   if (float_abscmp(x, &cPi) <= 0)
0399     return 1;
0400   expx = float_getexponent(x);
0401   if (expx > float_getlength(&cPi) - digits)
0402     return 0;
0403   save = float_setprecision(MAXDIGITS);
0404   float_create(&tmp);
0405   sgn = float_getsign(x);
0406   float_abs(x);
0407   float_divmod(&tmp, x, x, &cPi, INTQUOT);
0408   float_setprecision(save);
0409   odd = float_isodd(&tmp);
0410   if (odd)
0411     float_sub(x, x, &cPi, digits+1);
0412   if (sgn < 0)
0413     float_neg(x);
0414   float_free(&tmp);
0415   return 1;
0416 }
0417 
0418 void
0419 _sinpix(
0420   floatnum x,
0421   int digits)
0422 {
0423   char odd;
0424 
0425   odd = float_isodd(x);
0426   float_frac(x);
0427   float_mul(x, &cPi, x, digits+1);
0428   _sin(x, digits);
0429   if (odd)
0430     float_neg(x);
0431 }