@stdlib/math-base-special-sincosf 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/main.c ADDED
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "stdlib/math/base/special/sincosf.h"
20
+ #include "stdlib/math/base/special/kernel_sincosf.h"
21
+ #include "stdlib/math/base/special/rempio2f.h"
22
+ #include "stdlib/constants/float64/half_pi.h"
23
+ #include "stdlib/constants/float32/abs_mask.h"
24
+ #include "stdlib/constants/float32/exponent_mask.h"
25
+ #include "stdlib/number/float32/base/to_word.h"
26
+ #include <stdint.h>
27
+
28
+ // PI/4 = 0.7853981256484985 => 0 01111110 10010010000111111011010 => 0x3f490fda = 1061752768
29
+ static const int32_t PIO4_WORD = 0x3f490fda;
30
+
31
+ // 3*PI/4 = 2.356194257736206 => 0 10000000 00101101100101111100011 => 0x4016cbe3 = 1075235811
32
+ static const int32_t THREE_PIO4_WORD = 0x4016cbe3;
33
+
34
+ // 5*PI/4 = 3.9269907474517822 => 0 10000000 11110110101001111010001 => 0x407b53d1 = 1081824209
35
+ static const int32_t FIVE_PIO4_WORD = 0x407b53d1;
36
+
37
+ // 7*PI/4 = 5.497786998748779 => 0 10000001 01011111110110111011111 => 0x40afeddf = 1085271519
38
+ static const int32_t SEVEN_PIO4_WORD = 0x40afeddf;
39
+
40
+ // 9*PI/4 = 7.068583011627197 => 0 10000001 11000100011000111010101 => 0x40e231d5 = 1088565717
41
+ static const int32_t NINE_PIO4_WORD = 0x40e231d5;
42
+
43
+ // 2^-12 = 0.000244140625 => 0 01110011 00000000000000000000000 => 0x39800000 = 964689920
44
+ static const int32_t SMALL_WORD = 0x39800000;
45
+
46
+ // Small multiples of PI/2 in double-precision floating-point format:
47
+ static const double PIO2 = STDLIB_CONSTANT_FLOAT64_HALF_PI; // 0x3FF921FB, 0x54442D18
48
+ static const double PI = 2.0 * STDLIB_CONSTANT_FLOAT64_HALF_PI; // 0x400921FB, 0x54442D18
49
+ static const double THREE_PIO2 = 3.0 * STDLIB_CONSTANT_FLOAT64_HALF_PI; // 0x4012D97C, 0x7F3321D2
50
+ static const double TWO_PI = 4.0 * STDLIB_CONSTANT_FLOAT64_HALF_PI; // 0x401921FB, 0x54442D18
51
+
52
+ /**
53
+ * Simultaneously computes the sine and cosine of a single-precision floating-point number (in radians).
54
+ *
55
+ * ## Method
56
+ *
57
+ * - Let \\(S\\), \\(C\\), and \\(T\\) denote the \\(\sin\\), \\(\cos\\) and \\(\tan\\), respectively, on \\(\[-\pi/4, +\pi/4\]\\).
58
+ *
59
+ * - Reduce the argument \\(x\\) to \\(y = x-k\pi/2\\) in \\(\[-\pi/4, +\pi/4\]\\), and let \\(n = k \mod 4\\).
60
+ *
61
+ * - We have
62
+ *
63
+ * | n | sin(x) | cos(x) | tan(x) |
64
+ * | - | ------ | ------ | ------ |
65
+ * | 0 | S | C | T |
66
+ * | 1 | C | -S | -1/T |
67
+ * | 2 | -S | -C | T |
68
+ * | 3 | -C | S | -1/T |
69
+ *
70
+ * @param x input value
71
+ * @param sine destination to store the sine
72
+ * @param cosine destination to store the cosine
73
+ *
74
+ * @example
75
+ * float x = 0.0f;
76
+ *
77
+ * float cosine;
78
+ * float sine;
79
+ * stdlib_base_sincosf( x, &sine, &cosine );
80
+ */
81
+ void stdlib_base_sincosf( const float x, float* sine, float* cosine ) {
82
+ uint32_t uix;
83
+ int32_t ix;
84
+ int32_t n;
85
+ float tmp;
86
+ double y;
87
+
88
+ stdlib_base_float32_to_word( x, &uix );
89
+ ix = (int32_t)uix;
90
+ ix &= STDLIB_CONSTANT_FLOAT32_ABS_MASK;
91
+
92
+ // Case: |x| ~<= π/4
93
+ if ( ix <= PIO4_WORD ) {
94
+ // Case: |x| < 2^-12
95
+ if ( ix < SMALL_WORD ) {
96
+ if ( (int32_t)x == 0 ) {
97
+ *sine = x;
98
+ *cosine = 1.0f;
99
+ return;
100
+ }
101
+ }
102
+ stdlib_base_kernel_sincosf( (double)x, sine, cosine );
103
+ return;
104
+ }
105
+ // Case: |x| ~<= 5π/4
106
+ if ( ix <= FIVE_PIO4_WORD ) {
107
+ // Case: |x| ~<= 3π/4
108
+ if ( ix <= THREE_PIO4_WORD ) {
109
+ if ( (int32_t)uix > 0 ) {
110
+ stdlib_base_kernel_sincosf( (double)x - PIO2, cosine, sine );
111
+ *cosine = -( *cosine );
112
+ } else {
113
+ stdlib_base_kernel_sincosf( (double)x + PIO2, cosine, sine );
114
+ *sine = -( *sine );
115
+ }
116
+ } else {
117
+ if ( (int32_t)uix > 0 ) {
118
+ stdlib_base_kernel_sincosf( (double)x - PI, sine, cosine );
119
+ } else {
120
+ stdlib_base_kernel_sincosf( (double)x + PI, sine, cosine );
121
+ }
122
+ *sine = -( *sine );
123
+ *cosine = -( *cosine );
124
+ }
125
+ return;
126
+ }
127
+ // Case: |x| ~<= 9π/4
128
+ if ( ix <= NINE_PIO4_WORD ) {
129
+ // Case: |x| ~<= 7π/4
130
+ if ( ix <= SEVEN_PIO4_WORD ) {
131
+ if ( (int32_t)uix > 0 ) {
132
+ stdlib_base_kernel_sincosf( (double)x - THREE_PIO2, cosine, sine );
133
+ *sine = -( *sine );
134
+ } else {
135
+ stdlib_base_kernel_sincosf( (double)x + THREE_PIO2, cosine, sine );
136
+ *cosine = -( *cosine );
137
+ }
138
+ } else if ( (int32_t)uix > 0 ) {
139
+ stdlib_base_kernel_sincosf( (double)x - TWO_PI, sine, cosine );
140
+ } else {
141
+ stdlib_base_kernel_sincosf( (double)x + TWO_PI, sine, cosine );
142
+ }
143
+ return;
144
+ }
145
+ // Case: x is NaN or infinity
146
+ if ( ix >= STDLIB_CONSTANT_FLOAT32_EXPONENT_MASK ) {
147
+ *sine = 0.0f / 0.0f; // NaN
148
+ *cosine = 0.0f / 0.0f; // NaN
149
+ return;
150
+ }
151
+ // Argument reduction...
152
+ n = stdlib_base_rempio2f( x, &y );
153
+
154
+ // Compute the sine and cosine together:
155
+ stdlib_base_kernel_sincosf( y, sine, cosine );
156
+
157
+ switch ( n & 3 ) {
158
+ case 0:
159
+ return;
160
+ case 1:
161
+ tmp = *cosine;
162
+ *cosine = -( *sine );
163
+ *sine = tmp;
164
+ return;
165
+ case 2:
166
+ *sine = -( *sine );
167
+ *cosine = -( *cosine );
168
+ return;
169
+ default:
170
+ tmp = -( *cosine );
171
+ *cosine = *sine;
172
+ *sine = tmp;
173
+ return;
174
+ }
175
+ }