this repo has no description
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*******************************************************************************
23* *
24* File atan2.c, *
25* Function atan2(y/x), *
26* Implementation of arc tangent of ( y / x ) for the PowerPC. *
27* *
28* Copyright c 1991-2001 Apple Computer, Inc. All rights reserved. *
29* *
30* Written by Ali Sazegari, started on November 1991, *
31* Modified and ported by Robert A. Murley (ram) for Mac OS X. *
32* *
33* A MathLib v4 file. *
34* *
35* December 03 1992: first rs6000 port. *
36* January 05 1993: added the environmental controls. *
37* July 07 1993: fixed the argument of __fpclassifyd. *
38* July 11 1993: changed feholdexcept to _feprocentry to set rounding *
39* to zero. removed the constant nan, fixed all edge *
40* cases to reflect the fpce-nceg requirements. *
41* September19 1994: changed all the environemntal enquiries to __setflm. *
42* October 06 1994: initialized CurrentEnvironment to correct an invalid *
43* flag problem. *
44* July 23 2001: replaced __setflm with FEGETENVD/FESETENVD; *
45* replaced DblInHex typedef with hexdouble. *
46* September 07 2001: added #ifdef __ppc__. *
47* September 09 2001: added more comments. *
48* September 10 2001: added macros to detect PowerPC and correct compiler. *
49* September 18 2001: added <CoreServices/CoreServices.h> to get to <fp.h> *
50* and <fenv.h>. *
51* September 25 2001: removed fenv_access pragma. *
52* October 05 2001: added const double pi. *
53* October 08 2001: removed <CoreServices/CoreServices.h>. *
54* changed compiler errors to warnings. *
55* November 06 2001: commented out warning about Intel architectures. *
56* *
57* W A R N I N G: *
58* These routines require a 64-bit double precision IEEE-754 model. *
59* They are written for PowerPC only and are expecting the compiler *
60* to generate the correct sequence of multiply-add fused instructions. *
61* *
62* These routines are not intended for 32-bit Intel architectures. *
63* *
64* A version of gcc higher than 932 is required. *
65* *
66* GCC compiler options: *
67* optimization level 3 (-O3) *
68* -fschedule-insns -finline-functions -funroll-all-loops *
69* *
70*******************************************************************************/
71
72#include "math.h"
73#include "fenv_private.h"
74#include "fp_private.h"
75
76/*******************************************************************************
77* Functions needed for the computation. *
78*******************************************************************************/
79
80/* the following fp.h functions are used: */
81/* atan, __fpclassifyd, copysign and __signbitd. */
82
83/*******************************************************************************
84* This function is odd. The positive interval is computed and for *
85* negative values, the sign is reflected in the computation. *
86*******************************************************************************/
87static const double kMinNormal = 0x1.0p-1022; // 2.2250738585072014e-308;
88static const double kMaxNormal = 1.7976931348623157e308;
89static const double kHalf = 0.5;
90
91extern double atanCore ( double );
92extern double atanCoreInv ( double );
93
94double atan2 ( double y, double x )
95{
96 register double result;
97 register double FPR_env, FPR_z, FPR_half, FPR_pi, FPR_kMinNormal, FPR_kMaxNormal, FPR_absx, FPR_absy, FPR_t;
98
99 FPR_z = 0.0;
100
101/*******************************************************************************
102* If argument is SNaN then a QNaN has to be returned and the invalid *
103* flag signaled. *
104*******************************************************************************/
105
106 if (unlikely( ( x != x ) || ( y != y ) ))
107 return x + y;
108
109 FEGETENVD( FPR_env );
110 FESETENVD( FPR_z );
111
112 __NOOP; // takes slot 0 following the mtfsf
113 FPR_t = y / x; // takes slot 1 (hence fpu1) following the mtfsf
114 FPR_pi = M_PI;
115
116 FPR_kMinNormal = kMinNormal; FPR_kMaxNormal = kMaxNormal;
117
118 FPR_absy = __FABS ( y );
119 FPR_half = kHalf;
120 FPR_absx = __FABS ( x );
121
122/*******************************************************************************
123* The next switch will decipher what sort of argument we have: *
124* *
125* atan2 ( �0, x ) = �0, if x > 0, *
126* atan2 ( �0, +0) = �0, *
127* atan2 ( �0, x ) = ��, if x < 0, *
128* atan2 ( �0, -0) = ��, *
129* atan2 ( y, �0 ) = �/2, if y > 0, *
130* atan2 ( y, �0 ) = -�/2, if y < 0, *
131* atan2 ( �y, � ) = �0, for finite y > 0, *
132* atan2 ( ��, x ) = ��/2, for finite x, *
133* atan2 ( �y, -�) = ��, for finite y > 0, *
134* atan2 ( ��, � ) = ��/4, *
135* atan2 ( ��, -�) = �3�/4. *
136* *
137* note that the non obvious cases are y and x both infinite or both zero. *
138* for more information, see �Branch Cuts for Complex Elementary Functions, *
139* or much Much Ado About Nothing�s Sign bit�, by W. Kahan, Proceedings of *
140* the joint IMA/SIAM conference on The state of the Art in Numerical *
141* Analysis, 14-18 April 1986, Clarendon Press (1987). *
142* *
143* atan2(y,0) does not raise the divide-by-zero exception, nor does *
144* atan2(0,0) raise the invalid exception. *
145*******************************************************************************/
146
147 if (likely( FPR_absx <= FPR_kMaxNormal )) // slot 0 hence fpu0
148 {
149 if (unlikely( x == FPR_z )) // slot 0 hence fpu 0
150 {
151 if ( y > FPR_z )
152 result = __FMUL( FPR_half, FPR_pi );
153 else if ( y < FPR_z )
154 result = __FMUL( -FPR_half, FPR_pi );
155 else
156 {
157 if ( signbit ( x ) ) // x is +-0
158 result = copysign ( FPR_pi, y ); // y is +-0
159 else
160 {
161 FESETENVD( FPR_env );
162 return y; // Exact zero result.
163 }
164 }
165 FESETENVD( FPR_env );
166 __PROG_INEXACT( FPR_pi );
167 return result;
168 }
169 }
170 else
171 { // Infinite x
172 if ( x > FPR_z )
173 {
174 if ( FPR_absy <= FPR_kMaxNormal )
175 {
176 FESETENVD( FPR_env );
177 result = copysign ( FPR_z, y );
178 return result;
179 }
180 else
181 {
182 if ( y > FPR_z )
183 result = __FMUL( 0.25f, FPR_pi );
184 else
185 result = __FMUL( -0.25f, FPR_pi );
186 }
187 }
188 else
189 {
190 if ( FPR_absy <= FPR_kMaxNormal )
191 result = copysign ( FPR_pi, y );
192 else
193 {
194 if ( y > FPR_z )
195 result = __FMUL( 0.75f, FPR_pi );
196 else
197 result = __FMUL( -0.75f, FPR_pi );
198 }
199 }
200 FESETENVD( FPR_env );
201 __PROG_INEXACT( FPR_pi );
202 return result;
203 }
204
205 if (likely( FPR_absy <= FPR_kMaxNormal ))
206 {
207 if (unlikely( y == FPR_z ))
208 {
209 if ( x > FPR_z )
210 {
211 FESETENVD( FPR_env );
212 return y;
213 }
214 else
215 result = copysign ( FPR_pi, y ); // y is +-0
216
217 FESETENVD( FPR_env );
218 __PROG_INEXACT( FPR_pi );
219 return result;
220 }
221 }
222 else
223 { // Infinite y
224 if ( y > FPR_z )
225 result = __FMUL( FPR_half, FPR_pi );
226 else
227 result = __FMUL( -FPR_half, FPR_pi );
228 FESETENVD( FPR_env );
229 __PROG_INEXACT( FPR_pi );
230 return result;
231 }
232
233/*******************************************************************************
234* End of the special case section. atan2 is mostly a collection of special *
235* case functions. Next we will carry out the main computation which at *
236* this point will only receive non-zero normal or denormal numbers. *
237*******************************************************************************/
238 if (FPR_absy > FPR_absx)
239 result = atanCoreInv ( __FABS( FPR_t ) );
240 else
241 result = atanCore ( __FABS( FPR_t ) );
242
243 if ( x < FPR_z )
244 result = FPR_pi - result;
245
246 FPR_t = __FABS( result );
247
248 FESETENVD( FPR_env );
249 if ( FPR_t >= FPR_kMinNormal || FPR_t == FPR_z )
250 __PROG_INEXACT( FPR_pi );
251 else
252 __PROG_UF_INEXACT( FPR_kMinNormal );
253
254 if ( y > FPR_z )
255 return result;
256 else
257 return -result;
258}