atof-generic.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 635 行 · 第 1/2 页
C
635 行
unsigned int more_than_enough_bits_for_digits; unsigned int more_than_enough_littlenums_for_digits; unsigned int size_of_digits_in_littlenums; unsigned int size_of_digits_in_chars; FLONUM_TYPE power_of_10_flonum; FLONUM_TYPE digits_flonum; precision = (address_of_generic_floating_point_number->high - address_of_generic_floating_point_number->low + 1); /* Number of destination littlenums. */ /* Includes guard bits (two littlenums worth) */#if 0 /* The integer version below is very close, and it doesn't require floating point support (which is currently buggy on the Alpha). */ maximum_useful_digits = (((double) (precision - 2)) * ((double) (LITTLENUM_NUMBER_OF_BITS)) / (LOG_TO_BASE_2_OF_10)) + 2; /* 2 :: guard digits. */#else maximum_useful_digits = (((precision - 2)) * ( (LITTLENUM_NUMBER_OF_BITS)) * 1000000 / 3321928) + 2; /* 2 :: guard digits. */#endif if (number_of_digits_available > maximum_useful_digits) { number_of_digits_to_use = maximum_useful_digits; } else { number_of_digits_to_use = number_of_digits_available; } /* Cast these to SIGNED LONG first, otherwise, on systems with LONG wider than INT (such as Alpha OSF/1), unsignedness may cause unexpected results. */ decimal_exponent += ((long) number_of_digits_before_decimal - (long) number_of_digits_to_use);#if 0 more_than_enough_bits_for_digits = ((((double) number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1);#else more_than_enough_bits_for_digits = (number_of_digits_to_use * 3321928 / 1000000 + 1);#endif more_than_enough_littlenums_for_digits = (more_than_enough_bits_for_digits / LITTLENUM_NUMBER_OF_BITS) + 2; /* Compute (digits) part. In "12.34E56" this is the "1234" part. Arithmetic is exact here. If no digits are supplied then this part is a 0 valued binary integer. Allocate room to build up the binary number as littlenums. We want this memory to disappear when we leave this function. Assume no alignment problems => (room for n objects) == n * (room for 1 object). */ size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits; size_of_digits_in_chars = size_of_digits_in_littlenums * sizeof (LITTLENUM_TYPE); digits_binary_low = (LITTLENUM_TYPE *) alloca (size_of_digits_in_chars); memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars); /* Digits_binary_low[] is allocated and zeroed. */ /* * Parse the decimal digits as if * digits_low was in the units position. * Emit a binary number into digits_binary_low[]. * * Use a large-precision version of: * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit */ for (p = first_digit, count = number_of_digits_to_use; count; p++, --count) { c = *p; if (isdigit ((unsigned char) c)) { /* * Multiply by 10. Assume can never overflow. * Add this digit to digits_binary_low[]. */ long carry; LITTLENUM_TYPE *littlenum_pointer; LITTLENUM_TYPE *littlenum_limit; littlenum_limit = digits_binary_low + more_than_enough_littlenums_for_digits - 1; carry = c - '0'; /* char -> binary */ for (littlenum_pointer = digits_binary_low; littlenum_pointer <= littlenum_limit; littlenum_pointer++) { long work; work = carry + 10 * (long) (*littlenum_pointer); *littlenum_pointer = work & LITTLENUM_MASK; carry = work >> LITTLENUM_NUMBER_OF_BITS; } if (carry != 0) { /* * We have a GROSS internal error. * This should never happen. */ as_fatal (_("failed sanity check.")); } } else { ++count; /* '.' doesn't alter digits used count. */ } } /* * Digits_binary_low[] properly encodes the value of the digits. * Forget about any high-order littlenums that are 0. */ while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0 && size_of_digits_in_littlenums >= 2) size_of_digits_in_littlenums--; digits_flonum.low = digits_binary_low; digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1; digits_flonum.leader = digits_flonum.high; digits_flonum.exponent = 0; /* * The value of digits_flonum . sign should not be important. * We have already decided the output's sign. * We trust that the sign won't influence the other parts of the number! * So we give it a value for these reasons: * (1) courtesy to humans reading/debugging * these numbers so they don't get excited about strange values * (2) in future there may be more meaning attached to sign, * and what was * harmless noise may become disruptive, ill-conditioned (or worse) * input. */ digits_flonum.sign = '+'; { /* * Compute the mantssa (& exponent) of the power of 10. * If sucessful, then multiply the power of 10 by the digits * giving return_binary_mantissa and return_binary_exponent. */ LITTLENUM_TYPE *power_binary_low; int decimal_exponent_is_negative; /* This refers to the "-56" in "12.34E-56". */ /* FALSE: decimal_exponent is positive (or 0) */ /* TRUE: decimal_exponent is negative */ FLONUM_TYPE temporary_flonum; LITTLENUM_TYPE *temporary_binary_low; unsigned int size_of_power_in_littlenums; unsigned int size_of_power_in_chars; size_of_power_in_littlenums = precision; /* Precision has a built-in fudge factor so we get a few guard bits. */ decimal_exponent_is_negative = decimal_exponent < 0; if (decimal_exponent_is_negative) { decimal_exponent = -decimal_exponent; } /* From now on: the decimal exponent is > 0. Its sign is separate. */ size_of_power_in_chars = size_of_power_in_littlenums * sizeof (LITTLENUM_TYPE) + 2; power_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); temporary_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); memset ((char *) power_binary_low, '\0', size_of_power_in_chars); *power_binary_low = 1; power_of_10_flonum.exponent = 0; power_of_10_flonum.low = power_binary_low; power_of_10_flonum.leader = power_binary_low; power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1; power_of_10_flonum.sign = '+'; temporary_flonum.low = temporary_binary_low; temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1; /* * (power) == 1. * Space for temporary_flonum allocated. */ /* * ... * * WHILE more bits * DO find next bit (with place value) * multiply into power mantissa * OD */ { int place_number_limit; /* Any 10^(2^n) whose "n" exceeds this */ /* value will fall off the end of */ /* flonum_XXXX_powers_of_ten[]. */ int place_number; const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */ place_number_limit = table_size_of_flonum_powers_of_ten; multiplicand = (decimal_exponent_is_negative ? flonum_negative_powers_of_ten : flonum_positive_powers_of_ten); for (place_number = 1;/* Place value of this bit of exponent. */ decimal_exponent;/* Quit when no more 1 bits in exponent. */ decimal_exponent >>= 1, place_number++) { if (decimal_exponent & 1) { if (place_number > place_number_limit) { /* The decimal exponent has a magnitude so great that our tables can't help us fragment it. Although this routine is in error because it can't imagine a number that big, signal an error as if it is the user's fault for presenting such a big number. */ return_value = ERROR_EXPONENT_OVERFLOW; /* quit out of loop gracefully */ decimal_exponent = 0; } else {#ifdef TRACE printf ("before multiply, place_number = %d., power_of_10_flonum:\n", place_number); flonum_print (&power_of_10_flonum); (void) putchar ('\n');#endif#ifdef TRACE printf ("multiplier:\n"); flonum_print (multiplicand + place_number); (void) putchar ('\n');#endif flonum_multip (multiplicand + place_number, &power_of_10_flonum, &temporary_flonum);#ifdef TRACE printf ("after multiply:\n"); flonum_print (&temporary_flonum); (void) putchar ('\n');#endif flonum_copy (&temporary_flonum, &power_of_10_flonum);#ifdef TRACE printf ("after copy:\n"); flonum_print (&power_of_10_flonum); (void) putchar ('\n');#endif } /* If this bit of decimal_exponent was computable.*/ } /* If this bit of decimal_exponent was set. */ } /* For each bit of binary representation of exponent */#ifdef TRACE printf ("after computing power_of_10_flonum:\n"); flonum_print (&power_of_10_flonum); (void) putchar ('\n');#endif } } /* * power_of_10_flonum is power of ten in binary (mantissa) , (exponent). * It may be the number 1, in which case we don't NEED to multiply. * * Multiply (decimal digits) by power_of_10_flonum. */ flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number); /* Assert sign of the number we made is '+'. */ address_of_generic_floating_point_number->sign = digits_sign_char; } return return_value;}#ifdef TRACEstatic voidflonum_print (f) const FLONUM_TYPE *f;{ LITTLENUM_TYPE *lp; char littlenum_format[10]; sprintf (littlenum_format, " %%0%dx", sizeof (LITTLENUM_TYPE) * 2);#define print_littlenum(LP) (printf (littlenum_format, LP)) printf ("flonum @%p %c e%ld", f, f->sign, f->exponent); if (f->low < f->high) for (lp = f->high; lp >= f->low; lp--) print_littlenum (*lp); else for (lp = f->low; lp <= f->high; lp++) print_littlenum (*lp); printf ("\n"); fflush (stdout);}#endif/* end of atof_generic.c */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?