1169689Skan/* IEEE floating point support routines, for GDB, the GNU Debugger. 2169689Skan Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006 3169689Skan Free Software Foundation, Inc. 4169689Skan 5169689SkanThis file is part of GDB. 6169689Skan 7169689SkanThis program is free software; you can redistribute it and/or modify 8169689Skanit under the terms of the GNU General Public License as published by 9169689Skanthe Free Software Foundation; either version 2 of the License, or 10169689Skan(at your option) any later version. 11169689Skan 12169689SkanThis program is distributed in the hope that it will be useful, 13169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 14169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15169689SkanGNU General Public License for more details. 16169689Skan 17169689SkanYou should have received a copy of the GNU General Public License 18169689Skanalong with this program; if not, write to the Free Software 19169689SkanFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 20169689Skan 21169689Skan/* This is needed to pick up the NAN macro on some systems. */ 22169689Skan#define _GNU_SOURCE 23169689Skan 24169689Skan#ifdef HAVE_CONFIG_H 25169689Skan#include "config.h" 26169689Skan#endif 27169689Skan 28169689Skan#include <math.h> 29169689Skan 30169689Skan#ifdef HAVE_STRING_H 31169689Skan#include <string.h> 32169689Skan#endif 33169689Skan 34169689Skan/* On some platforms, <float.h> provides DBL_QNAN. */ 35169689Skan#ifdef STDC_HEADERS 36169689Skan#include <float.h> 37169689Skan#endif 38169689Skan 39169689Skan#include "ansidecl.h" 40169689Skan#include "libiberty.h" 41169689Skan#include "floatformat.h" 42169689Skan 43169689Skan#ifndef INFINITY 44169689Skan#ifdef HUGE_VAL 45169689Skan#define INFINITY HUGE_VAL 46169689Skan#else 47169689Skan#define INFINITY (1.0 / 0.0) 48169689Skan#endif 49169689Skan#endif 50169689Skan 51169689Skan#ifndef NAN 52169689Skan#ifdef DBL_QNAN 53169689Skan#define NAN DBL_QNAN 54169689Skan#else 55169689Skan#define NAN (0.0 / 0.0) 56169689Skan#endif 57169689Skan#endif 58169689Skan 59169689Skanstatic unsigned long get_field (const unsigned char *, 60169689Skan enum floatformat_byteorders, 61169689Skan unsigned int, 62169689Skan unsigned int, 63169689Skan unsigned int); 64169689Skanstatic int floatformat_always_valid (const struct floatformat *fmt, 65169689Skan const void *from); 66169689Skan 67169689Skanstatic int 68169689Skanfloatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, 69169689Skan const void *from ATTRIBUTE_UNUSED) 70169689Skan{ 71169689Skan return 1; 72169689Skan} 73169689Skan 74169689Skan/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 75169689Skan going to bother with trying to muck around with whether it is defined in 76169689Skan a system header, what we do if not, etc. */ 77169689Skan#define FLOATFORMAT_CHAR_BIT 8 78169689Skan 79169689Skan/* floatformats for IEEE single and double, big and little endian. */ 80169689Skanconst struct floatformat floatformat_ieee_single_big = 81169689Skan{ 82169689Skan floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, 83169689Skan floatformat_intbit_no, 84169689Skan "floatformat_ieee_single_big", 85169689Skan floatformat_always_valid 86169689Skan}; 87169689Skanconst struct floatformat floatformat_ieee_single_little = 88169689Skan{ 89169689Skan floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, 90169689Skan floatformat_intbit_no, 91169689Skan "floatformat_ieee_single_little", 92169689Skan floatformat_always_valid 93169689Skan}; 94169689Skanconst struct floatformat floatformat_ieee_double_big = 95169689Skan{ 96169689Skan floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, 97169689Skan floatformat_intbit_no, 98169689Skan "floatformat_ieee_double_big", 99169689Skan floatformat_always_valid 100169689Skan}; 101169689Skanconst struct floatformat floatformat_ieee_double_little = 102169689Skan{ 103169689Skan floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, 104169689Skan floatformat_intbit_no, 105169689Skan "floatformat_ieee_double_little", 106169689Skan floatformat_always_valid 107169689Skan}; 108169689Skan 109169689Skan/* floatformat for IEEE double, little endian byte order, with big endian word 110169689Skan ordering, as on the ARM. */ 111169689Skan 112169689Skanconst struct floatformat floatformat_ieee_double_littlebyte_bigword = 113169689Skan{ 114169689Skan floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, 115169689Skan floatformat_intbit_no, 116169689Skan "floatformat_ieee_double_littlebyte_bigword", 117169689Skan floatformat_always_valid 118169689Skan}; 119169689Skan 120169689Skan/* floatformat for VAX. Not quite IEEE, but close enough. */ 121169689Skan 122169689Skanconst struct floatformat floatformat_vax_f = 123169689Skan{ 124169689Skan floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23, 125169689Skan floatformat_intbit_no, 126169689Skan "floatformat_vax_f", 127169689Skan floatformat_always_valid 128169689Skan}; 129169689Skanconst struct floatformat floatformat_vax_d = 130169689Skan{ 131169689Skan floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55, 132169689Skan floatformat_intbit_no, 133169689Skan "floatformat_vax_d", 134169689Skan floatformat_always_valid 135169689Skan}; 136169689Skanconst struct floatformat floatformat_vax_g = 137169689Skan{ 138169689Skan floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52, 139169689Skan floatformat_intbit_no, 140169689Skan "floatformat_vax_g", 141169689Skan floatformat_always_valid 142169689Skan}; 143169689Skan 144169689Skanstatic int floatformat_i387_ext_is_valid (const struct floatformat *fmt, 145169689Skan const void *from); 146169689Skan 147169689Skanstatic int 148169689Skanfloatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from) 149169689Skan{ 150169689Skan /* In the i387 double-extended format, if the exponent is all ones, 151169689Skan then the integer bit must be set. If the exponent is neither 0 152169689Skan nor ~0, the intbit must also be set. Only if the exponent is 153169689Skan zero can it be zero, and then it must be zero. */ 154169689Skan unsigned long exponent, int_bit; 155169689Skan const unsigned char *ufrom = (const unsigned char *) from; 156169689Skan 157169689Skan exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 158169689Skan fmt->exp_start, fmt->exp_len); 159169689Skan int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, 160169689Skan fmt->man_start, 1); 161169689Skan 162169689Skan if ((exponent == 0) != (int_bit == 0)) 163169689Skan return 0; 164169689Skan else 165169689Skan return 1; 166169689Skan} 167169689Skan 168169689Skanconst struct floatformat floatformat_i387_ext = 169169689Skan{ 170169689Skan floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 171169689Skan floatformat_intbit_yes, 172169689Skan "floatformat_i387_ext", 173169689Skan floatformat_i387_ext_is_valid 174169689Skan}; 175169689Skanconst struct floatformat floatformat_m68881_ext = 176169689Skan{ 177169689Skan /* Note that the bits from 16 to 31 are unused. */ 178169689Skan floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, 179169689Skan floatformat_intbit_yes, 180169689Skan "floatformat_m68881_ext", 181169689Skan floatformat_always_valid 182169689Skan}; 183169689Skanconst struct floatformat floatformat_i960_ext = 184169689Skan{ 185169689Skan /* Note that the bits from 0 to 15 are unused. */ 186169689Skan floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, 187169689Skan floatformat_intbit_yes, 188169689Skan "floatformat_i960_ext", 189169689Skan floatformat_always_valid 190169689Skan}; 191169689Skanconst struct floatformat floatformat_m88110_ext = 192169689Skan{ 193169689Skan floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 194169689Skan floatformat_intbit_yes, 195169689Skan "floatformat_m88110_ext", 196169689Skan floatformat_always_valid 197169689Skan}; 198169689Skanconst struct floatformat floatformat_m88110_harris_ext = 199169689Skan{ 200169689Skan /* Harris uses raw format 128 bytes long, but the number is just an ieee 201169689Skan double, and the last 64 bits are wasted. */ 202169689Skan floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, 203169689Skan floatformat_intbit_no, 204169689Skan "floatformat_m88110_ext_harris", 205169689Skan floatformat_always_valid 206169689Skan}; 207169689Skanconst struct floatformat floatformat_arm_ext_big = 208169689Skan{ 209169689Skan /* Bits 1 to 16 are unused. */ 210169689Skan floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 211169689Skan floatformat_intbit_yes, 212169689Skan "floatformat_arm_ext_big", 213169689Skan floatformat_always_valid 214169689Skan}; 215169689Skanconst struct floatformat floatformat_arm_ext_littlebyte_bigword = 216169689Skan{ 217169689Skan /* Bits 1 to 16 are unused. */ 218169689Skan floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 219169689Skan floatformat_intbit_yes, 220169689Skan "floatformat_arm_ext_littlebyte_bigword", 221169689Skan floatformat_always_valid 222169689Skan}; 223169689Skanconst struct floatformat floatformat_ia64_spill_big = 224169689Skan{ 225169689Skan floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 226169689Skan floatformat_intbit_yes, 227169689Skan "floatformat_ia64_spill_big", 228169689Skan floatformat_always_valid 229169689Skan}; 230169689Skanconst struct floatformat floatformat_ia64_spill_little = 231169689Skan{ 232169689Skan floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, 233169689Skan floatformat_intbit_yes, 234169689Skan "floatformat_ia64_spill_little", 235169689Skan floatformat_always_valid 236169689Skan}; 237169689Skanconst struct floatformat floatformat_ia64_quad_big = 238169689Skan{ 239169689Skan floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 240169689Skan floatformat_intbit_no, 241169689Skan "floatformat_ia64_quad_big", 242169689Skan floatformat_always_valid 243169689Skan}; 244169689Skanconst struct floatformat floatformat_ia64_quad_little = 245169689Skan{ 246169689Skan floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, 247169689Skan floatformat_intbit_no, 248169689Skan "floatformat_ia64_quad_little", 249169689Skan floatformat_always_valid 250169689Skan}; 251169689Skan 252169689Skan 253169689Skan#ifndef min 254169689Skan#define min(a, b) ((a) < (b) ? (a) : (b)) 255169689Skan#endif 256169689Skan 257169689Skan/* Extract a field which starts at START and is LEN bits long. DATA and 258169689Skan TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 259169689Skanstatic unsigned long 260169689Skanget_field (const unsigned char *data, enum floatformat_byteorders order, 261169689Skan unsigned int total_len, unsigned int start, unsigned int len) 262169689Skan{ 263169689Skan unsigned long result = 0; 264169689Skan unsigned int cur_byte; 265169689Skan int lo_bit, hi_bit, cur_bitshift = 0; 266169689Skan int nextbyte = (order == floatformat_little) ? 1 : -1; 267169689Skan 268169689Skan /* Start is in big-endian bit order! Fix that first. */ 269169689Skan start = total_len - (start + len); 270169689Skan 271169689Skan /* Start at the least significant part of the field. */ 272169689Skan if (order == floatformat_little) 273169689Skan cur_byte = start / FLOATFORMAT_CHAR_BIT; 274169689Skan else 275169689Skan cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 276169689Skan 277169689Skan lo_bit = start % FLOATFORMAT_CHAR_BIT; 278169689Skan hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 279169689Skan 280169689Skan do 281169689Skan { 282169689Skan unsigned int shifted = *(data + cur_byte) >> lo_bit; 283169689Skan unsigned int bits = hi_bit - lo_bit; 284169689Skan unsigned int mask = (1 << bits) - 1; 285169689Skan result |= (shifted & mask) << cur_bitshift; 286169689Skan len -= bits; 287169689Skan cur_bitshift += bits; 288169689Skan cur_byte += nextbyte; 289169689Skan lo_bit = 0; 290169689Skan hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 291169689Skan } 292169689Skan while (len != 0); 293169689Skan 294169689Skan return result; 295169689Skan} 296169689Skan 297169689Skan/* Convert from FMT to a double. 298169689Skan FROM is the address of the extended float. 299169689Skan Store the double in *TO. */ 300169689Skan 301169689Skanvoid 302169689Skanfloatformat_to_double (const struct floatformat *fmt, 303169689Skan const void *from, double *to) 304169689Skan{ 305169689Skan const unsigned char *ufrom = (const unsigned char *) from; 306169689Skan double dto; 307169689Skan long exponent; 308169689Skan unsigned long mant; 309169689Skan unsigned int mant_bits, mant_off; 310169689Skan int mant_bits_left; 311169689Skan int special_exponent; /* It's a NaN, denorm or zero */ 312 313 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 314 fmt->exp_start, fmt->exp_len); 315 316 /* If the exponent indicates a NaN, we don't have information to 317 decide what to do. So we handle it like IEEE, except that we 318 don't try to preserve the type of NaN. FIXME. */ 319 if ((unsigned long) exponent == fmt->exp_nan) 320 { 321 int nan; 322 323 mant_off = fmt->man_start; 324 mant_bits_left = fmt->man_len; 325 nan = 0; 326 while (mant_bits_left > 0) 327 { 328 mant_bits = min (mant_bits_left, 32); 329 330 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, 331 mant_off, mant_bits) != 0) 332 { 333 /* This is a NaN. */ 334 nan = 1; 335 break; 336 } 337 338 mant_off += mant_bits; 339 mant_bits_left -= mant_bits; 340 } 341 342 /* On certain systems (such as GNU/Linux), the use of the 343 INFINITY macro below may generate a warning that can not be 344 silenced due to a bug in GCC (PR preprocessor/11931). The 345 preprocessor fails to recognise the __extension__ keyword in 346 conjunction with the GNU/C99 extension for hexadecimal 347 floating point constants and will issue a warning when 348 compiling with -pedantic. */ 349 if (nan) 350 dto = NAN; 351 else 352 dto = INFINITY; 353 354 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 355 dto = -dto; 356 357 *to = dto; 358 359 return; 360 } 361 362 mant_bits_left = fmt->man_len; 363 mant_off = fmt->man_start; 364 dto = 0.0; 365 366 special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan; 367 368 /* Don't bias zero's, denorms or NaNs. */ 369 if (!special_exponent) 370 exponent -= fmt->exp_bias; 371 372 /* Build the result algebraically. Might go infinite, underflow, etc; 373 who cares. */ 374 375 /* If this format uses a hidden bit, explicitly add it in now. Otherwise, 376 increment the exponent by one to account for the integer bit. */ 377 378 if (!special_exponent) 379 { 380 if (fmt->intbit == floatformat_intbit_no) 381 dto = ldexp (1.0, exponent); 382 else 383 exponent++; 384 } 385 386 while (mant_bits_left > 0) 387 { 388 mant_bits = min (mant_bits_left, 32); 389 390 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 391 mant_off, mant_bits); 392 393 /* Handle denormalized numbers. FIXME: What should we do for 394 non-IEEE formats? */ 395 if (special_exponent && exponent == 0 && mant != 0) 396 dto += ldexp ((double)mant, 397 (- fmt->exp_bias 398 - mant_bits 399 - (mant_off - fmt->man_start) 400 + 1)); 401 else 402 dto += ldexp ((double)mant, exponent - mant_bits); 403 if (exponent != 0) 404 exponent -= mant_bits; 405 mant_off += mant_bits; 406 mant_bits_left -= mant_bits; 407 } 408 409 /* Negate it if negative. */ 410 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 411 dto = -dto; 412 *to = dto; 413} 414 415static void put_field (unsigned char *, enum floatformat_byteorders, 416 unsigned int, 417 unsigned int, 418 unsigned int, 419 unsigned long); 420 421/* Set a field which starts at START and is LEN bits long. DATA and 422 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 423static void 424put_field (unsigned char *data, enum floatformat_byteorders order, 425 unsigned int total_len, unsigned int start, unsigned int len, 426 unsigned long stuff_to_put) 427{ 428 unsigned int cur_byte; 429 int lo_bit, hi_bit; 430 int nextbyte = (order == floatformat_little) ? 1 : -1; 431 432 /* Start is in big-endian bit order! Fix that first. */ 433 start = total_len - (start + len); 434 435 /* Start at the least significant part of the field. */ 436 if (order == floatformat_little) 437 cur_byte = start / FLOATFORMAT_CHAR_BIT; 438 else 439 cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; 440 441 lo_bit = start % FLOATFORMAT_CHAR_BIT; 442 hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); 443 444 do 445 { 446 unsigned char *byte_ptr = data + cur_byte; 447 unsigned int bits = hi_bit - lo_bit; 448 unsigned int mask = ((1 << bits) - 1) << lo_bit; 449 *byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); 450 stuff_to_put >>= bits; 451 len -= bits; 452 cur_byte += nextbyte; 453 lo_bit = 0; 454 hi_bit = min (len, FLOATFORMAT_CHAR_BIT); 455 } 456 while (len != 0); 457} 458 459/* The converse: convert the double *FROM to an extended float 460 and store where TO points. Neither FROM nor TO have any alignment 461 restrictions. */ 462 463void 464floatformat_from_double (const struct floatformat *fmt, 465 const double *from, void *to) 466{ 467 double dfrom; 468 int exponent; 469 double mant; 470 unsigned int mant_bits, mant_off; 471 int mant_bits_left; 472 unsigned char *uto = (unsigned char *) to; 473 474 dfrom = *from; 475 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); 476 477 /* If negative, set the sign bit. */ 478 if (dfrom < 0) 479 { 480 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 481 dfrom = -dfrom; 482 } 483 484 if (dfrom == 0) 485 { 486 /* 0.0. */ 487 return; 488 } 489 490 if (dfrom != dfrom) 491 { 492 /* NaN. */ 493 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 494 fmt->exp_len, fmt->exp_nan); 495 /* Be sure it's not infinity, but NaN value is irrelevant. */ 496 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 497 32, 1); 498 return; 499 } 500 501 if (dfrom + dfrom == dfrom) 502 { 503 /* This can only happen for an infinite value (or zero, which we 504 already handled above). */ 505 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 506 fmt->exp_len, fmt->exp_nan); 507 return; 508 } 509 510 mant = frexp (dfrom, &exponent); 511 if (exponent + fmt->exp_bias - 1 > 0) 512 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 513 fmt->exp_len, exponent + fmt->exp_bias - 1); 514 else 515 { 516 /* Handle a denormalized number. FIXME: What should we do for 517 non-IEEE formats? */ 518 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 519 fmt->exp_len, 0); 520 mant = ldexp (mant, exponent + fmt->exp_bias - 1); 521 } 522 523 mant_bits_left = fmt->man_len; 524 mant_off = fmt->man_start; 525 while (mant_bits_left > 0) 526 { 527 unsigned long mant_long; 528 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 529 530 mant *= 4294967296.0; 531 mant_long = (unsigned long)mant; 532 mant -= mant_long; 533 534 /* If the integer bit is implicit, and we are not creating a 535 denormalized number, then we need to discard it. */ 536 if ((unsigned int) mant_bits_left == fmt->man_len 537 && fmt->intbit == floatformat_intbit_no 538 && exponent + fmt->exp_bias - 1 > 0) 539 { 540 mant_long &= 0x7fffffff; 541 mant_bits -= 1; 542 } 543 else if (mant_bits < 32) 544 { 545 /* The bits we want are in the most significant MANT_BITS bits of 546 mant_long. Move them to the least significant. */ 547 mant_long >>= 32 - mant_bits; 548 } 549 550 put_field (uto, fmt->byteorder, fmt->totalsize, 551 mant_off, mant_bits, mant_long); 552 mant_off += mant_bits; 553 mant_bits_left -= mant_bits; 554 } 555} 556 557/* Return non-zero iff the data at FROM is a valid number in format FMT. */ 558 559int 560floatformat_is_valid (const struct floatformat *fmt, const void *from) 561{ 562 return fmt->is_valid (fmt, from); 563} 564 565 566#ifdef IEEE_DEBUG 567 568#include <stdio.h> 569 570/* This is to be run on a host which uses IEEE floating point. */ 571 572void 573ieee_test (double n) 574{ 575 double result; 576 577 floatformat_to_double (&floatformat_ieee_double_little, &n, &result); 578 if ((n != result && (! isnan (n) || ! isnan (result))) 579 || (n < 0 && result >= 0) 580 || (n >= 0 && result < 0)) 581 printf ("Differ(to): %.20g -> %.20g\n", n, result); 582 583 floatformat_from_double (&floatformat_ieee_double_little, &n, &result); 584 if ((n != result && (! isnan (n) || ! isnan (result))) 585 || (n < 0 && result >= 0) 586 || (n >= 0 && result < 0)) 587 printf ("Differ(from): %.20g -> %.20g\n", n, result); 588 589#if 0 590 { 591 char exten[16]; 592 593 floatformat_from_double (&floatformat_m68881_ext, &n, exten); 594 floatformat_to_double (&floatformat_m68881_ext, exten, &result); 595 if (n != result) 596 printf ("Differ(to+from): %.20g -> %.20g\n", n, result); 597 } 598#endif 599 600#if IEEE_DEBUG > 1 601 /* This is to be run on a host which uses 68881 format. */ 602 { 603 long double ex = *(long double *)exten; 604 if (ex != n) 605 printf ("Differ(from vs. extended): %.20g\n", n); 606 } 607#endif 608} 609 610int 611main (void) 612{ 613 ieee_test (0.0); 614 ieee_test (0.5); 615 ieee_test (256.0); 616 ieee_test (0.12345); 617 ieee_test (234235.78907234); 618 ieee_test (-512.0); 619 ieee_test (-0.004321); 620 ieee_test (1.2E-70); 621 ieee_test (1.2E-316); 622 ieee_test (4.9406564584124654E-324); 623 ieee_test (- 4.9406564584124654E-324); 624 ieee_test (- 0.0); 625 ieee_test (- INFINITY); 626 ieee_test (- NAN); 627 ieee_test (INFINITY); 628 ieee_test (NAN); 629 return 0; 630} 631#endif 632