00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include "wsint.h"
00072
00073
00074
00075 #define WS_IEEE754_SINGLE_EXP_SIZE 8
00076 #define WS_IEEE754_SINGLE_MANT_SIZE 23
00077 #define WS_IEEE754_SINGLE_BIAS 127
00078
00079 #define WS_IEEE754_SINGLE_EXP_MIN -126
00080 #define WS_IEEE754_SINGLE_EXP_MAX 127
00081
00082 #define WS_IEEE754_POSITIVE_INFINITY 0x7f800000
00083
00084
00085
00086 unsigned char ws_ieee754_nan[4] = {0xff, 0xff, 0xff, 0xff};
00087
00088 unsigned char ws_ieee754_positive_inf[4] = {0x7f, 0x80, 0x00, 0x00};
00089
00090 unsigned char ws_ieee754_negative_inf[4] = {0xff, 0x80, 0x00, 0x00};
00091
00092
00093
00094 WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf)
00095 {
00096 int sign = 0;
00097 WsInt32 exp = 0;
00098 WsUInt32 mant = 0;
00099 int i;
00100 WsIeee754Result result = WS_IEEE754_OK;
00101
00102
00103 if (value < 0.0) {
00104 sign = 1;
00105 value = -value;
00106 }
00107
00108
00109 if (value > 1.0) {
00110
00111 while (value >= 2.0 && exp <= WS_IEEE754_SINGLE_EXP_MAX) {
00112 value /= 2.0;
00113 exp++;
00114 }
00115 if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
00116
00117 exp = 0xff;
00118
00119 if (sign)
00120 result = WS_IEEE754_NEGATIVE_INF;
00121 else
00122 result = WS_IEEE754_POSITIVE_INF;
00123
00124 goto done;
00125 }
00126
00127
00128 value -= 1;
00129 } else {
00130
00131 while (value < 1.0 && exp > WS_IEEE754_SINGLE_EXP_MIN) {
00132 value *= 2.0;
00133 exp--;
00134 }
00135 if (value >= 1.0) {
00136
00137
00138 gw_assert(value >= 1.0);
00139 value -= 1.0;
00140 } else {
00141
00142
00143
00144
00145 exp--;
00146 gw_assert(exp == -127);
00147 }
00148 }
00149
00150 for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
00151 value *= 2.0;
00152 mant <<= 1;
00153
00154 if (value >= 1.0) {
00155 mant |= 1;
00156 value -= 1.0;
00157 }
00158 }
00159
00160
00161
00162 if (value * 2.0 > 1.0) {
00163 mant++;
00164 if (mant == 0x800000) {
00165
00166
00167
00168
00169 mant = 0;
00170 exp++;
00171
00172 if (exp > WS_IEEE754_SINGLE_EXP_MAX) {
00173
00174 exp = 0xff;
00175 goto done;
00176 }
00177 }
00178 }
00179
00180
00181 exp += WS_IEEE754_SINGLE_BIAS;
00182
00183 done:
00184
00185
00186
00187 mant |= exp << 23;
00188 mant |= sign << 31;
00189
00190 buf[3] = (mant & 0x000000ff);
00191 buf[2] = (mant & 0x0000ff00) >> 8;
00192 buf[1] = (mant & 0x00ff0000) >> 16;
00193 buf[0] = (mant & 0xff000000) >> 24;
00194
00195 return result;
00196 }
00197
00198
00199 WsIeee754Result ws_ieee754_decode_single(unsigned char *buf,
00200 double *value_return)
00201 {
00202 WsUInt32 sign = ws_ieee754_single_get_sign(buf);
00203 WsInt32 exp = (WsInt32) ws_ieee754_single_get_exp(buf);
00204 WsUInt32 mant = ws_ieee754_single_get_mant(buf);
00205 double value;
00206 int i;
00207
00208
00209 if (exp == 0xff) {
00210 if (mant == 0)
00211 return sign ? WS_IEEE754_NEGATIVE_INF : WS_IEEE754_POSITIVE_INF;
00212
00213 return WS_IEEE754_NAN;
00214 }
00215
00216
00217 value = 0.0;
00218 for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) {
00219 if (mant & 0x1)
00220 value += 1.0;
00221
00222 value /= 2.0;
00223 mant >>= 1;
00224 }
00225
00226
00227 if (exp == 0)
00228
00229 exp = -126;
00230 else {
00231
00232 value += 1.0;
00233 exp -= WS_IEEE754_SINGLE_BIAS;
00234 }
00235
00236
00237 while (exp > 0) {
00238 value *= 2;
00239 exp--;
00240 }
00241 while (exp < 0) {
00242 value /= 2;
00243 exp++;
00244 }
00245
00246
00247 if (sign)
00248 value = -value;
00249
00250 *value_return = value;
00251
00252 return WS_IEEE754_OK;
00253 }
00254
00255
00256 WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf)
00257 {
00258 return (buf[0] & 0x80) >> 7;
00259 }
00260
00261
00262 WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf)
00263 {
00264 WsUInt32 value = buf[0] & 0x7f;
00265
00266 value <<= 1;
00267 value |= (buf[1] & 0x80) >> 7;
00268
00269 return value;
00270 }
00271
00272
00273 WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf)
00274 {
00275 WsUInt32 value = buf[1] & 0x7f;
00276
00277 value <<= 8;
00278 value |= buf[2];
00279
00280 value <<= 8;
00281 value |= buf[3];
00282
00283 return value;
00284 }
00285
00286 #if 0
00287
00288
00289 void ws_ieee754_print(unsigned char *buf)
00290 {
00291 int i, j;
00292
00293 for (i = 0; i < 4; i++) {
00294 unsigned char mask = 0x80;
00295 unsigned char ch = buf[i];
00296
00297 for (j = 0; j < 8; j++) {
00298 if (ch & mask)
00299 printf("1");
00300 else
00301 printf("0");
00302
00303 if ((i == 0 && j == 0)
00304 || (i == 1 && j == 0))
00305 printf(" ");
00306
00307 mask >>= 1;
00308 }
00309 }
00310 printf("\n");
00311 }
00312
00313 #include <math.h>
00314 #include <stdlib.h>
00315 #include <machine/ieee.h>
00316
00317 void check_value(double num)
00318 {
00319 float native = num;
00320 unsigned char buf[4];
00321 struct ieee_single *s = (struct ieee_single *) & native;
00322 unsigned int *uip = (unsigned int *) s;
00323 unsigned int n = ntohl(*uip);
00324 double d;
00325
00326 ws_ieee754_encode_single(num, buf);
00327 if (memcmp(buf, &n, 4) != 0) {
00328 printf("\n");
00329 printf("%f failed:\n", num);
00330 printf("ws: ");
00331 ws_ieee754_print(buf);
00332 printf("native: ");
00333 ws_ieee754_print((unsigned char *) &n);
00334 abort();
00335 }
00336
00337 if (ws_ieee754_decode_single(buf, &d) != WS_IEEE754_OK
00338 || d != native) {
00339 printf("\ndecode of %f failed: got %f\n", num, d);
00340 abort();
00341 }
00342 }
00343
00344
00345 int main(int argc, char *argv[])
00346 {
00347 unsigned char buf[4];
00348 unsigned int rounds = 0;
00349
00350 if (argc > 1) {
00351 int i;
00352
00353 for (i = 1; i < argc; i++)
00354 check_value(strtod(argv[1], NULL));
00355
00356 return 0;
00357 }
00358
00359 ws_ieee754_encode_single(5.75, buf);
00360 ws_ieee754_print(buf);
00361 check_value(5.75);
00362
00363 ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf);
00364 ws_ieee754_print(buf);
00365 check_value(340282346638528859811704183484516925440.0);
00366
00367 ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf);
00368 ws_ieee754_print(buf);
00369 check_value( -340282346638528859811704183484516925440.0);
00370
00371 ws_ieee754_encode_single(3.0 * pow(2, -129), buf);
00372 ws_ieee754_print(buf);
00373 check_value(3.0 * pow(2, -129));
00374
00375 ws_ieee754_encode_single(pow(2, -149), buf);
00376 ws_ieee754_print(buf);
00377 check_value(pow(2, -149));
00378
00379 ws_ieee754_encode_single(pow(2, -149) * .1, buf);
00380 ws_ieee754_print(buf);
00381 check_value(pow(2, -149) * .1);
00382
00383 ws_ieee754_encode_single( -pow(2, -149), buf);
00384 ws_ieee754_print(buf);
00385 check_value( -pow(2, -149));
00386
00387 ws_ieee754_encode_single( -pow(2, -149) * .1, buf);
00388 ws_ieee754_print(buf);
00389
00390 while (1) {
00391 double a = random();
00392 double b = random();
00393
00394 if (b == 0.0)
00395 continue;
00396
00397 check_value(a / b);
00398 check_value(a * b);
00399
00400 if ((++rounds % 100000) == 0) {
00401 printf("%d ", rounds);
00402 fflush(stdout);
00403 }
00404
00405 }
00406
00407 return 0;
00408 }
00409 #endif
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.