Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /* flonum_mult.c - multiply two flonums
  2.    Copyright 1987, 1990, 1991, 1992, 1995, 2000, 2002, 2003, 2007
  3.    Free Software Foundation, Inc.
  4.  
  5.    This file is part of GAS, the GNU Assembler.
  6.  
  7.    GAS is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 3, or (at your option)
  10.    any later version.
  11.  
  12.    GAS is distributed in the hope that it will be useful, but WITHOUT
  13.    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14.    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  15.    License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with GAS; see the file COPYING.  If not, write to the Free
  19.    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
  20.    02110-1301, USA.  */
  21.  
  22. #include "ansidecl.h"
  23. #include "flonum.h"
  24.  
  25. /*      plan for a . b => p(roduct)
  26.  
  27.         +-------+-------+-/   /-+-------+-------+
  28.         | a     | a     |  ...  | a     | a     |
  29.         |  A    |  A-1  |       |  1    |  0    |
  30.         +-------+-------+-/   /-+-------+-------+
  31.  
  32.         +-------+-------+-/   /-+-------+-------+
  33.         | b     | b     |  ...  | b     | b     |
  34.         |  B    |  B-1  |       |  1    |  0    |
  35.         +-------+-------+-/   /-+-------+-------+
  36.  
  37.         +-------+-------+-/   /-+-------+-/   /-+-------+-------+
  38.         | p     | p     |  ...  | p     |  ...  | p     | p     |
  39.         |  A+B+1|  A+B  |       |  N    |       |  1    |  0    |
  40.         +-------+-------+-/   /-+-------+-/   /-+-------+-------+
  41.  
  42.         /^\
  43.         (carry) a .b       ...      |      ...   a .b    a .b
  44.         A  B                |             0  1    0  0
  45.         |
  46.         ...         |      ...   a .b
  47.         |                 1  0
  48.         |
  49.         |          ...
  50.         |
  51.         |
  52.         |
  53.         |                 ___
  54.         |                 \
  55.         +-----  P  =   >  a .b
  56.         N         /__  i  j
  57.  
  58.         N = 0 ... A+B
  59.  
  60.         for all i,j where i+j=N
  61.         [i,j integers > 0]
  62.  
  63.         a[], b[], p[] may not intersect.
  64.         Zero length factors signify 0 significant bits: treat as 0.0.
  65.         0.0 factors do the right thing.
  66.         Zero length product OK.
  67.  
  68.         I chose the ForTran accent "foo[bar]" instead of the C accent "*garply"
  69.         because I felt the ForTran way was more intuitive. The C way would
  70.         probably yield better code on most C compilers. Dean Elsner.
  71.         (C style also gives deeper insight [to me] ... oh well ...)  */
  72. void
  73. flonum_multip (const FLONUM_TYPE *a, const FLONUM_TYPE *b,
  74.                FLONUM_TYPE *product)
  75. {
  76.   int size_of_a;                /* 0 origin  */
  77.   int size_of_b;                /* 0 origin  */
  78.   int size_of_product;          /* 0 origin  */
  79.   int size_of_sum;              /* 0 origin  */
  80.   int extra_product_positions;  /* 1 origin  */
  81.   unsigned long work;
  82.   unsigned long carry;
  83.   long exponent;
  84.   LITTLENUM_TYPE *q;
  85.   long significant;             /* TRUE when we emit a non-0 littlenum  */
  86.   /* ForTran accent follows.  */
  87.   int P;                        /* Scan product low-order -> high.  */
  88.   int N;                        /* As in sum above.  */
  89.   int A;                        /* Which [] of a?  */
  90.   int B;                        /* Which [] of b?  */
  91.  
  92.   if ((a->sign != '-' && a->sign != '+')
  93.       || (b->sign != '-' && b->sign != '+'))
  94.     {
  95.       /* Got to fail somehow.  Any suggestions?  */
  96.       product->sign = 0;
  97.       return;
  98.     }
  99.   product->sign = (a->sign == b->sign) ? '+' : '-';
  100.   size_of_a = a->leader - a->low;
  101.   size_of_b = b->leader - b->low;
  102.   exponent = a->exponent + b->exponent;
  103.   size_of_product = product->high - product->low;
  104.   size_of_sum = size_of_a + size_of_b;
  105.   extra_product_positions = size_of_product - size_of_sum;
  106.   if (extra_product_positions < 0)
  107.     {
  108.       P = extra_product_positions;      /* P < 0  */
  109.       exponent -= extra_product_positions;      /* Increases exponent.  */
  110.     }
  111.   else
  112.     {
  113.       P = 0;
  114.     }
  115.   carry = 0;
  116.   significant = 0;
  117.   for (N = 0; N <= size_of_sum; N++)
  118.     {
  119.       work = carry;
  120.       carry = 0;
  121.       for (A = 0; A <= N; A++)
  122.         {
  123.           B = N - A;
  124.           if (A <= size_of_a && B <= size_of_b && B >= 0)
  125.             {
  126. #ifdef TRACE
  127.               printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n",
  128.                       A, a->low[A], B, b->low[B], work);
  129. #endif
  130.               /* Watch out for sign extension!  Without the casts, on
  131.                  the DEC Alpha, the multiplication result is *signed*
  132.                  int, which gets sign-extended to convert to the
  133.                  unsigned long!  */
  134.               work += (unsigned long) a->low[A] * (unsigned long) b->low[B];
  135.               carry += work >> LITTLENUM_NUMBER_OF_BITS;
  136.               work &= LITTLENUM_MASK;
  137. #ifdef TRACE
  138.               printf ("work=%08x carry=%04x\n", work, carry);
  139. #endif
  140.             }
  141.         }
  142.       significant |= work;
  143.       if (significant || P < 0)
  144.         {
  145.           if (P >= 0)
  146.             {
  147.               product->low[P] = work;
  148. #ifdef TRACE
  149.               printf ("P=%d. work[p]:=%04x\n", P, work);
  150. #endif
  151.             }
  152.           P++;
  153.         }
  154.       else
  155.         {
  156.           extra_product_positions++;
  157.           exponent++;
  158.         }
  159.     }
  160.   /* [P]-> position # size_of_sum + 1.
  161.      This is where 'carry' should go.  */
  162. #ifdef TRACE
  163.   printf ("final carry =%04x\n", carry);
  164. #endif
  165.   if (carry)
  166.     {
  167.       if (extra_product_positions > 0)
  168.         product->low[P] = carry;
  169.       else
  170.         {
  171.           /* No room at high order for carry littlenum.  */
  172.           /* Shift right 1 to make room for most significant littlenum.  */
  173.           exponent++;
  174.           P--;
  175.           for (q = product->low + P; q >= product->low; q--)
  176.             {
  177.               work = *q;
  178.               *q = carry;
  179.               carry = work;
  180.             }
  181.         }
  182.     }
  183.   else
  184.     P--;
  185.   product->leader = product->low + P;
  186.   product->exponent = exponent;
  187. }
  188.