00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define _GNU_SOURCE
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026
00027 #include <math.h>
00028
00029 #ifdef HAVE_STRING_H
00030 #include <string.h>
00031 #endif
00032
00033 #include "ansidecl.h"
00034 #include "libiberty.h"
00035 #include "floatformat.h"
00036
00037 #ifndef INFINITY
00038 #ifdef HUGE_VAL
00039 #define INFINITY HUGE_VAL
00040 #else
00041 #define INFINITY (1.0 / 0.0)
00042 #endif
00043 #endif
00044
00045 #ifndef NAN
00046 #define NAN (0.0 / 0.0)
00047 #endif
00048
00049 static unsigned long get_field PARAMS ((const unsigned char *,
00050 enum floatformat_byteorders,
00051 unsigned int,
00052 unsigned int,
00053 unsigned int));
00054 static int floatformat_always_valid PARAMS ((const struct floatformat *fmt,
00055 const char *from));
00056
00057 static int
00058 floatformat_always_valid (fmt, from)
00059 const struct floatformat *fmt ATTRIBUTE_UNUSED;
00060 const char *from ATTRIBUTE_UNUSED;
00061 {
00062 return 1;
00063 }
00064
00065
00066
00067
00068 #define FLOATFORMAT_CHAR_BIT 8
00069
00070
00071 const struct floatformat floatformat_ieee_single_big =
00072 {
00073 floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
00074 floatformat_intbit_no,
00075 "floatformat_ieee_single_big",
00076 floatformat_always_valid
00077 };
00078 const struct floatformat floatformat_ieee_single_little =
00079 {
00080 floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
00081 floatformat_intbit_no,
00082 "floatformat_ieee_single_little",
00083 floatformat_always_valid
00084 };
00085 const struct floatformat floatformat_ieee_double_big =
00086 {
00087 floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
00088 floatformat_intbit_no,
00089 "floatformat_ieee_double_big",
00090 floatformat_always_valid
00091 };
00092 const struct floatformat floatformat_ieee_double_little =
00093 {
00094 floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
00095 floatformat_intbit_no,
00096 "floatformat_ieee_double_little",
00097 floatformat_always_valid
00098 };
00099
00100
00101
00102
00103 const struct floatformat floatformat_ieee_double_littlebyte_bigword =
00104 {
00105 floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
00106 floatformat_intbit_no,
00107 "floatformat_ieee_double_littlebyte_bigword",
00108 floatformat_always_valid
00109 };
00110
00111 static int floatformat_i387_ext_is_valid PARAMS ((const struct floatformat *fmt, const char *from));
00112
00113 static int
00114 floatformat_i387_ext_is_valid (fmt, from)
00115 const struct floatformat *fmt;
00116 const char *from;
00117 {
00118
00119
00120
00121
00122 unsigned long exponent, int_bit;
00123 const unsigned char *ufrom = (const unsigned char *) from;
00124
00125 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00126 fmt->exp_start, fmt->exp_len);
00127 int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00128 fmt->man_start, 1);
00129
00130 if ((exponent == 0) != (int_bit == 0))
00131 return 0;
00132 else
00133 return 1;
00134 }
00135
00136 const struct floatformat floatformat_i387_ext =
00137 {
00138 floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00139 floatformat_intbit_yes,
00140 "floatformat_i387_ext",
00141 floatformat_i387_ext_is_valid
00142 };
00143 const struct floatformat floatformat_m68881_ext =
00144 {
00145
00146 floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
00147 floatformat_intbit_yes,
00148 "floatformat_m68881_ext",
00149 floatformat_always_valid
00150 };
00151 const struct floatformat floatformat_i960_ext =
00152 {
00153
00154 floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
00155 floatformat_intbit_yes,
00156 "floatformat_i960_ext",
00157 floatformat_always_valid
00158 };
00159 const struct floatformat floatformat_m88110_ext =
00160 {
00161 floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
00162 floatformat_intbit_yes,
00163 "floatformat_m88110_ext",
00164 floatformat_always_valid
00165 };
00166 const struct floatformat floatformat_m88110_harris_ext =
00167 {
00168
00169
00170 floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
00171 floatformat_intbit_no,
00172 "floatformat_m88110_ext_harris",
00173 floatformat_always_valid
00174 };
00175 const struct floatformat floatformat_arm_ext_big =
00176 {
00177
00178 floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00179 floatformat_intbit_yes,
00180 "floatformat_arm_ext_big",
00181 floatformat_always_valid
00182 };
00183 const struct floatformat floatformat_arm_ext_littlebyte_bigword =
00184 {
00185
00186 floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
00187 floatformat_intbit_yes,
00188 "floatformat_arm_ext_littlebyte_bigword",
00189 floatformat_always_valid
00190 };
00191 const struct floatformat floatformat_ia64_spill_big =
00192 {
00193 floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00194 floatformat_intbit_yes,
00195 "floatformat_ia64_spill_big",
00196 floatformat_always_valid
00197 };
00198 const struct floatformat floatformat_ia64_spill_little =
00199 {
00200 floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
00201 floatformat_intbit_yes,
00202 "floatformat_ia64_spill_little",
00203 floatformat_always_valid
00204 };
00205 const struct floatformat floatformat_ia64_quad_big =
00206 {
00207 floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00208 floatformat_intbit_no,
00209 "floatformat_ia64_quad_big",
00210 floatformat_always_valid
00211 };
00212 const struct floatformat floatformat_ia64_quad_little =
00213 {
00214 floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
00215 floatformat_intbit_no,
00216 "floatformat_ia64_quad_little",
00217 floatformat_always_valid
00218 };
00219
00220
00221
00222 static unsigned long
00223 get_field (data, order, total_len, start, len)
00224 const unsigned char *data;
00225 enum floatformat_byteorders order;
00226 unsigned int total_len;
00227 unsigned int start;
00228 unsigned int len;
00229 {
00230 unsigned long result;
00231 unsigned int cur_byte;
00232 int cur_bitshift;
00233
00234
00235 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
00236 if (order == floatformat_little)
00237 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
00238 cur_bitshift =
00239 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
00240 result = *(data + cur_byte) >> (-cur_bitshift);
00241 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00242 if (order == floatformat_little)
00243 ++cur_byte;
00244 else
00245 --cur_byte;
00246
00247
00248 while ((unsigned int) cur_bitshift < len)
00249 {
00250 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
00251
00252
00253 result |=
00254 (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
00255 << cur_bitshift;
00256 else
00257 result |= *(data + cur_byte) << cur_bitshift;
00258 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00259 if (order == floatformat_little)
00260 ++cur_byte;
00261 else
00262 --cur_byte;
00263 }
00264 return result;
00265 }
00266
00267 #ifndef min
00268 #define min(a, b) ((a) < (b) ? (a) : (b))
00269 #endif
00270
00271
00272
00273
00274
00275 void
00276 floatformat_to_double (fmt, from, to)
00277 const struct floatformat *fmt;
00278 const char *from;
00279 double *to;
00280 {
00281 const unsigned char *ufrom = (const unsigned char *)from;
00282 double dto;
00283 long exponent;
00284 unsigned long mant;
00285 unsigned int mant_bits, mant_off;
00286 int mant_bits_left;
00287 int special_exponent;
00288
00289 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00290 fmt->exp_start, fmt->exp_len);
00291
00292
00293
00294
00295 if ((unsigned long) exponent == fmt->exp_nan)
00296 {
00297 int nan;
00298
00299 mant_off = fmt->man_start;
00300 mant_bits_left = fmt->man_len;
00301 nan = 0;
00302 while (mant_bits_left > 0)
00303 {
00304 mant_bits = min (mant_bits_left, 32);
00305
00306 if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
00307 mant_off, mant_bits) != 0)
00308 {
00309
00310 nan = 1;
00311 break;
00312 }
00313
00314 mant_off += mant_bits;
00315 mant_bits_left -= mant_bits;
00316 }
00317
00318 if (nan)
00319 dto = NAN;
00320 else
00321 dto = INFINITY;
00322
00323 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
00324 dto = -dto;
00325
00326 *to = dto;
00327
00328 return;
00329 }
00330
00331 mant_bits_left = fmt->man_len;
00332 mant_off = fmt->man_start;
00333 dto = 0.0;
00334
00335 special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
00336
00337
00338 if (!special_exponent)
00339 exponent -= fmt->exp_bias;
00340
00341
00342
00343
00344
00345
00346
00347 if (!special_exponent)
00348 {
00349 if (fmt->intbit == floatformat_intbit_no)
00350 dto = ldexp (1.0, exponent);
00351 else
00352 exponent++;
00353 }
00354
00355 while (mant_bits_left > 0)
00356 {
00357 mant_bits = min (mant_bits_left, 32);
00358
00359 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
00360 mant_off, mant_bits);
00361
00362
00363
00364 if (exponent == 0 && mant != 0)
00365 dto += ldexp ((double)mant,
00366 (- fmt->exp_bias
00367 - mant_bits
00368 - (mant_off - fmt->man_start)
00369 + 1));
00370 else
00371 dto += ldexp ((double)mant, exponent - mant_bits);
00372 if (exponent != 0)
00373 exponent -= mant_bits;
00374 mant_off += mant_bits;
00375 mant_bits_left -= mant_bits;
00376 }
00377
00378
00379 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
00380 dto = -dto;
00381 *to = dto;
00382 }
00383
00384 static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders,
00385 unsigned int,
00386 unsigned int,
00387 unsigned int,
00388 unsigned long));
00389
00390
00391
00392 static void
00393 put_field (data, order, total_len, start, len, stuff_to_put)
00394 unsigned char *data;
00395 enum floatformat_byteorders order;
00396 unsigned int total_len;
00397 unsigned int start;
00398 unsigned int len;
00399 unsigned long stuff_to_put;
00400 {
00401 unsigned int cur_byte;
00402 int cur_bitshift;
00403
00404
00405 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
00406 if (order == floatformat_little)
00407 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
00408 cur_bitshift =
00409 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
00410 *(data + cur_byte) &=
00411 ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
00412 *(data + cur_byte) |=
00413 (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
00414 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00415 if (order == floatformat_little)
00416 ++cur_byte;
00417 else
00418 --cur_byte;
00419
00420
00421 while ((unsigned int) cur_bitshift < len)
00422 {
00423 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
00424 {
00425
00426 *(data + cur_byte) &=
00427 ~((1 << (len - cur_bitshift)) - 1);
00428 *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
00429 }
00430 else
00431 *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
00432 & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
00433 cur_bitshift += FLOATFORMAT_CHAR_BIT;
00434 if (order == floatformat_little)
00435 ++cur_byte;
00436 else
00437 --cur_byte;
00438 }
00439 }
00440
00441
00442
00443
00444
00445 void
00446 floatformat_from_double (fmt, from, to)
00447 const struct floatformat *fmt;
00448 const double *from;
00449 char *to;
00450 {
00451 double dfrom;
00452 int exponent;
00453 double mant;
00454 unsigned int mant_bits, mant_off;
00455 int mant_bits_left;
00456 unsigned char *uto = (unsigned char *)to;
00457
00458 dfrom = *from;
00459 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
00460
00461
00462 if (dfrom < 0)
00463 {
00464 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
00465 dfrom = -dfrom;
00466 }
00467
00468 if (dfrom == 0)
00469 {
00470
00471 return;
00472 }
00473
00474 if (dfrom != dfrom)
00475 {
00476
00477 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00478 fmt->exp_len, fmt->exp_nan);
00479
00480 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
00481 32, 1);
00482 return;
00483 }
00484
00485 if (dfrom + dfrom == dfrom)
00486 {
00487
00488
00489 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00490 fmt->exp_len, fmt->exp_nan);
00491 return;
00492 }
00493
00494 mant = frexp (dfrom, &exponent);
00495 if (exponent + fmt->exp_bias - 1 > 0)
00496 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00497 fmt->exp_len, exponent + fmt->exp_bias - 1);
00498 else
00499 {
00500
00501
00502 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
00503 fmt->exp_len, 0);
00504 mant = ldexp (mant, exponent + fmt->exp_bias - 1);
00505 }
00506
00507 mant_bits_left = fmt->man_len;
00508 mant_off = fmt->man_start;
00509 while (mant_bits_left > 0)
00510 {
00511 unsigned long mant_long;
00512 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
00513
00514 mant *= 4294967296.0;
00515 mant_long = (unsigned long)mant;
00516 mant -= mant_long;
00517
00518
00519
00520 if ((unsigned int) mant_bits_left == fmt->man_len
00521 && fmt->intbit == floatformat_intbit_no
00522 && exponent + fmt->exp_bias - 1 > 0)
00523 {
00524 mant_long &= 0x7fffffff;
00525 mant_bits -= 1;
00526 }
00527 else if (mant_bits < 32)
00528 {
00529
00530
00531 mant_long >>= 32 - mant_bits;
00532 }
00533
00534 put_field (uto, fmt->byteorder, fmt->totalsize,
00535 mant_off, mant_bits, mant_long);
00536 mant_off += mant_bits;
00537 mant_bits_left -= mant_bits;
00538 }
00539 }
00540
00541
00542
00543 int
00544 floatformat_is_valid (fmt, from)
00545 const struct floatformat *fmt;
00546 const char *from;
00547 {
00548 return fmt->is_valid (fmt, from);
00549 }
00550
00551
00552 #ifdef IEEE_DEBUG
00553
00554 #include <stdio.h>
00555
00556
00557
00558 void
00559 ieee_test (n)
00560 double n;
00561 {
00562 double result;
00563
00564 floatformat_to_double (&floatformat_ieee_double_little, (char *) &n,
00565 &result);
00566 if ((n != result && (! isnan (n) || ! isnan (result)))
00567 || (n < 0 && result >= 0)
00568 || (n >= 0 && result < 0))
00569 printf ("Differ(to): %.20g -> %.20g\n", n, result);
00570
00571 floatformat_from_double (&floatformat_ieee_double_little, &n,
00572 (char *) &result);
00573 if ((n != result && (! isnan (n) || ! isnan (result)))
00574 || (n < 0 && result >= 0)
00575 || (n >= 0 && result < 0))
00576 printf ("Differ(from): %.20g -> %.20g\n", n, result);
00577
00578 #if 0
00579 {
00580 char exten[16];
00581
00582 floatformat_from_double (&floatformat_m68881_ext, &n, exten);
00583 floatformat_to_double (&floatformat_m68881_ext, exten, &result);
00584 if (n != result)
00585 printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
00586 }
00587 #endif
00588
00589 #if IEEE_DEBUG > 1
00590
00591 {
00592 long double ex = *(long double *)exten;
00593 if (ex != n)
00594 printf ("Differ(from vs. extended): %.20g\n", n);
00595 }
00596 #endif
00597 }
00598
00599 int
00600 main ()
00601 {
00602 ieee_test (0.0);
00603 ieee_test (0.5);
00604 ieee_test (256.0);
00605 ieee_test (0.12345);
00606 ieee_test (234235.78907234);
00607 ieee_test (-512.0);
00608 ieee_test (-0.004321);
00609 ieee_test (1.2E-70);
00610 ieee_test (1.2E-316);
00611 ieee_test (4.9406564584124654E-324);
00612 ieee_test (- 4.9406564584124654E-324);
00613 ieee_test (- 0.0);
00614 ieee_test (- INFINITY);
00615 ieee_test (- NAN);
00616 ieee_test (INFINITY);
00617 ieee_test (NAN);
00618 return 0;
00619 }
00620 #endif