00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "floatformat.h"
00025 #include <math.h>
00026 #ifdef __STDC__
00027 #include <stddef.h>
00028 extern void *memcpy (void *s1, const void *s2, size_t n);
00029 extern void *memset (void *s, int c, size_t n);
00030 #else
00031 extern char *memcpy ();
00032 extern char *memset ();
00033 #endif
00034
00035
00036
00037
00038 #define FLOATFORMAT_CHAR_BIT 8
00039
00040
00041 const struct floatformat floatformat_ieee_single_big =
00042 {
00043 floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
00044 floatformat_intbit_no,
00045 "floatformat_ieee_single_big"
00046 };
00047 const struct floatformat floatformat_ieee_single_little =
00048 {
00049 floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
00050 floatformat_intbit_no,
00051 "floatformat_ieee_single_little"
00052 };
00053 const struct floatformat floatformat_ieee_double_big =
00054 {
00055 floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
00056 floatformat_intbit_no,
00057 "floatformat_ieee_double_big"
00058 };
00059 const struct floatformat floatformat_ieee_double_little =
00060 {
00061 floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
00062 floatformat_intbit_no,
00063 "floatformat_ieee_double_little"
00064 };
00065
00066
00067
00068
00069 const struct floatformat floatformat_ieee_double_littlebyte_bigword =
00070 {
00071 floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
00072 floatformat_intbit_no,
00073 "floatformat_ieee_double_littlebyte_bigword"
00074 };
00075
00076 const struct floatformat floatformat_i387_ext =
00077 {
00078 floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00079 floatformat_intbit_yes,
00080 "floatformat_i387_ext"
00081 };
00082 const struct floatformat floatformat_m68881_ext =
00083 {
00084
00085 floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
00086 floatformat_intbit_yes,
00087 "floatformat_m68881_ext"
00088 };
00089 const struct floatformat floatformat_i960_ext =
00090 {
00091
00092 floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
00093 floatformat_intbit_yes,
00094 "floatformat_i960_ext"
00095 };
00096 const struct floatformat floatformat_m88110_ext =
00097 {
00098 floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00099 floatformat_intbit_yes,
00100 "floatformat_m88110_ext"
00101 };
00102 const struct floatformat floatformat_m88110_harris_ext =
00103 {
00104
00105
00106 floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
00107 floatformat_intbit_no,
00108 "floatformat_m88110_ext_harris"
00109 };
00110 const struct floatformat floatformat_arm_ext_big =
00111 {
00112
00113 floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00114 floatformat_intbit_yes,
00115 "floatformat_arm_ext_big"
00116 };
00117 const struct floatformat floatformat_arm_ext_littlebyte_bigword =
00118 {
00119
00120 floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00121 floatformat_intbit_yes,
00122 "floatformat_arm_ext_littlebyte_bigword"
00123 };
00124 const struct floatformat floatformat_ia64_spill_big =
00125 {
00126 floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00127 floatformat_intbit_yes,
00128 "floatformat_ia64_spill_big"
00129 };
00130 const struct floatformat floatformat_ia64_spill_little =
00131 {
00132 floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00133 floatformat_intbit_yes,
00134 "floatformat_ia64_spill_little"
00135 };
00136 const struct floatformat floatformat_ia64_quad_big =
00137 {
00138 floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00139 floatformat_intbit_no,
00140 "floatformat_ia64_quad_big"
00141 };
00142 const struct floatformat floatformat_ia64_quad_little =
00143 {
00144 floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00145 floatformat_intbit_no,
00146 "floatformat_ia64_quad_little"
00147 };
00148
00149 static unsigned long get_field PARAMS ((unsigned char *,
00150 enum floatformat_byteorders,
00151 unsigned int,
00152 unsigned int,
00153 unsigned int));
00154
00155
00156
00157 static unsigned long
00158 get_field (data, order, total_len, start, len)
00159 unsigned char *data;
00160 enum floatformat_byteorders order;
00161 unsigned int total_len;
00162 unsigned int start;
00163 unsigned int len;
00164 {
00165 unsigned long result;
00166 unsigned int cur_byte;
00167 int cur_bitshift;
00168
00169
00170 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
00171 if (order == floatformat_little)
00172 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
00173 cur_bitshift =
00174 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
00175 result = *(data + cur_byte) >> (-cur_bitshift);
00176 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00177 if (order == floatformat_little)
00178 ++cur_byte;
00179 else
00180 --cur_byte;
00181
00182
00183 while ((unsigned int) cur_bitshift < len)
00184 {
00185 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
00186
00187
00188 result |=
00189 (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
00190 << cur_bitshift;
00191 else
00192 result |= *(data + cur_byte) << cur_bitshift;
00193 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00194 if (order == floatformat_little)
00195 ++cur_byte;
00196 else
00197 --cur_byte;
00198 }
00199 return result;
00200 }
00201
00202 #ifndef min
00203 #define min(a, b) ((a) < (b) ? (a) : (b))
00204 #endif
00205
00206
00207
00208
00209
00210 void
00211 floatformat_to_double (fmt, from, to)
00212 const struct floatformat *fmt;
00213 char *from;
00214 double *to;
00215 {
00216 unsigned char *ufrom = (unsigned char *)from;
00217 double dto;
00218 long exponent;
00219 unsigned long mant;
00220 unsigned int mant_bits, mant_off;
00221 int mant_bits_left;
00222 int special_exponent;
00223
00224 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00225 fmt->exp_start, fmt->exp_len);
00226
00227
00228
00229
00230 mant_bits_left = fmt->man_len;
00231 mant_off = fmt->man_start;
00232 dto = 0.0;
00233
00234 special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
00235
00236
00237 if (!special_exponent)
00238 exponent -= fmt->exp_bias;
00239
00240
00241
00242
00243
00244
00245
00246 if (!special_exponent)
00247 {
00248 if (fmt->intbit == floatformat_intbit_no)
00249 dto = ldexp (1.0, exponent);
00250 else
00251 exponent++;
00252 }
00253
00254 while (mant_bits_left > 0)
00255 {
00256 mant_bits = min (mant_bits_left, 32);
00257
00258 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00259 mant_off, mant_bits);
00260
00261 dto += ldexp ((double)mant, exponent - mant_bits);
00262 exponent -= mant_bits;
00263 mant_off += mant_bits;
00264 mant_bits_left -= mant_bits;
00265 }
00266
00267
00268 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
00269 dto = -dto;
00270 *to = dto;
00271 }
00272
00273 static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders,
00274 unsigned int,
00275 unsigned int,
00276 unsigned int,
00277 unsigned long));
00278
00279
00280
00281 static void
00282 put_field (data, order, total_len, start, len, stuff_to_put)
00283 unsigned char *data;
00284 enum floatformat_byteorders order;
00285 unsigned int total_len;
00286 unsigned int start;
00287 unsigned int len;
00288 unsigned long stuff_to_put;
00289 {
00290 unsigned int cur_byte;
00291 int cur_bitshift;
00292
00293
00294 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
00295 if (order == floatformat_little)
00296 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
00297 cur_bitshift =
00298 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
00299 *(data + cur_byte) &=
00300 ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
00301 *(data + cur_byte) |=
00302 (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
00303 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00304 if (order == floatformat_little)
00305 ++cur_byte;
00306 else
00307 --cur_byte;
00308
00309
00310 while ((unsigned int) cur_bitshift < len)
00311 {
00312 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
00313 {
00314
00315 *(data + cur_byte) &=
00316 ~((1 << (len - cur_bitshift)) - 1);
00317 *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
00318 }
00319 else
00320 *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
00321 & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
00322 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00323 if (order == floatformat_little)
00324 ++cur_byte;
00325 else
00326 --cur_byte;
00327 }
00328 }
00329
00330
00331
00332
00333
00334 void
00335 floatformat_from_double (fmt, from, to)
00336 const struct floatformat *fmt;
00337 double *from;
00338 char *to;
00339 {
00340 double dfrom;
00341 int exponent;
00342 double mant;
00343 unsigned int mant_bits, mant_off;
00344 int mant_bits_left;
00345 unsigned char *uto = (unsigned char *)to;
00346
00347 memcpy (&dfrom, from, sizeof (dfrom));
00348 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
00349 if (dfrom == 0)
00350 return;
00351 if (dfrom != dfrom)
00352 {
00353
00354 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00355 fmt->exp_len, fmt->exp_nan);
00356
00357 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
00358 32, 1);
00359 return;
00360 }
00361
00362
00363 if (dfrom < 0)
00364 {
00365 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
00366 dfrom = -dfrom;
00367 }
00368
00369
00370
00371 mant = frexp (dfrom, &exponent);
00372 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
00373 exponent + fmt->exp_bias - 1);
00374
00375 mant_bits_left = fmt->man_len;
00376 mant_off = fmt->man_start;
00377 while (mant_bits_left > 0)
00378 {
00379 unsigned long mant_long;
00380 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
00381
00382 mant *= 4294967296.0;
00383 mant_long = (unsigned long)mant;
00384 mant -= mant_long;
00385
00386
00387
00388
00389
00390 if ((unsigned int) mant_bits_left == fmt->man_len
00391 && fmt->intbit == floatformat_intbit_no)
00392 {
00393 mant_long &= 0x7fffffff;
00394 mant_bits -= 1;
00395 }
00396 else if (mant_bits < 32)
00397 {
00398
00399
00400 mant_long >>= 32 - mant_bits;
00401 }
00402
00403 put_field (uto, fmt->byteorder, fmt->totalsize,
00404 mant_off, mant_bits, mant_long);
00405 mant_off += mant_bits;
00406 mant_bits_left -= mant_bits;
00407 }
00408 }
00409
00410
00411 #ifdef IEEE_DEBUG
00412
00413
00414
00415 void
00416 ieee_test (n)
00417 double n;
00418 {
00419 double result;
00420 char exten[16];
00421
00422 floatformat_to_double (&floatformat_ieee_double_big, &n, &result);
00423 if (n != result)
00424 printf ("Differ(to): %.20g -> %.20g\n", n, result);
00425 floatformat_from_double (&floatformat_ieee_double_big, &n, &result);
00426 if (n != result)
00427 printf ("Differ(from): %.20g -> %.20g\n", n, result);
00428
00429 floatformat_from_double (&floatformat_m68881_ext, &n, exten);
00430 floatformat_to_double (&floatformat_m68881_ext, exten, &result);
00431 if (n != result)
00432 printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
00433
00434 #if IEEE_DEBUG > 1
00435
00436 {
00437 long double ex = *(long double *)exten;
00438 if (ex != n)
00439 printf ("Differ(from vs. extended): %.20g\n", n);
00440 }
00441 #endif
00442 }
00443
00444 int
00445 main ()
00446 {
00447 ieee_test (0.5);
00448 ieee_test (256.0);
00449 ieee_test (0.12345);
00450 ieee_test (234235.78907234);
00451 ieee_test (-512.0);
00452 ieee_test (-0.004321);
00453 return 0;
00454 }
00455 #endif