floatformat.c revision 33965
1/* IEEE floating point support routines, for GDB, the GNU Debugger. 2 Copyright (C) 1991, 1994 Free Software Foundation, Inc. 3 4This file is part of GDB. 5 6This program is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2 of the License, or 9(at your option) any later version. 10 11This program is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with this program; if not, write to the Free Software 18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20#include "floatformat.h" 21#include <math.h> /* ldexp */ 22#ifdef __STDC__ 23#include <stddef.h> 24extern void *memcpy (void *s1, const void *s2, size_t n); 25extern void *memset (void *s, int c, size_t n); 26#else 27extern char *memcpy (); 28extern char *memset (); 29#endif 30 31/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not 32 going to bother with trying to muck around with whether it is defined in 33 a system header, what we do if not, etc. */ 34#define FLOATFORMAT_CHAR_BIT 8 35 36/* floatformats for IEEE single and double, big and little endian. */ 37const struct floatformat floatformat_ieee_single_big = 38{ 39 floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no 40}; 41const struct floatformat floatformat_ieee_single_little = 42{ 43 floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, floatformat_intbit_no 44}; 45const struct floatformat floatformat_ieee_double_big = 46{ 47 floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no 48}; 49const struct floatformat floatformat_ieee_double_little = 50{ 51 floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, floatformat_intbit_no 52}; 53 54const struct floatformat floatformat_i387_ext = 55{ 56 floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 57 floatformat_intbit_yes 58}; 59const struct floatformat floatformat_m68881_ext = 60{ 61 /* Note that the bits from 16 to 31 are unused. */ 62 floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, floatformat_intbit_yes 63}; 64const struct floatformat floatformat_i960_ext = 65{ 66 /* Note that the bits from 0 to 15 are unused. */ 67 floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, 68 floatformat_intbit_yes 69}; 70const struct floatformat floatformat_m88110_ext = 71{ 72#ifdef HARRIS_FLOAT_FORMAT 73 /* Harris uses raw format 128 bytes long, but the number is just an ieee 74 double, and the last 64 bits are wasted. */ 75 floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, 76 floatformat_intbit_no 77#else 78 floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, 79 floatformat_intbit_yes 80#endif /* HARRIS_FLOAT_FORMAT */ 81}; 82const struct floatformat floatformat_arm_ext = 83{ 84 /* Bits 1 to 16 are unused. */ 85 floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, 86 floatformat_intbit_yes 87}; 88 89static unsigned long get_field PARAMS ((unsigned char *, 90 enum floatformat_byteorders, 91 unsigned int, 92 unsigned int, 93 unsigned int)); 94 95/* Extract a field which starts at START and is LEN bytes long. DATA and 96 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 97static unsigned long 98get_field (data, order, total_len, start, len) 99 unsigned char *data; 100 enum floatformat_byteorders order; 101 unsigned int total_len; 102 unsigned int start; 103 unsigned int len; 104{ 105 unsigned long result; 106 unsigned int cur_byte; 107 int cur_bitshift; 108 109 /* Start at the least significant part of the field. */ 110 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 111 if (order == floatformat_little) 112 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; 113 cur_bitshift = 114 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 115 result = *(data + cur_byte) >> (-cur_bitshift); 116 cur_bitshift += FLOATFORMAT_CHAR_BIT; 117 if (order == floatformat_little) 118 ++cur_byte; 119 else 120 --cur_byte; 121 122 /* Move towards the most significant part of the field. */ 123 while (cur_bitshift < len) 124 { 125 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) 126 /* This is the last byte; zero out the bits which are not part of 127 this field. */ 128 result |= 129 (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1)) 130 << cur_bitshift; 131 else 132 result |= *(data + cur_byte) << cur_bitshift; 133 cur_bitshift += FLOATFORMAT_CHAR_BIT; 134 if (order == floatformat_little) 135 ++cur_byte; 136 else 137 --cur_byte; 138 } 139 return result; 140} 141 142#ifndef min 143#define min(a, b) ((a) < (b) ? (a) : (b)) 144#endif 145 146/* Convert from FMT to a double. 147 FROM is the address of the extended float. 148 Store the double in *TO. */ 149 150void 151floatformat_to_double (fmt, from, to) 152 const struct floatformat *fmt; 153 char *from; 154 double *to; 155{ 156 unsigned char *ufrom = (unsigned char *)from; 157 double dto; 158 long exponent; 159 unsigned long mant; 160 unsigned int mant_bits, mant_off; 161 int mant_bits_left; 162 int special_exponent; /* It's a NaN, denorm or zero */ 163 164 exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, 165 fmt->exp_start, fmt->exp_len); 166 /* Note that if exponent indicates a NaN, we can't really do anything useful 167 (not knowing if the host has NaN's, or how to build one). So it will 168 end up as an infinity or something close; that is OK. */ 169 170 mant_bits_left = fmt->man_len; 171 mant_off = fmt->man_start; 172 dto = 0.0; 173 174 special_exponent = exponent == 0 || exponent == fmt->exp_nan; 175 176 /* Don't bias zero's, denorms or NaNs. */ 177 if (!special_exponent) 178 exponent -= fmt->exp_bias; 179 180 /* Build the result algebraically. Might go infinite, underflow, etc; 181 who cares. */ 182 183 /* If this format uses a hidden bit, explicitly add it in now. Otherwise, 184 increment the exponent by one to account for the integer bit. */ 185 186 if (!special_exponent) 187 if (fmt->intbit == floatformat_intbit_no) 188 dto = ldexp (1.0, exponent); 189 else 190 exponent++; 191 192 while (mant_bits_left > 0) 193 { 194 mant_bits = min (mant_bits_left, 32); 195 196 mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, 197 mant_off, mant_bits); 198 199 dto += ldexp ((double)mant, exponent - mant_bits); 200 exponent -= mant_bits; 201 mant_off += mant_bits; 202 mant_bits_left -= mant_bits; 203 } 204 205 /* Negate it if negative. */ 206 if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) 207 dto = -dto; 208 *to = dto; 209} 210 211static void put_field PARAMS ((unsigned char *, enum floatformat_byteorders, 212 unsigned int, 213 unsigned int, 214 unsigned int, 215 unsigned long)); 216 217/* Set a field which starts at START and is LEN bytes long. DATA and 218 TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ 219static void 220put_field (data, order, total_len, start, len, stuff_to_put) 221 unsigned char *data; 222 enum floatformat_byteorders order; 223 unsigned int total_len; 224 unsigned int start; 225 unsigned int len; 226 unsigned long stuff_to_put; 227{ 228 unsigned int cur_byte; 229 int cur_bitshift; 230 231 /* Start at the least significant part of the field. */ 232 cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT; 233 if (order == floatformat_little) 234 cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1; 235 cur_bitshift = 236 ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT; 237 *(data + cur_byte) &= 238 ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift)); 239 *(data + cur_byte) |= 240 (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift); 241 cur_bitshift += FLOATFORMAT_CHAR_BIT; 242 if (order == floatformat_little) 243 ++cur_byte; 244 else 245 --cur_byte; 246 247 /* Move towards the most significant part of the field. */ 248 while (cur_bitshift < len) 249 { 250 if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT) 251 { 252 /* This is the last byte. */ 253 *(data + cur_byte) &= 254 ~((1 << (len - cur_bitshift)) - 1); 255 *(data + cur_byte) |= (stuff_to_put >> cur_bitshift); 256 } 257 else 258 *(data + cur_byte) = ((stuff_to_put >> cur_bitshift) 259 & ((1 << FLOATFORMAT_CHAR_BIT) - 1)); 260 cur_bitshift += FLOATFORMAT_CHAR_BIT; 261 if (order == floatformat_little) 262 ++cur_byte; 263 else 264 --cur_byte; 265 } 266} 267 268/* The converse: convert the double *FROM to an extended float 269 and store where TO points. Neither FROM nor TO have any alignment 270 restrictions. */ 271 272void 273floatformat_from_double (fmt, from, to) 274 CONST struct floatformat *fmt; 275 double *from; 276 char *to; 277{ 278 double dfrom; 279 int exponent; 280 double mant; 281 unsigned int mant_bits, mant_off; 282 int mant_bits_left; 283 unsigned char *uto = (unsigned char *)to; 284 285 memcpy (&dfrom, from, sizeof (dfrom)); 286 memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); 287 if (dfrom == 0) 288 return; /* Result is zero */ 289 if (dfrom != dfrom) 290 { 291 /* From is NaN */ 292 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, 293 fmt->exp_len, fmt->exp_nan); 294 /* Be sure it's not infinity, but NaN value is irrel */ 295 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, 296 32, 1); 297 return; 298 } 299 300 /* If negative, set the sign bit. */ 301 if (dfrom < 0) 302 { 303 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); 304 dfrom = -dfrom; 305 } 306 307 /* How to tell an infinity from an ordinary number? FIXME-someday */ 308 309 mant = frexp (dfrom, &exponent); 310 put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len, 311 exponent + fmt->exp_bias - 1); 312 313 mant_bits_left = fmt->man_len; 314 mant_off = fmt->man_start; 315 while (mant_bits_left > 0) 316 { 317 unsigned long mant_long; 318 mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; 319 320 mant *= 4294967296.0; 321 mant_long = (unsigned long)mant; 322 mant -= mant_long; 323 324 /* If the integer bit is implicit, then we need to discard it. 325 If we are discarding a zero, we should be (but are not) creating 326 a denormalized number which means adjusting the exponent 327 (I think). */ 328 if (mant_bits_left == fmt->man_len 329 && fmt->intbit == floatformat_intbit_no) 330 { 331 mant_long &= 0x7fffffff; 332 mant_bits -= 1; 333 } 334 else if (mant_bits < 32) 335 { 336 /* The bits we want are in the most significant MANT_BITS bits of 337 mant_long. Move them to the least significant. */ 338 mant_long >>= 32 - mant_bits; 339 } 340 341 put_field (uto, fmt->byteorder, fmt->totalsize, 342 mant_off, mant_bits, mant_long); 343 mant_off += mant_bits; 344 mant_bits_left -= mant_bits; 345 } 346} 347 348 349#ifdef IEEE_DEBUG 350 351/* This is to be run on a host which uses IEEE floating point. */ 352 353void 354ieee_test (n) 355 double n; 356{ 357 double result; 358 char exten[16]; 359 360 floatformat_to_double (&floatformat_ieee_double_big, &n, &result); 361 if (n != result) 362 printf ("Differ(to): %.20g -> %.20g\n", n, result); 363 floatformat_from_double (&floatformat_ieee_double_big, &n, &result); 364 if (n != result) 365 printf ("Differ(from): %.20g -> %.20g\n", n, result); 366 367 floatformat_from_double (&floatformat_m68881_ext, &n, exten); 368 floatformat_to_double (&floatformat_m68881_ext, exten, &result); 369 if (n != result) 370 printf ("Differ(to+from): %.20g -> %.20g\n", n, result); 371 372#if IEEE_DEBUG > 1 373 /* This is to be run on a host which uses 68881 format. */ 374 { 375 long double ex = *(long double *)exten; 376 if (ex != n) 377 printf ("Differ(from vs. extended): %.20g\n", n); 378 } 379#endif 380} 381 382int 383main () 384{ 385 ieee_test (0.5); 386 ieee_test (256.0); 387 ieee_test (0.12345); 388 ieee_test (234235.78907234); 389 ieee_test (-512.0); 390 ieee_test (-0.004321); 391 return 0; 392} 393#endif 394