Subversion Repositories Kolibri OS

Rev

Rev 5222 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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