1 /*
2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 /** \file
18 * \brief Implement floating-point folding with host arithmetic
19 *
20 * Implements the compile-time evaluation interfaces of "fp-folding.h"
21 * using the native host floating-point arithmetic operations and
22 * math library.
23 */
24
25 #include "fp-folding.h"
26 #include <assert.h>
27 #include <complex.h>
28 #include <errno.h>
29 #include <fenv.h>
30 #include <float.h>
31 #include <math.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 /*
39 * Build-time sanity checks
40 */
41 #if __STDC_VERSION__+0 < 199901
42 # warning C99 compiler required but __STDC_VERSION__ is less than 199901
43 #endif
44 #if FLT_RADIX+0 != 2
45 # error FLT_RADIX != 2
46 #endif
47 #if FLT_MANT_DIG+0 != 24
48 # error FLT_MANT_DIG != 24
49 #endif
50 #if DBL_MANT_DIG+0 != 53
51 # error DBL_MANT_DIG != 53
52 #endif
53 #if DECIMAL_DIG < 17
54 # error DECIMAL_DIG < 17
55 #endif
56
57 void
fold_sanity_check(void)58 fold_sanity_check(void)
59 {
60 assert(sizeof(float32_t) == 4);
61 assert(sizeof(float64_t) == 8);
62 assert(sizeof(float128_t) == 16);
63 }
64
65 /*
66 * C99 feature: alert the compiler that the following code cares about
67 * the dynamic floating-point environment.
68 */
69 #pragma STDC FENV_ACCESS ON
70
71 /*
72 * Configure "denormal inputs are zero" and "flush denormal results to zero"
73 * modes.
74 *
75 * TODO: Find a more portable way to configure these settings.
76 */
77
78 static void
configure_denormals(bool denorms_are_zeros,bool flush_to_zero)79 configure_denormals(bool denorms_are_zeros, bool flush_to_zero)
80 {
81 fenv_t fenv;
82 if (fegetenv(&fenv) != 0)
83 fprintf(stderr, "fegetenv() failed: %s\n", strerror(errno));
84 #ifdef __x86_64__
85 fenv.__mxcsr &= ~0x0040;
86 if (denorms_are_zeros)
87 fenv.__mxcsr |= 0x0040;
88 fenv.__mxcsr &= ~0x8000;
89 if (flush_to_zero)
90 fenv.__mxcsr |= 0x8000;
91 #endif
92 if (fesetenv(&fenv) != 0)
93 fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno));
94 }
95
96 /*
97 * Comparisons. These can't trap.
98 */
99
100 #define COMPARE_BODY { \
101 enum fold_relation rel = FOLD_UN; \
102 fenv_t fenv; \
103 if (feholdexcept(&fenv) != 0) \
104 fprintf(stderr, "feholdexcept() failed: %s\n", strerror(errno)); \
105 configure_denormals(false, false); \
106 if (*x < *y) \
107 rel = FOLD_LT; \
108 else if (*x == *y) \
109 rel = FOLD_EQ; \
110 else if (*x > *y) \
111 rel = FOLD_GT; \
112 if (fesetenv(&fenv) != 0) \
113 fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno)); \
114 return rel; \
115 }
116
117 enum fold_relation
fold_real32_compare(const float32_t * x,const float32_t * y)118 fold_real32_compare(const float32_t *x, const float32_t *y)
119 {
120 COMPARE_BODY
121 }
122
123 enum fold_relation
fold_real64_compare(const float64_t * x,const float64_t * y)124 fold_real64_compare(const float64_t *x, const float64_t *y)
125 {
126 COMPARE_BODY
127 }
128
129 enum fold_relation
fold_real128_compare(const float128_t * x,const float128_t * y)130 fold_real128_compare(const float128_t *x, const float128_t *y)
131 {
132 COMPARE_BODY
133 }
134
135 /*
136 * Set up the floating-point environment so that exceptional conditions
137 * are recorded but don't raise traps.
138 *
139 * TODO: Consider setting the daz and flushz modes by the compiler to
140 * match the expected run-time environment (-Mdaz, -Mflushz). Those
141 * compiler options are documented as "link-time" but maybe it would
142 * be a good idea to respect them while folding.
143 */
144 static void
set_up_floating_point_environment(fenv_t * fenv)145 set_up_floating_point_environment(fenv_t *fenv)
146 {
147 if (feholdexcept(fenv) != 0)
148 fprintf(stderr, "feholdexcept() failed: %s\n", strerror(errno));
149 configure_denormals(false, false);
150 errno = 0;
151 }
152
153 /*
154 * Map floating-point exceptional conditions to a folding status code.
155 */
156
157 static enum fold_status
interpret_exceptions(int exceptions,int errno_capture)158 interpret_exceptions(int exceptions, int errno_capture)
159 {
160 if (exceptions & FE_INVALID)
161 return FOLD_INVALID;
162 if (exceptions & (FE_DIVBYZERO | FE_OVERFLOW))
163 return FOLD_OVERFLOW;
164 if (exceptions & FE_UNDERFLOW)
165 return FOLD_UNDERFLOW;
166 if (exceptions & FE_INEXACT)
167 return FOLD_INEXACT;
168 /* ignore any non-standard extended flags */
169 if (errno_capture == EDOM)
170 return FOLD_INVALID;
171 if (errno_capture == ERANGE)
172 return FOLD_OVERFLOW; /* can't distinguish over/underflow from errno */
173 return FOLD_OK;
174 }
175
176 /*
177 * Common exit processing: restore the processor's floating-point
178 * environment and translate any exceptions that may have arisen.
179 */
180
181 static enum fold_status
check_and_restore_floating_point_environment(const fenv_t * saved_fenv)182 check_and_restore_floating_point_environment(const fenv_t *saved_fenv)
183 {
184 int errno_capture = errno;
185 int exceptions = fetestexcept(FE_ALL_EXCEPT);
186 if (fesetenv(saved_fenv) != 0)
187 fprintf(stderr, "fesetenv() failed: %s\n", strerror(errno));
188 return interpret_exceptions(exceptions, errno_capture);
189 }
190
191 /*
192 * Compile-time evaluation routines for a large set of operations
193 * on all of the available host floating-point types.
194 */
195
196 /* 32-bit */
197
198 enum fold_status
fold_int32_from_real32(int32_t * res,const float32_t * arg)199 fold_int32_from_real32(int32_t *res, const float32_t *arg)
200 {
201 fenv_t saved_fenv;
202 set_up_floating_point_environment(&saved_fenv);
203 *res = *arg;
204 return check_and_restore_floating_point_environment(&saved_fenv);
205 }
206
207 enum fold_status
fold_int64_from_real32(int64_t * res,const float32_t * arg)208 fold_int64_from_real32(int64_t *res, const float32_t *arg)
209 {
210 fenv_t saved_fenv;
211 set_up_floating_point_environment(&saved_fenv);
212 *res = *arg;
213 return check_and_restore_floating_point_environment(&saved_fenv);
214 }
215
216 enum fold_status
fold_uint64_from_real32(uint64_t * res,const float32_t * arg)217 fold_uint64_from_real32(uint64_t *res, const float32_t *arg)
218 {
219 fenv_t saved_fenv;
220 set_up_floating_point_environment(&saved_fenv);
221 *res = *arg;
222 return check_and_restore_floating_point_environment(&saved_fenv);
223 }
224
225 enum fold_status
fold_uint32_from_real32(uint32_t * res,const float32_t * arg)226 fold_uint32_from_real32(uint32_t *res, const float32_t *arg)
227 {
228 fenv_t saved_fenv;
229 set_up_floating_point_environment(&saved_fenv);
230 *res = *arg;
231 return check_and_restore_floating_point_environment(&saved_fenv);
232 }
233
234 enum fold_status
fold_real32_from_int64(float32_t * res,const int64_t * arg)235 fold_real32_from_int64(float32_t *res, const int64_t *arg)
236 {
237 fenv_t saved_fenv;
238 set_up_floating_point_environment(&saved_fenv);
239 *res = *arg;
240 return check_and_restore_floating_point_environment(&saved_fenv);
241 }
242
243 enum fold_status
fold_real32_from_uint64(float32_t * res,const uint64_t * arg)244 fold_real32_from_uint64(float32_t *res, const uint64_t *arg)
245 {
246 fenv_t saved_fenv;
247 set_up_floating_point_environment(&saved_fenv);
248 *res = *arg;
249 return check_and_restore_floating_point_environment(&saved_fenv);
250 }
251
252 enum fold_status
fold_real32_from_real64(float32_t * res,const float64_t * arg)253 fold_real32_from_real64(float32_t *res, const float64_t *arg)
254 {
255 fenv_t saved_fenv;
256 set_up_floating_point_environment(&saved_fenv);
257 *res = *arg;
258 return check_and_restore_floating_point_environment(&saved_fenv);
259 }
260
261 enum fold_status
fold_real32_from_real128(float32_t * res,const float128_t * arg)262 fold_real32_from_real128(float32_t *res, const float128_t *arg)
263 {
264 fenv_t saved_fenv;
265 set_up_floating_point_environment(&saved_fenv);
266 *res = *arg;
267 return check_and_restore_floating_point_environment(&saved_fenv);
268 }
269
270 enum fold_status
fold_real32_negate(float32_t * res,const float32_t * arg)271 fold_real32_negate(float32_t *res, const float32_t *arg)
272 {
273 fenv_t saved_fenv;
274 set_up_floating_point_environment(&saved_fenv);
275 *res = -*arg;
276 return check_and_restore_floating_point_environment(&saved_fenv);
277 }
278
279 enum fold_status
fold_real32_abs(float32_t * res,const float32_t * arg)280 fold_real32_abs(float32_t *res, const float32_t *arg)
281 {
282 fenv_t saved_fenv;
283 set_up_floating_point_environment(&saved_fenv);
284 *res = fabsf(*arg);
285 return check_and_restore_floating_point_environment(&saved_fenv);
286 }
287
288 enum fold_status
fold_real32_sqrt(float32_t * res,const float32_t * arg)289 fold_real32_sqrt(float32_t *res, const float32_t *arg)
290 {
291 fenv_t saved_fenv;
292 set_up_floating_point_environment(&saved_fenv);
293 *res = sqrtf(*arg);
294 return check_and_restore_floating_point_environment(&saved_fenv);
295 }
296
297 enum fold_status
fold_real32_add(float32_t * res,const float32_t * x,const float32_t * y)298 fold_real32_add(float32_t *res, const float32_t *x, const float32_t *y)
299 {
300 fenv_t saved_fenv;
301 set_up_floating_point_environment(&saved_fenv);
302 *res = *x+*y;
303 return check_and_restore_floating_point_environment(&saved_fenv);
304 }
305
306 enum fold_status
fold_real32_subtract(float32_t * res,const float32_t * x,const float32_t * y)307 fold_real32_subtract(float32_t *res, const float32_t *x, const float32_t *y)
308 {
309 fenv_t saved_fenv;
310 set_up_floating_point_environment(&saved_fenv);
311 *res = *x - *y;
312 return check_and_restore_floating_point_environment(&saved_fenv);
313 }
314
315 enum fold_status
fold_real32_multiply(float32_t * res,const float32_t * x,const float32_t * y)316 fold_real32_multiply(float32_t *res, const float32_t *x, const float32_t *y)
317 {
318 fenv_t saved_fenv;
319 set_up_floating_point_environment(&saved_fenv);
320 *res = *x * *y;
321 return check_and_restore_floating_point_environment(&saved_fenv);
322 }
323
324 enum fold_status
fold_real32_divide(float32_t * res,const float32_t * x,const float32_t * y)325 fold_real32_divide(float32_t *res, const float32_t *x, const float32_t *y)
326 {
327 fenv_t saved_fenv;
328 set_up_floating_point_environment(&saved_fenv);
329 *res = *x / *y;
330 return check_and_restore_floating_point_environment(&saved_fenv);
331 }
332
333 enum fold_status
fold_real32_pow(float32_t * res,const float32_t * x,const float32_t * y)334 fold_real32_pow(float32_t *res, const float32_t *x, const float32_t *y)
335 {
336 fenv_t saved_fenv;
337 set_up_floating_point_environment(&saved_fenv);
338 *res = powf(*x, *y);
339 return check_and_restore_floating_point_environment(&saved_fenv);
340 }
341
342 enum fold_status
fold_real32_sin(float32_t * res,const float32_t * arg)343 fold_real32_sin(float32_t *res, const float32_t *arg)
344 {
345 fenv_t saved_fenv;
346 set_up_floating_point_environment(&saved_fenv);
347 *res = sinf(*arg);
348 return check_and_restore_floating_point_environment(&saved_fenv);
349 }
350
351 enum fold_status
fold_real32_cos(float32_t * res,const float32_t * arg)352 fold_real32_cos(float32_t *res, const float32_t *arg)
353 {
354 fenv_t saved_fenv;
355 set_up_floating_point_environment(&saved_fenv);
356 *res = cosf(*arg);
357 return check_and_restore_floating_point_environment(&saved_fenv);
358 }
359
360 enum fold_status
fold_real32_tan(float32_t * res,const float32_t * arg)361 fold_real32_tan(float32_t *res, const float32_t *arg)
362 {
363 fenv_t saved_fenv;
364 set_up_floating_point_environment(&saved_fenv);
365 *res = tanf(*arg);
366 return check_and_restore_floating_point_environment(&saved_fenv);
367 }
368
369 enum fold_status
fold_real32_asin(float32_t * res,const float32_t * arg)370 fold_real32_asin(float32_t *res, const float32_t *arg)
371 {
372 fenv_t saved_fenv;
373 set_up_floating_point_environment(&saved_fenv);
374 *res = asinf(*arg);
375 return check_and_restore_floating_point_environment(&saved_fenv);
376 }
377
378 enum fold_status
fold_real32_acos(float32_t * res,const float32_t * arg)379 fold_real32_acos(float32_t *res, const float32_t *arg)
380 {
381 fenv_t saved_fenv;
382 set_up_floating_point_environment(&saved_fenv);
383 *res = acosf(*arg);
384 return check_and_restore_floating_point_environment(&saved_fenv);
385 }
386
387 enum fold_status
fold_real32_atan(float32_t * res,const float32_t * arg)388 fold_real32_atan(float32_t *res, const float32_t *arg)
389 {
390 fenv_t saved_fenv;
391 set_up_floating_point_environment(&saved_fenv);
392 *res = atanf(*arg);
393 return check_and_restore_floating_point_environment(&saved_fenv);
394 }
395
396 enum fold_status
fold_real32_atan2(float32_t * res,const float32_t * x,const float32_t * y)397 fold_real32_atan2(float32_t *res, const float32_t *x, const float32_t *y)
398 {
399 fenv_t saved_fenv;
400 set_up_floating_point_environment(&saved_fenv);
401 *res = atan2f(*x, *y);
402 return check_and_restore_floating_point_environment(&saved_fenv);
403 }
404
405 enum fold_status
fold_real32_exp(float32_t * res,const float32_t * arg)406 fold_real32_exp(float32_t *res, const float32_t *arg)
407 {
408 fenv_t saved_fenv;
409 set_up_floating_point_environment(&saved_fenv);
410 *res = expf(*arg);
411 return check_and_restore_floating_point_environment(&saved_fenv);
412 }
413
414 enum fold_status
fold_real32_log(float32_t * res,const float32_t * arg)415 fold_real32_log(float32_t *res, const float32_t *arg)
416 {
417 fenv_t saved_fenv;
418 set_up_floating_point_environment(&saved_fenv);
419 *res = logf(*arg);
420 return check_and_restore_floating_point_environment(&saved_fenv);
421 }
422
423 enum fold_status
fold_real32_log10(float32_t * res,const float32_t * arg)424 fold_real32_log10(float32_t *res, const float32_t *arg)
425 {
426 fenv_t saved_fenv;
427 set_up_floating_point_environment(&saved_fenv);
428 *res = log10f(*arg);
429 return check_and_restore_floating_point_environment(&saved_fenv);
430 }
431
432 /* 64-bit */
433
434 enum fold_status
fold_int32_from_real64(int32_t * res,const float64_t * arg)435 fold_int32_from_real64(int32_t *res, const float64_t *arg)
436 {
437 fenv_t saved_fenv;
438 set_up_floating_point_environment(&saved_fenv);
439 *res = *arg;
440 return check_and_restore_floating_point_environment(&saved_fenv);
441 }
442
443 enum fold_status
fold_int64_from_real64(int64_t * res,const float64_t * arg)444 fold_int64_from_real64(int64_t *res, const float64_t *arg)
445 {
446 fenv_t saved_fenv;
447 set_up_floating_point_environment(&saved_fenv);
448 *res = *arg;
449 return check_and_restore_floating_point_environment(&saved_fenv);
450 }
451
452 enum fold_status
fold_uint32_from_real64(uint32_t * res,const float64_t * arg)453 fold_uint32_from_real64(uint32_t *res, const float64_t *arg)
454 {
455 fenv_t saved_fenv;
456 set_up_floating_point_environment(&saved_fenv);
457 *res = *arg;
458 return check_and_restore_floating_point_environment(&saved_fenv);
459 }
460
461 enum fold_status
fold_uint64_from_real64(uint64_t * res,const float64_t * arg)462 fold_uint64_from_real64(uint64_t *res, const float64_t *arg)
463 {
464 fenv_t saved_fenv;
465 set_up_floating_point_environment(&saved_fenv);
466 *res = *arg;
467 return check_and_restore_floating_point_environment(&saved_fenv);
468 }
469
470 enum fold_status
fold_real64_from_int64(float64_t * res,const int64_t * arg)471 fold_real64_from_int64(float64_t *res, const int64_t *arg)
472 {
473 fenv_t saved_fenv;
474 set_up_floating_point_environment(&saved_fenv);
475 *res = *arg;
476 return check_and_restore_floating_point_environment(&saved_fenv);
477 }
478
479 enum fold_status
fold_real64_from_uint64(float64_t * res,const uint64_t * arg)480 fold_real64_from_uint64(float64_t *res, const uint64_t *arg)
481 {
482 fenv_t saved_fenv;
483 set_up_floating_point_environment(&saved_fenv);
484 *res = *arg;
485 return check_and_restore_floating_point_environment(&saved_fenv);
486 }
487
488 enum fold_status
fold_real64_from_real32(float64_t * res,const float32_t * arg)489 fold_real64_from_real32(float64_t *res, const float32_t *arg)
490 {
491 fenv_t saved_fenv;
492 set_up_floating_point_environment(&saved_fenv);
493 *res = *arg;
494 return check_and_restore_floating_point_environment(&saved_fenv);
495 }
496
497 enum fold_status
fold_real64_from_real128(float64_t * res,const float128_t * arg)498 fold_real64_from_real128(float64_t *res, const float128_t *arg)
499 {
500 fenv_t saved_fenv;
501 set_up_floating_point_environment(&saved_fenv);
502 *res = *arg;
503 return check_and_restore_floating_point_environment(&saved_fenv);
504 }
505
506 enum fold_status
fold_real64_negate(float64_t * res,const float64_t * arg)507 fold_real64_negate(float64_t *res, const float64_t *arg)
508 {
509 fenv_t saved_fenv;
510 set_up_floating_point_environment(&saved_fenv);
511 *res = -*arg;
512 return check_and_restore_floating_point_environment(&saved_fenv);
513 }
514
515 enum fold_status
fold_real64_abs(float64_t * res,const float64_t * arg)516 fold_real64_abs(float64_t *res, const float64_t *arg)
517 {
518 fenv_t saved_fenv;
519 set_up_floating_point_environment(&saved_fenv);
520 *res = fabs(*arg);
521 return check_and_restore_floating_point_environment(&saved_fenv);
522 }
523
524 enum fold_status
fold_real64_sqrt(float64_t * res,const float64_t * arg)525 fold_real64_sqrt(float64_t *res, const float64_t *arg)
526 {
527 fenv_t saved_fenv;
528 set_up_floating_point_environment(&saved_fenv);
529 *res = sqrt(*arg);
530 return check_and_restore_floating_point_environment(&saved_fenv);
531 }
532
533 enum fold_status
fold_real64_add(float64_t * res,const float64_t * x,const float64_t * y)534 fold_real64_add(float64_t *res, const float64_t *x, const float64_t *y)
535 {
536 fenv_t saved_fenv;
537 set_up_floating_point_environment(&saved_fenv);
538 *res = *x + *y;
539 return check_and_restore_floating_point_environment(&saved_fenv);
540 }
541
542 enum fold_status
fold_real64_subtract(float64_t * res,const float64_t * x,const float64_t * y)543 fold_real64_subtract(float64_t *res, const float64_t *x, const float64_t *y)
544 {
545 fenv_t saved_fenv;
546 set_up_floating_point_environment(&saved_fenv);
547 *res = *x - *y;
548 return check_and_restore_floating_point_environment(&saved_fenv);
549 }
550
551 enum fold_status
fold_real64_multiply(float64_t * res,const float64_t * x,const float64_t * y)552 fold_real64_multiply(float64_t *res, const float64_t *x, const float64_t *y)
553 {
554 fenv_t saved_fenv;
555 set_up_floating_point_environment(&saved_fenv);
556 *res = *x * *y;
557 return check_and_restore_floating_point_environment(&saved_fenv);
558 }
559
560 enum fold_status
fold_real64_divide(float64_t * res,const float64_t * x,const float64_t * y)561 fold_real64_divide(float64_t *res, const float64_t *x, const float64_t *y)
562 {
563 fenv_t saved_fenv;
564 set_up_floating_point_environment(&saved_fenv);
565 *res = *x / *y;
566 return check_and_restore_floating_point_environment(&saved_fenv);
567 }
568
569 enum fold_status
fold_real64_pow(float64_t * res,const float64_t * x,const float64_t * y)570 fold_real64_pow(float64_t *res, const float64_t *x, const float64_t *y)
571 {
572 fenv_t saved_fenv;
573 set_up_floating_point_environment(&saved_fenv);
574 *res = pow(*x, *y);
575 return check_and_restore_floating_point_environment(&saved_fenv);
576 }
577
578 enum fold_status
fold_real64_sin(float64_t * res,const float64_t * arg)579 fold_real64_sin(float64_t *res, const float64_t *arg)
580 {
581 fenv_t saved_fenv;
582 set_up_floating_point_environment(&saved_fenv);
583 *res = sin(*arg);
584 return check_and_restore_floating_point_environment(&saved_fenv);
585 }
586
587 enum fold_status
fold_real64_cos(float64_t * res,const float64_t * arg)588 fold_real64_cos(float64_t *res, const float64_t *arg)
589 {
590 fenv_t saved_fenv;
591 set_up_floating_point_environment(&saved_fenv);
592 *res = cos(*arg);
593 return check_and_restore_floating_point_environment(&saved_fenv);
594 }
595
596 enum fold_status
fold_real64_tan(float64_t * res,const float64_t * arg)597 fold_real64_tan(float64_t *res, const float64_t *arg)
598 {
599 fenv_t saved_fenv;
600 set_up_floating_point_environment(&saved_fenv);
601 *res = tan(*arg);
602 return check_and_restore_floating_point_environment(&saved_fenv);
603 }
604
605 enum fold_status
fold_real64_asin(float64_t * res,const float64_t * arg)606 fold_real64_asin(float64_t *res, const float64_t *arg)
607 {
608 fenv_t saved_fenv;
609 set_up_floating_point_environment(&saved_fenv);
610 *res = asin(*arg);
611 return check_and_restore_floating_point_environment(&saved_fenv);
612 }
613
614 enum fold_status
fold_real64_acos(float64_t * res,const float64_t * arg)615 fold_real64_acos(float64_t *res, const float64_t *arg)
616 {
617 fenv_t saved_fenv;
618 set_up_floating_point_environment(&saved_fenv);
619 *res = acos(*arg);
620 return check_and_restore_floating_point_environment(&saved_fenv);
621 }
622
623 enum fold_status
fold_real64_atan(float64_t * res,const float64_t * arg)624 fold_real64_atan(float64_t *res, const float64_t *arg)
625 {
626 fenv_t saved_fenv;
627 set_up_floating_point_environment(&saved_fenv);
628 *res = atan(*arg);
629 return check_and_restore_floating_point_environment(&saved_fenv);
630 }
631
632 enum fold_status
fold_real64_atan2(float64_t * res,const float64_t * x,const float64_t * y)633 fold_real64_atan2(float64_t *res, const float64_t *x, const float64_t *y)
634 {
635 fenv_t saved_fenv;
636 set_up_floating_point_environment(&saved_fenv);
637 *res = atan2(*x, *y);
638 return check_and_restore_floating_point_environment(&saved_fenv);
639 }
640
641 enum fold_status
fold_real64_exp(float64_t * res,const float64_t * arg)642 fold_real64_exp(float64_t *res, const float64_t *arg)
643 {
644 fenv_t saved_fenv;
645 set_up_floating_point_environment(&saved_fenv);
646 *res = exp(*arg);
647 return check_and_restore_floating_point_environment(&saved_fenv);
648 }
649
650 enum fold_status
fold_real64_log(float64_t * res,const float64_t * arg)651 fold_real64_log(float64_t *res, const float64_t *arg)
652 {
653 fenv_t saved_fenv;
654 set_up_floating_point_environment(&saved_fenv);
655 *res = log(*arg);
656 return check_and_restore_floating_point_environment(&saved_fenv);
657 }
658
659 enum fold_status
fold_real64_log10(float64_t * res,const float64_t * arg)660 fold_real64_log10(float64_t *res, const float64_t *arg)
661 {
662 fenv_t saved_fenv;
663 set_up_floating_point_environment(&saved_fenv);
664 *res = log10(*arg);
665 return check_and_restore_floating_point_environment(&saved_fenv);
666 }
667
668 /* 80, 64+64, or 128-bit */
669
670 enum fold_status
fold_int32_from_real128(int32_t * res,const float128_t * arg)671 fold_int32_from_real128(int32_t *res, const float128_t *arg)
672 {
673 fenv_t saved_fenv;
674 set_up_floating_point_environment(&saved_fenv);
675 *res = *arg;
676 return check_and_restore_floating_point_environment(&saved_fenv);
677 }
678
679 enum fold_status
fold_int64_from_real128(int64_t * res,const float128_t * arg)680 fold_int64_from_real128(int64_t *res, const float128_t *arg)
681 {
682 fenv_t saved_fenv;
683 set_up_floating_point_environment(&saved_fenv);
684 *res = *arg;
685 return check_and_restore_floating_point_environment(&saved_fenv);
686 }
687
688 enum fold_status
fold_uint32_from_real128(uint32_t * res,const float128_t * arg)689 fold_uint32_from_real128(uint32_t *res, const float128_t *arg)
690 {
691 fenv_t saved_fenv;
692 set_up_floating_point_environment(&saved_fenv);
693 *res = *arg;
694 return check_and_restore_floating_point_environment(&saved_fenv);
695 }
696
697 enum fold_status
fold_uint64_from_real128(uint64_t * res,const float128_t * arg)698 fold_uint64_from_real128(uint64_t *res, const float128_t *arg)
699 {
700 fenv_t saved_fenv;
701 set_up_floating_point_environment(&saved_fenv);
702 *res = *arg;
703 return check_and_restore_floating_point_environment(&saved_fenv);
704 }
705
706 enum fold_status
fold_real128_from_int64(float128_t * res,const int64_t * arg)707 fold_real128_from_int64(float128_t *res, const int64_t *arg)
708 {
709 fenv_t saved_fenv;
710 set_up_floating_point_environment(&saved_fenv);
711 *res = *arg;
712 return check_and_restore_floating_point_environment(&saved_fenv);
713 }
714
715 enum fold_status
fold_real128_from_uint64(float128_t * res,const uint64_t * arg)716 fold_real128_from_uint64(float128_t *res, const uint64_t *arg)
717 {
718 fenv_t saved_fenv;
719 set_up_floating_point_environment(&saved_fenv);
720 *res = *arg;
721 return check_and_restore_floating_point_environment(&saved_fenv);
722 }
723
724 enum fold_status
fold_real128_from_real32(float128_t * res,const float32_t * arg)725 fold_real128_from_real32(float128_t *res, const float32_t *arg)
726 {
727 fenv_t saved_fenv;
728 set_up_floating_point_environment(&saved_fenv);
729 *res = *arg;
730 return check_and_restore_floating_point_environment(&saved_fenv);
731 }
732
733 enum fold_status
fold_real128_from_real64(float128_t * res,const float64_t * arg)734 fold_real128_from_real64(float128_t *res, const float64_t *arg)
735 {
736 fenv_t saved_fenv;
737 set_up_floating_point_environment(&saved_fenv);
738 *res = *arg;
739 return check_and_restore_floating_point_environment(&saved_fenv);
740 }
741
742 enum fold_status
fold_real128_negate(float128_t * res,const float128_t * arg)743 fold_real128_negate(float128_t *res, const float128_t *arg)
744 {
745 fenv_t saved_fenv;
746 set_up_floating_point_environment(&saved_fenv);
747 *res = -*arg;
748 return check_and_restore_floating_point_environment(&saved_fenv);
749 }
750
751 enum fold_status
fold_real128_abs(float128_t * res,const float128_t * arg)752 fold_real128_abs(float128_t *res, const float128_t *arg)
753 {
754 fenv_t saved_fenv;
755 set_up_floating_point_environment(&saved_fenv);
756 *res = fabsl(*arg);
757 return check_and_restore_floating_point_environment(&saved_fenv);
758 }
759
760 enum fold_status
fold_real128_sqrt(float128_t * res,const float128_t * arg)761 fold_real128_sqrt(float128_t *res, const float128_t *arg)
762 {
763 fenv_t saved_fenv;
764 set_up_floating_point_environment(&saved_fenv);
765 *res = sqrtl(*arg);
766 return check_and_restore_floating_point_environment(&saved_fenv);
767 }
768
769 enum fold_status
fold_real128_add(float128_t * res,const float128_t * x,const float128_t * y)770 fold_real128_add(float128_t *res, const float128_t *x, const float128_t *y)
771 {
772 fenv_t saved_fenv;
773 set_up_floating_point_environment(&saved_fenv);
774 *res = *x + *y;
775 return check_and_restore_floating_point_environment(&saved_fenv);
776 }
777
778 enum fold_status
fold_real128_subtract(float128_t * res,const float128_t * x,const float128_t * y)779 fold_real128_subtract(float128_t *res, const float128_t *x, const float128_t *y)
780 {
781 fenv_t saved_fenv;
782 set_up_floating_point_environment(&saved_fenv);
783 *res = *x - *y;
784 return check_and_restore_floating_point_environment(&saved_fenv);
785 }
786
787 enum fold_status
fold_real128_multiply(float128_t * res,const float128_t * x,const float128_t * y)788 fold_real128_multiply(float128_t *res, const float128_t *x, const float128_t *y)
789 {
790 fenv_t saved_fenv;
791 set_up_floating_point_environment(&saved_fenv);
792 *res = *x * *y;
793 return check_and_restore_floating_point_environment(&saved_fenv);
794 }
795
796 enum fold_status
fold_real128_divide(float128_t * res,const float128_t * x,const float128_t * y)797 fold_real128_divide(float128_t *res, const float128_t *x, const float128_t *y)
798 {
799 fenv_t saved_fenv;
800 set_up_floating_point_environment(&saved_fenv);
801 *res = *x / *y;
802 return check_and_restore_floating_point_environment(&saved_fenv);
803 }
804
805 enum fold_status
fold_real128_pow(float128_t * res,const float128_t * x,const float128_t * y)806 fold_real128_pow(float128_t *res, const float128_t *x, const float128_t *y)
807 {
808 fenv_t saved_fenv;
809 set_up_floating_point_environment(&saved_fenv);
810 *res = powl(*x, *y);
811 return check_and_restore_floating_point_environment(&saved_fenv);
812 }
813
814 enum fold_status
fold_real128_sin(float128_t * res,const float128_t * arg)815 fold_real128_sin(float128_t *res, const float128_t *arg)
816 {
817 fenv_t saved_fenv;
818 set_up_floating_point_environment(&saved_fenv);
819 *res = sinl(*arg);
820 return check_and_restore_floating_point_environment(&saved_fenv);
821 }
822
823 enum fold_status
fold_real128_cos(float128_t * res,const float128_t * arg)824 fold_real128_cos(float128_t *res, const float128_t *arg)
825 {
826 fenv_t saved_fenv;
827 set_up_floating_point_environment(&saved_fenv);
828 *res = cosl(*arg);
829 return check_and_restore_floating_point_environment(&saved_fenv);
830 }
831
832 enum fold_status
fold_real128_tan(float128_t * res,const float128_t * arg)833 fold_real128_tan(float128_t *res, const float128_t *arg)
834 {
835 fenv_t saved_fenv;
836 set_up_floating_point_environment(&saved_fenv);
837 *res = tanl(*arg);
838 return check_and_restore_floating_point_environment(&saved_fenv);
839 }
840
841 enum fold_status
fold_real128_asin(float128_t * res,const float128_t * arg)842 fold_real128_asin(float128_t *res, const float128_t *arg)
843 {
844 fenv_t saved_fenv;
845 set_up_floating_point_environment(&saved_fenv);
846 *res = asinl(*arg);
847 return check_and_restore_floating_point_environment(&saved_fenv);
848 }
849
850 enum fold_status
fold_real128_acos(float128_t * res,const float128_t * arg)851 fold_real128_acos(float128_t *res, const float128_t *arg)
852 {
853 fenv_t saved_fenv;
854 set_up_floating_point_environment(&saved_fenv);
855 *res = acosl(*arg);
856 return check_and_restore_floating_point_environment(&saved_fenv);
857 }
858
859 enum fold_status
fold_real128_atan(float128_t * res,const float128_t * arg)860 fold_real128_atan(float128_t *res, const float128_t *arg)
861 {
862 fenv_t saved_fenv;
863 set_up_floating_point_environment(&saved_fenv);
864 *res = atanl(*arg);
865 return check_and_restore_floating_point_environment(&saved_fenv);
866 }
867
868 enum fold_status
fold_real128_atan2(float128_t * res,const float128_t * x,const float128_t * y)869 fold_real128_atan2(float128_t *res, const float128_t *x, const float128_t *y)
870 {
871 fenv_t saved_fenv;
872 set_up_floating_point_environment(&saved_fenv);
873 *res = atan2l(*x, *y);
874 return check_and_restore_floating_point_environment(&saved_fenv);
875 }
876
877 enum fold_status
fold_real128_exp(float128_t * res,const float128_t * arg)878 fold_real128_exp(float128_t *res, const float128_t *arg)
879 {
880 fenv_t saved_fenv;
881 set_up_floating_point_environment(&saved_fenv);
882 *res = expl(*arg);
883 return check_and_restore_floating_point_environment(&saved_fenv);
884 }
885
886 enum fold_status
fold_real128_log(float128_t * res,const float128_t * arg)887 fold_real128_log(float128_t *res, const float128_t *arg)
888 {
889 fenv_t saved_fenv;
890 set_up_floating_point_environment(&saved_fenv);
891 *res = logl(*arg);
892 return check_and_restore_floating_point_environment(&saved_fenv);
893 }
894
895 enum fold_status
fold_real128_log10(float128_t * res,const float128_t * arg)896 fold_real128_log10(float128_t *res, const float128_t *arg)
897 {
898 fenv_t saved_fenv;
899 set_up_floating_point_environment(&saved_fenv);
900 *res = log10l(*arg);
901 return check_and_restore_floating_point_environment(&saved_fenv);
902 }
903