Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Typedefs | Functions | Variables
flonum.h File Reference
#include "bignum.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  FLONUM_STRUCT

Defines

#define ERROR_EXPONENT_OVERFLOW   (2)

Typedefs

typedef struct FLONUM_STRUCT

Functions

int atof_generic (char **address_of_string_pointer, const char *string_of_decimal_marks, const char *string_of_decimal_exponent_marks, FLONUM_TYPE *address_of_generic_floating_point_number)
void flonum_copy (FLONUM_TYPE *in, FLONUM_TYPE *out)
void flonum_multip (const FLONUM_TYPE *a, const FLONUM_TYPE *b, FLONUM_TYPE *product)

Variables

const FLONUM_TYPE flonum_positive_powers_of_ten []
const FLONUM_TYPE flonum_negative_powers_of_ten []
const int table_size_of_flonum_powers_of_ten

Class Documentation

struct FLONUM_STRUCT

Definition at line 52 of file flonum.h.

Class Members
long exponent
LITTLENUM_TYPE * high
LITTLENUM_TYPE * leader
LITTLENUM_TYPE * low
char sign

Define Documentation

#define ERROR_EXPONENT_OVERFLOW   (2)

Definition at line 102 of file flonum.h.


Typedef Documentation

Definition at line 61 of file flonum.h.


Function Documentation

int atof_generic ( char **  address_of_string_pointer,
const char *  string_of_decimal_marks,
const char *  string_of_decimal_exponent_marks,
FLONUM_TYPE *  address_of_generic_floating_point_number 
)

Definition at line 76 of file atof-generic.c.

