1*4c3eb207Smrg /* Implementation of the degree trignometric functions COSD, SIND, TAND. 2*4c3eb207Smrg Copyright (C) 2020 Free Software Foundation, Inc. 3*4c3eb207Smrg Contributed by Steven G. Kargl <kargl@gcc.gnu.org> 4*4c3eb207Smrg 5*4c3eb207Smrg This file is part of the GNU Fortran runtime library (libgfortran). 6*4c3eb207Smrg 7*4c3eb207Smrg Libgfortran is free software; you can redistribute it and/or 8*4c3eb207Smrg modify it under the terms of the GNU General Public 9*4c3eb207Smrg License as published by the Free Software Foundation; either 10*4c3eb207Smrg version 3 of the License, or (at your option) any later version. 11*4c3eb207Smrg 12*4c3eb207Smrg Libgfortran is distributed in the hope that it will be useful, 13*4c3eb207Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of 14*4c3eb207Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*4c3eb207Smrg GNU General Public License for more details. 16*4c3eb207Smrg 17*4c3eb207Smrg Under Section 7 of GPL version 3, you are granted additional 18*4c3eb207Smrg permissions described in the GCC Runtime Library Exception, version 19*4c3eb207Smrg 3.1, as published by the Free Software Foundation. 20*4c3eb207Smrg 21*4c3eb207Smrg You should have received a copy of the GNU General Public License and 22*4c3eb207Smrg a copy of the GCC Runtime Library Exception along with this program; 23*4c3eb207Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24*4c3eb207Smrg <http://www.gnu.org/licenses/>. */ 25*4c3eb207Smrg 26*4c3eb207Smrg #include "libgfortran.h" 27*4c3eb207Smrg 28*4c3eb207Smrg #include <math.h> 29*4c3eb207Smrg 30*4c3eb207Smrg /* Body of library functions which are cannot be implemented on the current 31*4c3eb207Smrg * platform because it lacks a capability, such as an underlying trigonometric 32*4c3eb207Smrg * function (sin, cos, tan) or C99 floating-point function (fabs, fmod). */ 33*4c3eb207Smrg #define STRINGIFY_EXPAND(x) #x 34*4c3eb207Smrg #define ERROR_RETURN(f, k, x) runtime_error (#f " is unavailable for" \ 35*4c3eb207Smrg " REAL(KIND=" STRINGIFY_EXPAND(k) ") because the system math library" \ 36*4c3eb207Smrg " lacks support for it"); \ 37*4c3eb207Smrg RETURN(x) 38*4c3eb207Smrg 39*4c3eb207Smrg /* 40*4c3eb207Smrg For real x, let {x}_P or x_P be the closest representible number in the 41*4c3eb207Smrg floating point representation which uses P binary bits of fractional 42*4c3eb207Smrg precision (with IEEE rounding semantics). 43*4c3eb207Smrg 44*4c3eb207Smrg Similarly, let f_P(x) be shorthand for {f(x)}_P. 45*4c3eb207Smrg 46*4c3eb207Smrg Let ulp_P(x) be the unit of least precision for x: in other words the 47*4c3eb207Smrg maximal value of |a_P - b_P| where a_P <= x <= b_P and a_P != b_P. 48*4c3eb207Smrg 49*4c3eb207Smrg Let x ~= y <-> | x - y | < ulp_P(x - y). 50*4c3eb207Smrg 51*4c3eb207Smrg Let deg(x) be the value of x radians in degrees. 52*4c3eb207Smrg 53*4c3eb207Smrg Values for each precision P were selected as follows. 54*4c3eb207Smrg 55*4c3eb207Smrg 56*4c3eb207Smrg COSD_SMALL = 2**{-N} such that for all x <= COSD_SMALL: 57*4c3eb207Smrg 58*4c3eb207Smrg * cos(deg(x)) ~= 1, or equivalently: 59*4c3eb207Smrg 60*4c3eb207Smrg | 1 - cos(deg(x)) | < ulp_P(1). 61*4c3eb207Smrg 62*4c3eb207Smrg Unfortunately for SIND (and therefore TAND) a similar relation is only 63*4c3eb207Smrg possible for REAL(4) and REAL(8). With REAL(10) and REAL(16), enough 64*4c3eb207Smrg precision is available such that sin_P(x) != x_P for some x less than any 65*4c3eb207Smrg value. (There are values where this equality holds, but the distance has 66*4c3eb207Smrg inflection points.) 67*4c3eb207Smrg 68*4c3eb207Smrg For REAL(4) and REAL(8), we can select SIND_SMALL such that: 69*4c3eb207Smrg 70*4c3eb207Smrg * sin(deg(x)) ~= deg(x), or equivalently: 71*4c3eb207Smrg 72*4c3eb207Smrg | deg(x) - sin(deg(x)) | < ulp_P(deg(x)). 73*4c3eb207Smrg 74*4c3eb207Smrg */ 75*4c3eb207Smrg 76*4c3eb207Smrg #ifdef HAVE_GFC_REAL_4 77*4c3eb207Smrg 78*4c3eb207Smrg /* Build _gfortran_sind_r4, _gfortran_cosd_r4, and _gfortran_tand_r4 */ 79*4c3eb207Smrg 80*4c3eb207Smrg #define KIND 4 81*4c3eb207Smrg #define TINY 0x1.p-100 /* ~= 7.889e-31 */ 82*4c3eb207Smrg #define COSD_SMALL 0x1.p-7 /* = 7.8125e-3 */ 83*4c3eb207Smrg #define SIND_SMALL 0x1.p-5 /* = 3.125e-2 */ 84*4c3eb207Smrg #define COSD30 8.66025388e-01 85*4c3eb207Smrg #define PIO180H 1.74560547e-02 /* high 12 bits. */ 86*4c3eb207Smrg #define PIO180L -2.76216747e-06 /* Next 24 bits. */ 87*4c3eb207Smrg 88*4c3eb207Smrg #if defined(HAVE_FABSF) && defined(HAVE_FMODF) && defined(HAVE_COPYSIGNF) 89*4c3eb207Smrg 90*4c3eb207Smrg #ifdef HAVE_SINF 91*4c3eb207Smrg #define ENABLE_SIND 92*4c3eb207Smrg #endif 93*4c3eb207Smrg 94*4c3eb207Smrg #ifdef HAVE_COSF 95*4c3eb207Smrg #define ENABLE_COSD 96*4c3eb207Smrg #endif 97*4c3eb207Smrg 98*4c3eb207Smrg #ifdef HAVE_TANF 99*4c3eb207Smrg #define ENABLE_TAND 100*4c3eb207Smrg #endif 101*4c3eb207Smrg 102*4c3eb207Smrg #endif /* HAVE_FABSF && HAVE_FMODF && HAVE_COPYSIGNF */ 103*4c3eb207Smrg 104*4c3eb207Smrg #ifdef GFC_REAL_4_INFINITY 105*4c3eb207Smrg #define HAVE_INFINITY_KIND 106*4c3eb207Smrg #endif 107*4c3eb207Smrg 108*4c3eb207Smrg #include "trigd_lib.inc" 109*4c3eb207Smrg 110*4c3eb207Smrg #undef KIND 111*4c3eb207Smrg #undef TINY 112*4c3eb207Smrg #undef COSD_SMALL 113*4c3eb207Smrg #undef SIND_SMALL 114*4c3eb207Smrg #undef COSD30 115*4c3eb207Smrg #undef PIO180H 116*4c3eb207Smrg #undef PIO180L 117*4c3eb207Smrg #undef ENABLE_SIND 118*4c3eb207Smrg #undef ENABLE_COSD 119*4c3eb207Smrg #undef ENABLE_TAND 120*4c3eb207Smrg #undef HAVE_INFINITY_KIND 121*4c3eb207Smrg 122*4c3eb207Smrg #endif /* HAVE_GFC_REAL_4... */ 123*4c3eb207Smrg 124*4c3eb207Smrg 125*4c3eb207Smrg #ifdef HAVE_GFC_REAL_8 126*4c3eb207Smrg 127*4c3eb207Smrg /* Build _gfortran_sind_r8, _gfortran_cosd_r8, and _gfortran_tand_r8 */ 128*4c3eb207Smrg 129*4c3eb207Smrg #define KIND 8 130*4c3eb207Smrg #define TINY 0x1.p-1000 /* ~= 9.33e-302 (min exp -1074) */ 131*4c3eb207Smrg #define COSD_SMALL 0x1.p-21 /* ~= 4.768e-7 */ 132*4c3eb207Smrg #define SIND_SMALL 0x1.p-19 /* ~= 9.537e-7 */ 133*4c3eb207Smrg #define COSD30 8.6602540378443860e-01 134*4c3eb207Smrg #define PIO180H 1.7453283071517944e-02 /* high 21 bits. */ 135*4c3eb207Smrg #define PIO180L 9.4484253514332993e-09 /* Next 53 bits. */ 136*4c3eb207Smrg 137*4c3eb207Smrg #if defined(HAVE_FABS) && defined(HAVE_FMOD) && defined(HAVE_COPYSIGN) 138*4c3eb207Smrg 139*4c3eb207Smrg #ifdef HAVE_SIN 140*4c3eb207Smrg #define ENABLE_SIND 141*4c3eb207Smrg #endif 142*4c3eb207Smrg 143*4c3eb207Smrg #ifdef HAVE_COS 144*4c3eb207Smrg #define ENABLE_COSD 145*4c3eb207Smrg #endif 146*4c3eb207Smrg 147*4c3eb207Smrg #ifdef HAVE_TAN 148*4c3eb207Smrg #define ENABLE_TAND 149*4c3eb207Smrg #endif 150*4c3eb207Smrg 151*4c3eb207Smrg #endif /* HAVE_FABS && HAVE_FMOD && HAVE_COPYSIGN */ 152*4c3eb207Smrg 153*4c3eb207Smrg #ifdef GFC_REAL_8_INFINITY 154*4c3eb207Smrg #define HAVE_INFINITY_KIND 155*4c3eb207Smrg #endif 156*4c3eb207Smrg 157*4c3eb207Smrg #include "trigd_lib.inc" 158*4c3eb207Smrg 159*4c3eb207Smrg #undef KIND 160*4c3eb207Smrg #undef TINY 161*4c3eb207Smrg #undef COSD_SMALL 162*4c3eb207Smrg #undef SIND_SMALL 163*4c3eb207Smrg #undef COSD30 164*4c3eb207Smrg #undef PIO180H 165*4c3eb207Smrg #undef PIO180L 166*4c3eb207Smrg #undef ENABLE_SIND 167*4c3eb207Smrg #undef ENABLE_COSD 168*4c3eb207Smrg #undef ENABLE_TAND 169*4c3eb207Smrg #undef HAVE_INFINITY_KIND 170*4c3eb207Smrg 171*4c3eb207Smrg #endif /* HAVE_GFC_REAL_8... */ 172*4c3eb207Smrg 173*4c3eb207Smrg 174*4c3eb207Smrg #ifdef HAVE_GFC_REAL_10 175*4c3eb207Smrg 176*4c3eb207Smrg /* Build _gfortran_sind_r10, _gfortran_cosd_r10, and _gfortran_tand_r10 */ 177*4c3eb207Smrg 178*4c3eb207Smrg #define KIND 10 179*4c3eb207Smrg #define TINY 0x1.p-16400 /* ~= 1.28e-4937 (min exp -16494) */ 180*4c3eb207Smrg #define COSD_SMALL 0x1.p-26 /* ~= 1.490e-8 */ 181*4c3eb207Smrg #undef SIND_SMALL /* not precise */ 182*4c3eb207Smrg #define COSD30 8.66025403784438646787e-01 183*4c3eb207Smrg #define PIO180H 1.74532925229868851602e-02 /* high 32 bits */ 184*4c3eb207Smrg #define PIO180L -3.04358939097084072823e-12 /* Next 64 bits */ 185*4c3eb207Smrg 186*4c3eb207Smrg #if defined(HAVE_FABSL) && defined(HAVE_FMODL) && defined(HAVE_COPYSIGNL) 187*4c3eb207Smrg 188*4c3eb207Smrg #ifdef HAVE_SINL 189*4c3eb207Smrg #define ENABLE_SIND 190*4c3eb207Smrg #endif 191*4c3eb207Smrg 192*4c3eb207Smrg #ifdef HAVE_COSL 193*4c3eb207Smrg #define ENABLE_COSD 194*4c3eb207Smrg #endif 195*4c3eb207Smrg 196*4c3eb207Smrg #ifdef HAVE_TANL 197*4c3eb207Smrg #define ENABLE_TAND 198*4c3eb207Smrg #endif 199*4c3eb207Smrg 200*4c3eb207Smrg #endif /* HAVE_FABSL && HAVE_FMODL && HAVE_COPYSIGNL */ 201*4c3eb207Smrg 202*4c3eb207Smrg #ifdef GFC_REAL_10_INFINITY 203*4c3eb207Smrg #define HAVE_INFINITY_KIND 204*4c3eb207Smrg #endif 205*4c3eb207Smrg 206*4c3eb207Smrg #include "trigd_lib.inc" 207*4c3eb207Smrg 208*4c3eb207Smrg #undef KIND 209*4c3eb207Smrg #undef TINY 210*4c3eb207Smrg #undef COSD_SMALL 211*4c3eb207Smrg #undef SIND_SMALL 212*4c3eb207Smrg #undef COSD30 213*4c3eb207Smrg #undef PIO180H 214*4c3eb207Smrg #undef PIO180L 215*4c3eb207Smrg #undef ENABLE_SIND 216*4c3eb207Smrg #undef ENABLE_COSD 217*4c3eb207Smrg #undef ENABLE_TAND 218*4c3eb207Smrg #undef HAVE_INFINITY_KIND 219*4c3eb207Smrg 220*4c3eb207Smrg #endif /* HAVE_GFC_REAL_10 */ 221*4c3eb207Smrg 222*4c3eb207Smrg 223*4c3eb207Smrg #ifdef HAVE_GFC_REAL_16 224*4c3eb207Smrg 225*4c3eb207Smrg /* Build _gfortran_sind_r16, _gfortran_cosd_r16, and _gfortran_tand_r16 */ 226*4c3eb207Smrg 227*4c3eb207Smrg #define KIND 16 228*4c3eb207Smrg #define TINY 0x1.p-16400 /* ~= 1.28e-4937 */ 229*4c3eb207Smrg #undef SIND_SMALL /* not precise */ 230*4c3eb207Smrg 231*4c3eb207Smrg #if GFC_REAL_16_DIGITS == 64 232*4c3eb207Smrg /* 80 bit precision, use constants from REAL(10). */ 233*4c3eb207Smrg #define COSD_SMALL 0x1.p-26 /* ~= 1.490e-8 */ 234*4c3eb207Smrg #define COSD30 8.66025403784438646787e-01 235*4c3eb207Smrg #define PIO180H 1.74532925229868851602e-02 /* high 32 bits */ 236*4c3eb207Smrg #define PIO180L -3.04358939097084072823e-12 /* Next 64 bits */ 237*4c3eb207Smrg 238*4c3eb207Smrg #else 239*4c3eb207Smrg /* Proper float128 precision. */ 240*4c3eb207Smrg #define COSD_SMALL 0x1.p-51 /* ~= 4.441e-16 */ 241*4c3eb207Smrg #define COSD30 8.66025403784438646763723170752936183e-01 242*4c3eb207Smrg #define PIO180H 1.74532925199433197605003442731685936e-02 243*4c3eb207Smrg #define PIO180L -2.39912634365882824665106671063098954e-17 244*4c3eb207Smrg #endif 245*4c3eb207Smrg 246*4c3eb207Smrg #ifdef GFC_REAL_16_IS_LONG_DOUBLE 247*4c3eb207Smrg 248*4c3eb207Smrg #if defined(HAVE_FABSL) && defined(HAVE_FMODL) && defined(HAVE_COPYSIGNL) 249*4c3eb207Smrg 250*4c3eb207Smrg #ifdef HAVE_SINL 251*4c3eb207Smrg #define ENABLE_SIND 252*4c3eb207Smrg #endif 253*4c3eb207Smrg 254*4c3eb207Smrg #ifdef HAVE_COSL 255*4c3eb207Smrg #define ENABLE_COSD 256*4c3eb207Smrg #endif 257*4c3eb207Smrg 258*4c3eb207Smrg #ifdef HAVE_TANL 259*4c3eb207Smrg #define ENABLE_TAND 260*4c3eb207Smrg #endif 261*4c3eb207Smrg 262*4c3eb207Smrg #endif /* HAVE_FABSL && HAVE_FMODL && HAVE_COPYSIGNL */ 263*4c3eb207Smrg 264*4c3eb207Smrg #else 265*4c3eb207Smrg 266*4c3eb207Smrg /* libquadmath: HAVE_*Q are never defined. They must be available. */ 267*4c3eb207Smrg #define ENABLE_SIND 268*4c3eb207Smrg #define ENABLE_COSD 269*4c3eb207Smrg #define ENABLE_TAND 270*4c3eb207Smrg 271*4c3eb207Smrg #endif /* GFC_REAL_16_IS_LONG_DOUBLE */ 272*4c3eb207Smrg 273*4c3eb207Smrg #ifdef GFC_REAL_16_INFINITY 274*4c3eb207Smrg #define HAVE_INFINITY_KIND 275*4c3eb207Smrg #endif 276*4c3eb207Smrg 277*4c3eb207Smrg #include "trigd_lib.inc" 278*4c3eb207Smrg 279*4c3eb207Smrg #undef KIND 280*4c3eb207Smrg #undef TINY 281*4c3eb207Smrg #undef COSD_SMALL 282*4c3eb207Smrg #undef SIND_SMALL 283*4c3eb207Smrg #undef COSD30 284*4c3eb207Smrg #undef PIO180H 285*4c3eb207Smrg #undef PIO180L 286*4c3eb207Smrg #undef ENABLE_SIND 287*4c3eb207Smrg #undef ENABLE_COSD 288*4c3eb207Smrg #undef ENABLE_TAND 289*4c3eb207Smrg #undef HAVE_INFINITY_KIND 290*4c3eb207Smrg 291*4c3eb207Smrg #endif /* HAVE_GFC_REAL_16 */ 292