write_real.h 666 0 0 2540 6170362332 6322 /* This file contains the class definition for the real_to_ascii class, which converts double precision (64-bit) IEEE reals to the equivalent ASCII string. */ /*==================================================================== This software was written by Ian L. Kaplan, Chief Fat Bear, Bear Products International. Use of this software, for any purpose, is granted on two conditions: 1. This copyright notice must be included with the software or any software derived from it. 2. The risk of using this software is accepted by the user. No warranty as to its usefulness or functionality is provided or implied. The author and Bear Products International provides no support. July 1996 ====================================================================*/ class real_to_ascii { private: typedef enum { FALSE = 0, TRUE = 1 } bool_vals; int odd( unsigned int exponent ) { return (exponent & 0x1); } double power_of_ten( unsigned int exponent ); unsigned int ExpExtract( double num ); int do_mantissa( double mantissa, char *str, unsigned int strindex, unsigned int num_digits ); int do_exp_part( int exponent, char *str, unsigned int strindex ); public: void rtoa(double real, char *str, unsigned int num_digits); }; write_real.cpp 666 0 0 14523 6170365324 6705 /* This file contains the class functions for the real_to_ascii class, which converts double precision (64-bit) IEEE reals to the equivalent ASCII string for a number in scientific notation (e.g., 6.020E+023). This code is based on some floating point to ASCII code originally written by Joel McCormack, in Modula-2, long, long ago. */ /*==================================================================== This software was written by Ian L. Kaplan, Chief Fat Bear, Bear Products International. Use of this software, for any purpose, is granted on two conditions: 1. This copyright notice must be included with the software or any software derived from it. 2. The risk of using this software is accepted by the user. No warranty as to its usefulness or functionality is provided or implied. The author and Bear Products International provides no support. July 1996 ====================================================================*/ #include "write_real.h" /* Power_of_ten is passed an unsigned short integer exponent and returns * the cooresponding power of ten. This routine calculates power in * log( exponent ) time, where the log is log to the base 2. */ double real_to_ascii::power_of_ten( unsigned int exponent ) { const int BASE = 10; double base, PowerCount; base = BASE; PowerCount = 1.0; while (exponent) { if ( odd( exponent ) ) PowerCount = PowerCount * base; exponent = exponent / 2; if (exponent) base = base * base; } /* while */ return PowerCount; } /* power_of_ten */ /* * ExpExtract returns the exponent of a 64 bit IEEE format floating point * number. The exponent is returned in as an unbiased power of two. The * sign bit is the most significant bit in an IEEE real. The next eleven * bits (bits 62 to 52) are the exponent bits. This places the exponent * in the most significant word. */ unsigned int real_to_ascii::ExpExtract( double num ) { const unsigned int MASK = 0x7ff0; const unsigned int bias = 1022; union { double real; unsigned short word[ 4 ]; } exp_conv; short exponent; exp_conv.real = num; exponent = exp_conv.word[ 3 ] & MASK; /* Mask out the sign and low 4 bits */ exponent = exponent >> 4; /* Shift exponent down four bits */ exponent = exponent - bias; return exponent; } /* ExpExtract */ /* index in string where decimal point should appear */ int real_to_ascii::do_mantissa( double mantissa, char *str, unsigned int strindex, unsigned int num_digits ) { const int DECPOINT = 2; int i; unsigned short digit; for (i = 1; i <= num_digits; ++i) { digit = (unsigned short)mantissa; mantissa = (mantissa - (double)digit) * 10.0; if (i == DECPOINT) { str[ strindex ] = '.'; ++strindex; } str[ strindex ] = (char)(digit + (int)'0'); ++strindex; } /* for */ return strindex; } /* do_mantissa */ int real_to_ascii::do_exp_part( int exponent, char *str, unsigned int strindex ) { unsigned short localexp; str[ strindex ] = 'E'; ++strindex; if (exponent < 0) { str[ strindex ] = '-'; localexp = -exponent; } else { str[ strindex ] = '+'; localexp = exponent; } ++strindex; str[ strindex ] = (char)( localexp / 100 + (int)'0'); str[ strindex + 1 ] = (char)( localexp / 10 % 10 + (int)'0'); str[ strindex + 2 ] = (char)( localexp % 10 + (int)'0'); strindex += 3; /* increment to next free element */ return strindex; } /* do_exp_part */ /* Real to ASCII -- Convert a floating point number from its binary form to ASCII. There are three parameters: real, str and num_digits. Real is the floating point number, str is a pointer to the string that is to hold the ASCII equivelent of real and num_digits is the number of digits that are to follow the decimal point. Since we are using C, the user of this routine is responsible for making sure that the string pointed to by str is large enough to hold the ASCII equivilant of the floating point number. */ void real_to_ascii::rtoa(double real, char *str, unsigned int num_digits) { /* maximum number of digits following the decimal point */ const int MAXDIGITS = 15; const double LogOfTwo = 0.3010299956640; /* log to the base ten of 2 */ int negative; /* boolean flag set to true if number is negative */ unsigned short strindex; short exponent; double mantissa; negative = FALSE; if (real < 0.0) { negative = TRUE; real = -real; } if (real == 0.0) exponent = 0.0; else /* extract the exponent from the floating point number */ exponent = ExpExtract( real ); /* convert the number from a power of two to a power of ten */ exponent = (int)( exponent * LogOfTwo ); if (exponent < 0) --exponent; if (real != 0.0) { if (exponent > 0) mantissa = real / power_of_ten( (unsigned short)exponent ); else mantissa = real * power_of_ten( (unsigned short)-exponent ); if (mantissa < 1.0) { mantissa = mantissa * 10; --exponent; } /* if (mantissa < 1.0) */ /* if the user asks for more than the maximum number of significant digits for 64 bit floating point, correct num_digits to MAXDIGITS. */ if (num_digits > MAXDIGITS) num_digits = MAXDIGITS; /* round the number to the number of significant digits desired */ mantissa = mantissa + 5.0 / power_of_ten( num_digits ); } else mantissa = 0.0; /* Before rounding the number it could have been 9.999...E+000. By adding 5.0E-num_digits it could be >= 10.00, so the number is no longer normalized. */ if (mantissa >= 10.0) { /* renormalize */ ++exponent; mantissa = mantissa / 10.0; } strindex = 0; /* put the sign in the string */ if (negative) str[ strindex ] = '-'; else str[ strindex ] = ' '; strindex = 1; /* convert mantissa to string form */ strindex = do_mantissa( mantissa, str, strindex, num_digits ); strindex = do_exp_part( exponent, str, strindex ); str[ strindex ] = '\0'; } /* rtoa (real to ascii) */