fenv: Separate exception testing from environment save/restore.
[altfloat.git] / cfloat.c
blob58af4b916905023de1e060f397119b2afd18b044
1 /*
2 * Floating point functions that are difficult or impossible to implement
3 * in pure Haskell.
5 * Copyright (C) 2009-2010 Nick Bowler.
7 * License BSD2: 2-clause BSD license. See LICENSE for full terms.
8 * This is free software: you are free to change and redistribute it.
9 * There is NO WARRANTY, to the extent permitted by law.
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <math.h>
15 #include <fenv.h>
17 #include "cfloat.h"
19 #pragma STDC FENV_ACCESS ON
21 int double_format(char *buf, char spec, int precision, double val)
23 char fmt[] = "%.*f";
24 fmt[3] = spec;
26 if (buf == NULL)
27 return snprintf(NULL, 0, fmt, precision, val);
28 return sprintf(buf, fmt, precision, val);
31 double double_signum(double val)
33 if (signbit(val))
34 return -1;
35 return 1;
38 float float_signum(float val)
40 if (signbit(val))
41 return -1;
42 return 1;
45 int double_classify(double val)
47 switch (fpclassify(val)) {
48 case FP_INFINITE:
49 return 0;
50 case FP_NAN:
51 return 1;
52 case FP_NORMAL:
53 return 2;
54 case FP_SUBNORMAL:
55 return 3;
56 case FP_ZERO:
57 return 4;
60 return -1;
63 int float_classify(float val)
65 switch (fpclassify(val)) {
66 case FP_INFINITE:
67 return 0;
68 case FP_NAN:
69 return 1;
70 case FP_NORMAL:
71 return 2;
72 case FP_SUBNORMAL:
73 return 3;
74 case FP_ZERO:
75 return 4;
78 return -1;
81 int double_compare(double a, double b)
83 if (isless(a, b))
84 return 0;
85 if (a == b)
86 return 1;
87 if (isgreater(a, b))
88 return 2;
89 if (isunordered(a, b))
90 return 3;
91 return -1;
94 int float_compare(float a, float b)
96 if (isless(a, b))
97 return 0;
98 if (a == b)
99 return 1;
100 if (isgreater(a, b))
101 return 2;
102 if (isunordered(a, b))
103 return 3;
104 return -1;
107 int set_roundmode(int mode)
109 int cmode;
111 switch (mode) {
112 case 0:
113 cmode = FE_TONEAREST;
114 break;
115 case 1:
116 cmode = FE_UPWARD;
117 break;
118 case 2:
119 cmode = FE_DOWNWARD;
120 break;
121 case 3:
122 cmode = FE_TOWARDZERO;
123 break;
124 default:
125 return -1;
128 return fesetround(cmode);
131 int get_roundmode(void)
133 int cmode = fegetround();
135 switch (cmode) {
136 case FE_TONEAREST:
137 return 0;
138 case FE_UPWARD:
139 return 1;
140 case FE_DOWNWARD:
141 return 2;
142 case FE_TOWARDZERO:
143 return 3;
144 default:
145 return -1;
149 unsigned fenv_test_excepts(void)
151 int raw_excepts = fetestexcept(FE_ALL_EXCEPT);
152 unsigned excepts = 0;
154 #ifdef FE_DIVBYZERO
155 if (raw_excepts & FE_DIVBYZERO) excepts |= 0x01;
156 #endif
157 #ifdef FE_INEXACT
158 if (raw_excepts & FE_INEXACT) excepts |= 0x02;
159 #endif
160 #ifdef FE_INVALID
161 if (raw_excepts & FE_INVALID) excepts |= 0x04;
162 #endif
163 #ifdef FE_OVERFLOW
164 if (raw_excepts & FE_OVERFLOW) excepts |= 0x08;
165 #endif
166 #ifdef FE_UNDERFLOW
167 if (raw_excepts & FE_UNDERFLOW) excepts |= 0x10;
168 #endif
170 return excepts;
173 int fenv_raise_excepts(unsigned excepts)
175 int raw_excepts = 0;
177 #ifdef FE_DIVBYZERO
178 if (excepts & 0x01) raw_excepts |= FE_DIVBYZERO;
179 #endif
180 #ifdef FE_INEXACT
181 if (excepts & 0x02) raw_excepts |= FE_INEXACT;
182 #endif
183 #ifdef FE_INVALID
184 if (excepts & 0x04) raw_excepts |= FE_INVALID;
185 #endif
186 #ifdef FE_OVERFLOW
187 if (excepts & 0x08) raw_excepts |= FE_OVERFLOW;
188 #endif
189 #ifdef FE_UNDERFLOW
190 if (excepts & 0x10) raw_excepts |= FE_UNDERFLOW;
191 #endif
192 return feraiseexcept(raw_excepts);