1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "air.h" |
25 |
|
|
#include "privateAir.h" |
26 |
|
|
|
27 |
|
|
/* |
28 |
|
|
******** airSanity() |
29 |
|
|
** |
30 |
|
|
** Does run-time checks to see if the compile-time constants are correct. |
31 |
|
|
** Returns a value from the airInsane* enum; airInsane_not means all |
32 |
|
|
** the checks came back without detecting any problems. |
33 |
|
|
*/ |
34 |
|
|
int |
35 |
|
|
airSanity(void) { |
36 |
|
|
double nanValue, pinf, ninf; |
37 |
|
|
float nanF, pinfF, ninfF; |
38 |
|
40 |
unsigned int sign, expvalue, mant; |
39 |
|
|
int tmpI; |
40 |
|
|
char endian; |
41 |
|
|
unsigned char uc0, uc1; |
42 |
|
|
static int _airSanity=0; |
43 |
|
|
|
44 |
✗✓ |
20 |
if (_airSanity) { |
45 |
|
|
return airInsane_not; |
46 |
|
|
} |
47 |
|
|
|
48 |
|
|
/* now that there is no more compile-time endian info, this is |
49 |
|
|
merely double checking that airMyEndian() works, and returns |
50 |
|
|
the constants (either 1234, pronounced "little endian", or |
51 |
|
|
4321, "big endian") that are defined in air.h */ |
52 |
|
|
tmpI = 1; |
53 |
|
|
endian = !(*((char*)(&tmpI))); |
54 |
✗✓ |
20 |
if (endian) { |
55 |
|
|
/* big endian */ |
56 |
✗✗ |
20 |
if (4321 != airMyEndian()) { |
57 |
|
|
return airInsane_endian; |
58 |
|
|
} |
59 |
|
|
} else { |
60 |
✗✓ |
20 |
if (1234 != airMyEndian()) { |
61 |
|
|
return airInsane_endian; |
62 |
|
|
} |
63 |
|
|
} |
64 |
|
|
|
65 |
|
|
/* checks on sizes of uchar, float, int, double, airLLong */ |
66 |
|
|
uc0 = 255; |
67 |
|
|
uc1 = AIR_CAST(unsigned char, AIR_INT(uc0) + 1); /* want to overflow */ |
68 |
✓✗✗✓
|
40 |
if (!( 255 == uc0 && 0 == uc1 )) { |
69 |
|
|
return airInsane_UCSize; |
70 |
|
|
} |
71 |
|
|
/* these justify the AIR_EXISTS_F and AIR_EXISTS_D macros */ |
72 |
|
|
if (!( (sizeof(float) == sizeof(int)) && (4 == sizeof(int)) )) { |
73 |
|
|
return airInsane_FISize; |
74 |
|
|
} |
75 |
|
|
if (!( (sizeof(double) == sizeof(airLLong)) && (8 == sizeof(airLLong)) )) { |
76 |
|
|
return airInsane_DLSize; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
/* run-time NaN checks */ |
80 |
|
|
pinf = DBL_MAX; |
81 |
|
20 |
pinf = _airSanityHelper(pinf); |
82 |
|
20 |
pinf = _airSanityHelper(pinf); |
83 |
|
20 |
pinf = _airSanityHelper(pinf); |
84 |
✗✓ |
20 |
if (AIR_EXISTS(pinf)) { |
85 |
|
|
return airInsane_pInfExists; |
86 |
|
|
} |
87 |
|
20 |
ninf = -pinf; |
88 |
✗✓ |
20 |
if (AIR_EXISTS(ninf)) { |
89 |
|
|
return airInsane_nInfExists; |
90 |
|
|
} |
91 |
|
20 |
nanValue = pinf / pinf; |
92 |
✗✓ |
20 |
if (AIR_EXISTS(nanValue)) { |
93 |
|
|
return airInsane_NaNExists; |
94 |
|
|
} |
95 |
|
20 |
nanF = (float)nanValue; |
96 |
|
20 |
pinfF = (float)pinf; |
97 |
|
20 |
ninfF = (float)ninf; |
98 |
|
20 |
airFPValToParts_f(&sign, &expvalue, &mant, nanF); |
99 |
|
20 |
mant >>= 22; |
100 |
✗✓ |
20 |
if (AIR_QNANHIBIT != (int)mant) { |
101 |
|
|
return airInsane_QNaNHiBit; |
102 |
|
|
} |
103 |
|
|
|
104 |
✗✓ |
40 |
if (!( airFP_QNAN == airFPClass_f(AIR_NAN) |
105 |
✓✗ |
40 |
&& airFP_QNAN == airFPClass_f(AIR_QNAN) |
106 |
|
|
/* |
107 |
|
|
As of July 4 2012 GLK decides that the signalling NaN tests are |
108 |
|
|
more trouble than they're worth: the signal-ness of the NaN is not |
109 |
|
|
preserved in double-float conversion for some platforms (so |
110 |
|
|
airFP_SNAN == airFPClass_d(AIR_SNAN) has never been enforced), and |
111 |
|
|
there are more platforms for which (apparently) passing AIR_SNAN to |
112 |
|
|
airFPClass_d changes it to a quiet NaN, which defeats the purpose |
113 |
|
|
of the test. To summarize, given that: |
114 |
|
|
** AIR_NAN and AIR_QNAN are checked here to be quiet NaN, after |
115 |
|
|
casting to both float and double, |
116 |
|
|
** quiet NaN "hi bit" is tested above, and that |
117 |
|
|
** quiet and signalling NaN are mutually exclusive, |
118 |
|
|
skipping the signalling NaN tests is unlikely to undermine knowing |
119 |
|
|
the correctness of the compile-time representation of NaNs. So the |
120 |
|
|
following line is now commented out for all platforms. |
121 |
|
|
*/ |
122 |
|
|
/* && airFP_SNAN == airFPClass_f(AIR_SNAN) */ |
123 |
✓✗ |
40 |
&& airFP_QNAN == airFPClass_d(AIR_NAN) |
124 |
✓✗ |
40 |
&& airFP_QNAN == airFPClass_d(AIR_QNAN) )) { |
125 |
|
|
return airInsane_AIR_NAN; |
126 |
|
|
} |
127 |
✗✓ |
40 |
if (!(airFP_QNAN == airFPClass_f(nanF) |
128 |
✓✗ |
40 |
&& airFP_POS_INF == airFPClass_f(pinfF) |
129 |
✓✗ |
40 |
&& airFP_NEG_INF == airFPClass_f(ninfF))) { |
130 |
|
|
/* really, this is verifying that assigning from a double to a |
131 |
|
|
float maintains the FPClass for non-existent values */ |
132 |
|
|
return airInsane_FltDblFPClass; |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
/* just make sure AIR_DIO is reasonably set |
136 |
|
|
(actually, this should be done by include/teemDio.h) */ |
137 |
✗✓ |
20 |
switch (AIR_DIO) { |
138 |
|
|
case 0: break; |
139 |
|
|
case 1: break; |
140 |
|
|
default: |
141 |
|
|
return airInsane_dio; |
142 |
|
|
} |
143 |
|
|
|
144 |
|
20 |
_airSanity = 1; |
145 |
|
20 |
return airInsane_not; |
146 |
|
20 |
} |
147 |
|
|
|
148 |
|
|
static const char |
149 |
|
|
_airInsaneErr[AIR_INSANE_MAX+1][AIR_STRLEN_MED] = { |
150 |
|
|
"sanity checked PASSED!", |
151 |
|
|
"airMyEndian() is wrong", |
152 |
|
|
"AIR_EXISTS(+inf) was true", |
153 |
|
|
"AIR_EXISTS(-inf) was true", |
154 |
|
|
"AIR_EXISTS(NaN) was true", |
155 |
|
|
"air_FPClass_f() wrong after double->float assignment", |
156 |
|
|
"TEEM_QNANHIBIT is wrong", |
157 |
|
|
"airFPClass(AIR_QNAN) wrong", |
158 |
|
|
"TEEM_DIO has invalid value", |
159 |
|
|
"unsigned char isn't 8 bits", |
160 |
|
|
"sizeof(float), sizeof(int) not both == 4", |
161 |
|
|
"sizeof(double), sizeof(airLLong) not both == 8", |
162 |
|
|
}; |
163 |
|
|
|
164 |
|
|
static const char _airBadInsane[] = "(invalid insane value)"; |
165 |
|
|
|
166 |
|
|
const char * |
167 |
|
|
airInsaneErr(int insane) { |
168 |
|
|
|
169 |
|
|
if (AIR_IN_CL(0, insane, AIR_INSANE_MAX)) { |
170 |
|
|
return _airInsaneErr[insane]; |
171 |
|
|
} |
172 |
|
|
else { |
173 |
|
|
return _airBadInsane; |
174 |
|
|
} |
175 |
|
|
} |
176 |
|
|
|