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 }