e8555c89 Andy McCall 1 month ago
1
#ifndef CSTD_HH
2
#define CSTD_HH
3
4
#include " Math.hh"
5
#include " narrow.hh"
6
#include " xrange.hh"
7
#include < cassert>
8
#include < cmath>
9
#include < cstddef>
10
#include < functional>
11
#include < string_view>
12
#include < utility>
13
14
namespace cstd {
15
16
template < typename T>
17
[ [ nodiscard] ] constexpr T abs ( T t )
18
{
19
return ( t >= 0 ) ? t : - t;
20
}
21
22
23
24
#if (defined (__GNUC__) && !defined (__clang__))
25
26
27
28
template < int > [ [ nodiscard] ] constexpr double sin ( double x) { return std:: sin ( x ) ; }
29
template < int > [ [ nodiscard] ] constexpr double cos ( double x) { return std:: cos ( x ) ; }
30
template < int , int > [ [ nodiscard] ] constexpr double log ( double x) { return std:: log ( x ) ; }
31
template < int , int > [ [ nodiscard] ] constexpr double log2 ( double x) { return :: log ( x ) / :: log( 2 ) ; }
32
template < int , int > [ [ nodiscard] ] constexpr double log10 ( double x) { return std:: log10 ( x ) ; }
33
template < int > [ [ nodiscard] ] constexpr double exp ( double x) { return std:: exp ( x ) ; }
34
template < int > [ [ nodiscard] ] constexpr double exp2 ( double x) { return :: exp2 ( x ) ; }
35
template < int , int > [ [ nodiscard] ] constexpr double pow ( double x, double y) { return std:: pow ( x, y ) ; }
36
[ [ nodiscard] ] constexpr double round ( double x) { return :: round( x ) ; }
37
[ [ nodiscard] ] constexpr float round ( float x) { return :: roundf( x ) ; }
38
[ [ nodiscard] ] constexpr double sqrt ( double x) { return :: sqrt ( x ) ; }
39
40
#else
41
42
[ [ nodiscard] ] constexpr double upow ( double x, unsigned u)
43
{
44
double y = 1.0 ;
45
while ( u) {
46
if ( u & 1 ) y *= x;
47
x *= x;
48
u >>= 1 ;
49
}
50
return y;
51
}
52
53
[ [ nodiscard] ] constexpr double ipow ( double x, int i)
54
{
55
return ( i >= 0 ) ? upow ( x, i ) : upow ( x, - i ) ;
56
}
57
58
template < int ITERATIONS>
59
[ [ nodiscard] ] constexpr double exp ( double x)
60
{
61
62
63
64
65
auto i = int ( x) ;
66
auto f = x - i;
67
68
69
double y = 1.0 ;
70
double t = f;
71
double n = 1.0 ;
72
for ( auto k : xrange ( ITERATIONS ) ) {
73
y += t / n;
74
t *= f;
75
n *= k + 2 ;
76
}
77
78
79
int p = ( i >= 0 ) ? i : - i;
80
double s = upow ( Math:: e, p ) ;
81
82
83
if ( i >= 0 ) {
84
return y * s;
85
} else {
86
return y / s;
87
}
88
}
89
90
[ [ nodiscard] ] constexpr double simple_fmod ( double x, double y)
91
{
92
assert ( y > 0.0 ) ;
93
return x - int ( x / y) * y;
94
}
95
96
template < int ITERATIONS>
97
[ [ nodiscard] ] constexpr double sin_iter ( double x)
98
{
99
double x2 = x * x;
100
double y = 0.0 ;
101
double t = x;
102
double n = 1.0 ;
103
for ( int k = 1 ; k < ( 1 + 4 * ITERATIONS) ; ) {
104
y += t / n;
105
t *= x2;
106
n *= + + k;
107
n *= + + k;
108
109
y -= t / n;
110
t *= x2;
111
n *= + + k;
112
n *= + + k;
113
}
114
return y;
115
}
116
117
template < int ITERATIONS>
118
[ [ nodiscard] ] constexpr double cos_iter ( double x)
119
{
120
double x2 = x * x;
121
double y = 1.0 ;
122
double t = x2;
123
double n = 2.0 ;
124
for ( int k = 2 ; k < ( 2 + 4 * ITERATIONS) ; ) {
125
y -= t / n;
126
t *= x2;
127
n *= + + k;
128
n *= + + k;
129
130
y += t / n;
131
t *= x2;
132
n *= + + k;
133
n *= + + k;
134
}
135
return y;
136
}
137
138
template < int ITERATIONS>
139
[ [ nodiscard] ] constexpr double sin ( double x)
140
{
141
double sign = 1.0 ;
142
143
144
if ( x < 0.0 ) {
145
sign = - 1.0 ;
146
x = - x;
147
}
148
149
150
x = simple_fmod ( x, 2 * Math:: pi ) ;
151
152
153
if ( x > Math:: pi) {
154
sign = - sign;
155
x -= Math:: pi;
156
}
157
158
159
if ( x > Math:: pi / 2 ) {
160
x = Math:: pi - x;
161
}
162
163
164
if ( x > Math:: pi / 4 ) {
165
x = Math:: pi / 2 - x;
166
return sign * cos_iter < ITERATIONS> ( x ) ;
167
} else {
168
return sign * sin_iter < ITERATIONS> ( x ) ;
169
}
170
}
171
172
template < int ITERATIONS>
173
[ [ nodiscard] ] constexpr double cos ( double x)
174
{
175
double sign = 1.0 ;
176
177
178
if ( x < 0.0 ) {
179
x = - x;
180
}
181
182
183
x = simple_fmod ( x, 2 * Math:: pi ) ;
184
185
186
if ( x > Math:: pi) {
187
x = 2.0 * Math:: pi - x;
188
}
189
190
191
if ( x > Math:: pi / 2 ) {
192
sign = - sign;
193
x = Math:: pi - x;
194
}
195
196
197
if ( x > Math:: pi / 4 ) {
198
x = Math:: pi / 2 - x;
199
return sign * sin_iter < ITERATIONS> ( x ) ;
200
} else {
201
return sign * cos_iter < ITERATIONS> ( x ) ;
202
}
203
}
204
205
206
207
template < int E_ITERATIONS, int L_ITERATIONS>
208
[ [ nodiscard] ] constexpr double log ( double x)
209
{
210
int a = 0 ;
211
while ( x <= 0.25 ) {
212
x *= Math:: e;
213
+ + a;
214
}
215
double y = 0.0 ;
216
repeat ( L_ITERATIONS, [ & ] {
217
auto ey = cstd:: exp < E_ITERATIONS> ( y ) ;
218
y = y + 2.0 * ( x - ey) / ( x + ey) ;
219
} ) ;
220
return y - a;
221
}
222
223
template < int E_ITERATIONS, int L_ITERATIONS>
224
[ [ nodiscard] ] constexpr double log2 ( double x)
225
{
226
return cstd:: log < E_ITERATIONS, L_ITERATIONS> ( x ) / Math:: ln2;
227
}
228
229
template < int E_ITERATIONS, int L_ITERATIONS>
230
[ [ nodiscard] ] constexpr double log10 ( double x)
231
{
232
return cstd:: log < E_ITERATIONS, L_ITERATIONS> ( x ) / Math:: ln10;
233
}
234
235
template < int E_ITERATIONS, int L_ITERATIONS>
236
[ [ nodiscard] ] constexpr double pow ( double x, double y)
237
{
238
return cstd:: exp < E_ITERATIONS> ( cstd:: log < E_ITERATIONS, L_ITERATIONS> ( x ) * y) ;
239
}
240
241
template < int ITERATIONS>
242
[ [ nodiscard] ] constexpr double exp2 ( double x)
243
{
244
return cstd:: exp < ITERATIONS> ( Math:: ln2 * x ) ;
245
}
246
247
[ [ nodiscard] ] constexpr double round ( double x)
248
{
249
return narrow_cast < double > (
250
( x >= 0 ) ? narrow_cast < int > ( x + 0.5 )
251
: - narrow_cast < int > ( - x + 0.5 ) ) ;
252
}
253
254
[ [ nodiscard] ] constexpr float round ( float x)
255
{
256
return narrow_cast < float > (
257
( x >= 0 ) ? narrow_cast < int > ( x + 0.5f )
258
: - narrow_cast < int > ( - x + 0.5f ) ) ;
259
}
260
261
[ [ nodiscard] ] constexpr double sqrt ( double x)
262
{
263
assert ( x >= 0.0 ) ;
264
double curr = x;
265
double prev = 0.0 ;
266
while ( curr != prev) {
267
prev = curr;
268
curr = 0.5 * ( curr + x / curr) ;
269
}
270
return curr;
271
}
272
273
#endif
274
275
}
276
277
#endif