{
  int return_value;         /* 0 means OK.  */
  char *first_digit;
  unsigned int number_of_digits_before_decimal;
  unsigned int number_of_digits_after_decimal;
  long decimal_exponent;
  unsigned int number_of_digits_available;
  char digits_sign_char;

  /*
   * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent.
   * It would be simpler to modify the string, but we don't; just to be nice
   * to caller.
   * We need to know how many digits we have, so we can allocate space for
   * the digits' value.
   */

  char *p;
  char c;
  int seen_significant_digit;

#ifdef ASSUME_DECIMAL_MARK_IS_DOT
  assert (string_of_decimal_marks[0] == '.'
         && string_of_decimal_marks[1] == 0);
#define IS_DECIMAL_MARK(c)  ((c) == '.')
#else
#define IS_DECIMAL_MARK(c)  (0 != strchr (string_of_decimal_marks, (c)))
#endif

  first_digit = *address_of_string_pointer;
  c = *first_digit;

  if (c == '-' || c == '+')
    {
      digits_sign_char = c;
      first_digit++;
    }
  else
    digits_sign_char = '+';

  switch (first_digit[0])
    {
    case 'n':
    case 'N':
      if (!strncasecmp ("nan", first_digit, 3))
       {
         address_of_generic_floating_point_number->sign = 0;
         address_of_generic_floating_point_number->exponent = 0;
         address_of_generic_floating_point_number->leader =
           address_of_generic_floating_point_number->low;
         *address_of_string_pointer = first_digit + 3;
         return 0;
       }
      break;

    case 'i':
    case 'I':
      if (!strncasecmp ("inf", first_digit, 3))
       {
         address_of_generic_floating_point_number->sign =
           digits_sign_char == '+' ? 'P' : 'N';
         address_of_generic_floating_point_number->exponent = 0;
         address_of_generic_floating_point_number->leader =
           address_of_generic_floating_point_number->low;

         first_digit += 3;
         if (!strncasecmp ("inity", first_digit, 5))
           first_digit += 5;

         *address_of_string_pointer = first_digit;

         return 0;
       }
      break;
    }

  number_of_digits_before_decimal = 0;
  number_of_digits_after_decimal = 0;
  decimal_exponent = 0;
  seen_significant_digit = 0;
  for (p = first_digit;
       (((c = *p) != '\0')
       && (!c || !IS_DECIMAL_MARK (c))
       && (!c || !strchr (string_of_decimal_exponent_marks, c)));
       p++)
    {
      if (ISDIGIT (c))
       {
         if (seen_significant_digit || c > '0')
           {
             ++number_of_digits_before_decimal;
             seen_significant_digit = 1;
           }
         else
           {
             first_digit++;
           }
       }
      else
       {
         break;             /* p -> char after pre-decimal digits.  */
       }
    }                       /* For each digit before decimal mark.  */

#ifndef OLD_FLOAT_READS
  /* Ignore trailing 0's after the decimal point.  The original code here
   * (ifdef'd out) does not do this, and numbers like
   *   4.29496729600000000000e+09  (2**31)
   * come out inexact for some reason related to length of the digit
   * string.
   */
  if (c && IS_DECIMAL_MARK (c))
    {
      unsigned int zeros = 0;      /* Length of current string of zeros */

      for (p++; (c = *p) && ISDIGIT (c); p++)
       {
         if (c == '0')
           {
             zeros++;
           }
         else
           {
             number_of_digits_after_decimal += 1 + zeros;
             zeros = 0;
           }
       }
    }
#else
  if (c && IS_DECIMAL_MARK (c))
    {
      for (p++;
          (((c = *p) != '\0')
           && (!c || !strchr (string_of_decimal_exponent_marks, c)));
          p++)
       {
         if (ISDIGIT (c))
           {
             /* This may be retracted below.  */
             number_of_digits_after_decimal++;

             if ( /* seen_significant_digit || */ c > '0')
              {
                seen_significant_digit = TRUE;
              }
           }
         else
           {
             if (!seen_significant_digit)
              {
                number_of_digits_after_decimal = 0;
              }
             break;
           }
       }                    /* For each digit after decimal mark.  */
    }

  while (number_of_digits_after_decimal
        && first_digit[number_of_digits_before_decimal
                     + number_of_digits_after_decimal] == '0')
    --number_of_digits_after_decimal;
#endif

  if (flag_m68k_mri)
    {
      while (c == '_')
       c = *++p;
    }
  if (c && strchr (string_of_decimal_exponent_marks, c))
    {
      char digits_exponent_sign_char;

      c = *++p;
      if (flag_m68k_mri)
       {
         while (c == '_')
           c = *++p;
       }
      if (c && strchr ("+-", c))
       {
         digits_exponent_sign_char = c;
         c = *++p;
       }
      else
       {
         digits_exponent_sign_char = '+';
       }

      for (; (c); c = *++p)
       {
         if (ISDIGIT (c))
           {
             decimal_exponent = decimal_exponent * 10 + c - '0';
             /*
              * BUG! If we overflow here, we lose!
              */
           }
         else
           {
             break;
           }
       }

      if (digits_exponent_sign_char == '-')
       {
         decimal_exponent = -decimal_exponent;
       }
    }

  *address_of_string_pointer = p;

  number_of_digits_available =
    number_of_digits_before_decimal + number_of_digits_after_decimal;
  return_value = 0;
  if (number_of_digits_available == 0)
    {
      address_of_generic_floating_point_number->exponent = 0;  /* Not strictly necessary */
      address_of_generic_floating_point_number->leader
       = -1 + address_of_generic_floating_point_number->low;
      address_of_generic_floating_point_number->sign = digits_sign_char;
      /* We have just concocted (+/-)0.0E0 */

    }
  else
    {
      int count;            /* Number of useful digits left to scan.  */

      LITTLENUM_TYPE *digits_binary_low;
      unsigned int precision;
      unsigned int maximum_useful_digits;
      unsigned int number_of_digits_to_use;
      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) */
      maximum_useful_digits = (((precision - 2))
                            * ( (LITTLENUM_NUMBER_OF_BITS))
                            * 1000000 / 3321928)
       + 2;                 /* 2 :: guard digits.  */

      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);

      more_than_enough_bits_for_digits
       = (number_of_digits_to_use * 3321928 / 1000000 + 1);

      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 (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 successful, 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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void flonum_copy ( FLONUM_TYPE *  in,
FLONUM_TYPE *  out 
)

Definition at line 25 of file flonum-copy.c.

{
  unsigned int in_length;   /* 0 origin */
  unsigned int out_length;  /* 0 origin */

  out->sign = in->sign;
  in_length = in->leader - in->low;

  if (in->leader < in->low)
    {
      out->leader = out->low - 1;  /* 0.0 case */
    }
  else
    {
      out_length = out->high - out->low;
      /* Assume no GAPS in packing of littlenums.
        I.e. sizeof(array) == sizeof(element) * number_of_elements.  */
      if (in_length <= out_length)
       {
         {
           /* For defensive programming, zero any high-order
              littlenums we don't need.  This is destroying evidence
              and wasting time, so why bother???  */
           if (in_length < out_length)
             {
              memset ((char *) (out->low + in_length + 1), '\0',
                     out_length - in_length);
             }
         }
         memcpy ((void *) (out->low), (void *) (in->low),
                ((in_length + 1) * sizeof (LITTLENUM_TYPE)));
         out->exponent = in->exponent;
         out->leader = in->leader - in->low + out->low;
       }
      else
       {
         int shorten;              /* 1-origin. Number of littlenums we drop.  */

         shorten = in_length - out_length;
         /* Assume out_length >= 0 ! */
         memcpy ((void *) (out->low), (void *) (in->low + shorten),
                ((out_length + 1) * sizeof (LITTLENUM_TYPE)));
         out->leader = out->high;
         out->exponent = in->exponent + shorten;
       }
    }                       /* if any significant bits */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void flonum_multip ( const FLONUM_TYPE *  a,
const FLONUM_TYPE *  b,
FLONUM_TYPE *  product 
)

Definition at line 74 of file flonum-mult.c.

{
  int size_of_a;            /* 0 origin  */
  int size_of_b;            /* 0 origin  */
  int size_of_product;             /* 0 origin  */
  int size_of_sum;          /* 0 origin  */
  int extra_product_positions;     /* 1 origin  */
  unsigned long work;
  unsigned long carry;
  long exponent;
  LITTLENUM_TYPE *q;
  long significant;         /* TRUE when we emit a non-0 littlenum  */
  /* ForTran accent follows.  */
  int P;                    /* Scan product low-order -> high.  */
  int N;                    /* As in sum above.  */
  int A;                    /* Which [] of a?  */
  int B;                    /* Which [] of b?  */

  if ((a->sign != '-' && a->sign != '+')
      || (b->sign != '-' && b->sign != '+'))
    {
      /* Got to fail somehow.  Any suggestions?  */
      product->sign = 0;
      return;
    }
  product->sign = (a->sign == b->sign) ? '+' : '-';
  size_of_a = a->leader - a->low;
  size_of_b = b->leader - b->low;
  exponent = a->exponent + b->exponent;
  size_of_product = product->high - product->low;
  size_of_sum = size_of_a + size_of_b;
  extra_product_positions = size_of_product - size_of_sum;
  if (extra_product_positions < 0)
    {
      P = extra_product_positions; /* P < 0  */
      exponent -= extra_product_positions;       /* Increases exponent.  */
    }
  else
    {
      P = 0;
    }
  carry = 0;
  significant = 0;
  for (N = 0; N <= size_of_sum; N++)
    {
      work = carry;
      carry = 0;
      for (A = 0; A <= N; A++)
       {
         B = N - A;
         if (A <= size_of_a && B <= size_of_b && B >= 0)
           {
#ifdef TRACE
             printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n",
                    A, a->low[A], B, b->low[B], work);
#endif
             /* Watch out for sign extension!  Without the casts, on
               the DEC Alpha, the multiplication result is *signed*
               int, which gets sign-extended to convert to the
               unsigned long!  */
             work += (unsigned long) a->low[A] * (unsigned long) b->low[B];
             carry += work >> LITTLENUM_NUMBER_OF_BITS;
             work &= LITTLENUM_MASK;
#ifdef TRACE
             printf ("work=%08x carry=%04x\n", work, carry);
#endif
           }
       }
      significant |= work;
      if (significant || P < 0)
       {
         if (P >= 0)
           {
             product->low[P] = work;
#ifdef TRACE
             printf ("P=%d. work[p]:=%04x\n", P, work);
#endif
           }
         P++;
       }
      else
       {
         extra_product_positions++;
         exponent++;
       }
    }
  /* [P]-> position # size_of_sum + 1.
     This is where 'carry' should go.  */
#ifdef TRACE
  printf ("final carry =%04x\n", carry);
#endif
  if (carry)
    {
      if (extra_product_positions > 0)
       product->low[P] = carry;
      else
       {
         /* No room at high order for carry littlenum.  */
         /* Shift right 1 to make room for most significant littlenum.  */
         exponent++;
         P--;
         for (q = product->low + P; q >= product->low; q--)
           {
             work = *q;
             *q = carry;
             carry = work;
           }
       }
    }
  else
    P--;
  product->leader = product->low + P;
  product->exponent = exponent;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 189 of file flonum-konst.c.

Definition at line 206 of file flonum-konst.c.

Definition at line 28 of file flonum-konst.c.