PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - bcmath/libbcmath/src - div.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 110
Code covered: 92.7 % Executed lines: 102
Legend: not executed executed

       1                 : /* div.c: bcmath library file. */
       2                 : /*
       3                 :     Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
       4                 :     Copyright (C) 2000 Philip A. Nelson
       5                 : 
       6                 :     This library is free software; you can redistribute it and/or
       7                 :     modify it under the terms of the GNU Lesser General Public
       8                 :     License as published by the Free Software Foundation; either
       9                 :     version 2 of the License, or (at your option) any later version.
      10                 : 
      11                 :     This library is distributed in the hope that it will be useful,
      12                 :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :     Lesser General Public License for more details.  (COPYING.LIB)
      15                 : 
      16                 :     You should have received a copy of the GNU Lesser General Public
      17                 :     License along with this library; if not, write to:
      18                 : 
      19                 :       The Free Software Foundation, Inc.
      20                 :       59 Temple Place, Suite 330
      21                 :       Boston, MA 02111-1307 USA.
      22                 : 
      23                 :     You may contact the author by:
      24                 :        e-mail:  philnelson@acm.org
      25                 :       us-mail:  Philip A. Nelson
      26                 :                 Computer Science Department, 9062
      27                 :                 Western Washington University
      28                 :                 Bellingham, WA 98226-9062
      29                 :        
      30                 : *************************************************************************/
      31                 : 
      32                 : #include <config.h>
      33                 : #include <stdio.h>
      34                 : #include <assert.h>
      35                 : #include <stdlib.h>
      36                 : #include <ctype.h>
      37                 : #include <stdarg.h>
      38                 : #include "bcmath.h"
      39                 : #include "private.h"
      40                 : 
      41                 : 
      42                 : /* Some utility routines for the divide:  First a one digit multiply.
      43                 :    NUM (with SIZE digits) is multiplied by DIGIT and the result is
      44                 :    placed into RESULT.  It is written so that NUM and RESULT can be
      45                 :    the same pointers.  */
      46                 : 
      47                 : static void
      48                 : _one_mult (num, size, digit, result)
      49                 :      unsigned char *num;
      50                 :      int size, digit;
      51                 :      unsigned char *result;
      52             217 : {
      53                 :   int carry, value;
      54                 :   unsigned char *nptr, *rptr;
      55                 : 
      56             217 :   if (digit == 0)
      57               0 :     memset (result, 0, size);
      58                 :   else
      59                 :     {
      60             217 :       if (digit == 1)
      61              21 :         memcpy (result, num, size);
      62                 :       else
      63                 :         {
      64                 :           /* Initialize */
      65             196 :           nptr = (unsigned char *) (num+size-1);
      66             196 :           rptr = (unsigned char *) (result+size-1);
      67             196 :           carry = 0;
      68                 : 
      69            2926 :           while (size-- > 0)
      70                 :             {
      71            2534 :               value = *nptr-- * digit + carry;
      72            2534 :               *rptr-- = value % BASE;
      73            2534 :               carry = value / BASE;
      74                 :             }
      75                 : 
      76             196 :           if (carry != 0) *rptr = carry;
      77                 :         }
      78                 :     }
      79             217 : }
      80                 : 
      81                 : 
      82                 : /* The full division routine. This computes N1 / N2.  It returns
      83                 :    0 if the division is ok and the result is in QUOT.  The number of
      84                 :    digits after the decimal point is SCALE. It returns -1 if division
      85                 :    by zero is tried.  The algorithm is found in Knuth Vol 2. p237. */
      86                 : 
      87                 : int
      88                 : bc_divide (bc_num n1, bc_num n2, bc_num *quot, int scale TSRMLS_DC)
      89              24 : {
      90                 :   bc_num qval;
      91                 :   unsigned char *num1, *num2;
      92                 :   unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
      93                 :   int  scale1, val;
      94                 :   unsigned int  len1, len2, scale2, qdigits, extra, count;
      95                 :   unsigned int  qdig, qguess, borrow, carry;
      96                 :   unsigned char *mval;
      97                 :   char zero;
      98                 :   unsigned int  norm;
      99                 : 
     100                 :   /* Test for divide by zero. */
     101              24 :   if (bc_is_zero (n2 TSRMLS_CC)) return -1;
     102                 : 
     103                 :   /* Test for divide by 1.  If it is we must truncate. */
     104              23 :   if (n2->n_scale == 0)
     105                 :     {
     106              11 :       if (n2->n_len == 1 && *n2->n_value == 1)
     107                 :         {
     108               3 :           qval = bc_new_num (n1->n_len, scale);
     109               3 :           qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
     110               3 :           memset (&qval->n_value[n1->n_len],0,scale);
     111               3 :           memcpy (qval->n_value, n1->n_value,
     112                 :                   n1->n_len + MIN(n1->n_scale,scale));
     113               3 :           bc_free_num (quot);
     114               3 :           *quot = qval;
     115                 :         }
     116                 :     }
     117                 : 
     118                 :   /* Set up the divide.  Move the decimal point on n1 by n2's scale.
     119                 :      Remember, zeros on the end of num2 are wasted effort for dividing. */
     120              23 :   scale2 = n2->n_scale;
     121              23 :   n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
     122              23 :   while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
     123                 : 
     124              23 :   len1 = n1->n_len + scale2;
     125              23 :   scale1 = n1->n_scale - scale2;
     126              23 :   if (scale1 < scale)
     127              17 :     extra = scale - scale1;
     128                 :   else
     129               6 :     extra = 0;
     130              23 :   num1 = (unsigned char *) safe_emalloc (1, n1->n_len+n1->n_scale, extra+2);
     131              23 :   if (num1 == NULL) bc_out_of_memory();
     132              23 :   memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
     133              23 :   memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
     134                 : 
     135              23 :   len2 = n2->n_len + scale2;
     136              23 :   num2 = (unsigned char *) safe_emalloc (1, len2, 1);
     137              23 :   if (num2 == NULL) bc_out_of_memory();
     138              23 :   memcpy (num2, n2->n_value, len2);
     139              23 :   *(num2+len2) = 0;
     140              23 :   n2ptr = num2;
     141              46 :   while (*n2ptr == 0)
     142                 :     {
     143               0 :       n2ptr++;
     144               0 :       len2--;
     145                 :     }
     146                 : 
     147                 :   /* Calculate the number of quotient digits. */
     148              23 :   if (len2 > len1+scale)
     149                 :     {
     150               0 :       qdigits = scale+1;
     151               0 :       zero = TRUE;
     152                 :     }
     153                 :   else
     154                 :     {
     155              23 :       zero = FALSE;
     156              23 :       if (len2>len1)
     157               0 :         qdigits = scale+1;      /* One for the zero integer part. */
     158                 :       else
     159              23 :         qdigits = len1-len2+scale+1;
     160                 :     }
     161                 : 
     162                 :   /* Allocate and zero the storage for the quotient. */
     163              23 :   qval = bc_new_num (qdigits-scale,scale);
     164              23 :   memset (qval->n_value, 0, qdigits);
     165                 : 
     166                 :   /* Allocate storage for the temporary storage mval. */
     167              23 :   mval = (unsigned char *) safe_emalloc (1, len2, 1);
     168              23 :   if (mval == NULL) bc_out_of_memory ();
     169                 : 
     170                 :   /* Now for the full divide algorithm. */
     171              23 :   if (!zero)
     172                 :     {
     173                 :       /* Normalize */
     174              23 :       norm =  10 / ((int)*n2ptr + 1);
     175              23 :       if (norm != 1)
     176                 :         {
     177              19 :           _one_mult (num1, len1+scale1+extra+1, norm, num1);
     178              19 :           _one_mult (n2ptr, len2, norm, n2ptr);
     179                 :         }
     180                 : 
     181                 :       /* Initialize divide loop. */
     182              23 :       qdig = 0;
     183              23 :       if (len2 > len1)
     184               0 :         qptr = (unsigned char *) qval->n_value+len2-len1;
     185                 :       else
     186              23 :         qptr = (unsigned char *) qval->n_value;
     187                 : 
     188                 :       /* Loop */
     189             257 :       while (qdig <= len1+scale-len2)
     190                 :         {
     191                 :           /* Calculate the quotient digit guess. */
     192             211 :           if (*n2ptr == num1[qdig])
     193              10 :             qguess = 9;
     194                 :           else
     195             201 :             qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
     196                 : 
     197                 :           /* Test qguess. */
     198             211 :           if (n2ptr[1]*qguess >
     199                 :               (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
     200                 :                + num1[qdig+2])
     201                 :             {
     202              46 :               qguess--;
     203                 :               /* And again. */
     204              46 :               if (n2ptr[1]*qguess >
     205                 :                   (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
     206                 :                   + num1[qdig+2])
     207               0 :                 qguess--;
     208                 :             }
     209                 : 
     210                 :           /* Multiply and subtract. */
     211             211 :           borrow = 0;
     212             211 :           if (qguess != 0)
     213                 :             {
     214             179 :               *mval = 0;
     215             179 :               _one_mult (n2ptr, len2, qguess, mval+1);
     216             179 :               ptr1 = (unsigned char *) num1+qdig+len2;
     217             179 :               ptr2 = (unsigned char *) mval+len2;
     218            2634 :               for (count = 0; count < len2+1; count++)
     219                 :                 {
     220            2455 :                   val = (int) *ptr1 - (int) *ptr2-- - borrow;
     221            2455 :                   if (val < 0)
     222                 :                     {
     223            1010 :                       val += 10;
     224            1010 :                       borrow = 1;
     225                 :                     }
     226                 :                   else
     227            1445 :                     borrow = 0;
     228            2455 :                   *ptr1-- = val;
     229                 :                 }
     230                 :             }
     231                 : 
     232                 :           /* Test for negative result. */
     233             211 :           if (borrow == 1)
     234                 :             {
     235               2 :               qguess--;
     236               2 :               ptr1 = (unsigned char *) num1+qdig+len2;
     237               2 :               ptr2 = (unsigned char *) n2ptr+len2-1;
     238               2 :               carry = 0;
     239              20 :               for (count = 0; count < len2; count++)
     240                 :                 {
     241              18 :                   val = (int) *ptr1 + (int) *ptr2-- + carry;
     242              18 :                   if (val > 9)
     243                 :                     {
     244               9 :                       val -= 10;
     245               9 :                       carry = 1;
     246                 :                     }
     247                 :                   else
     248               9 :                     carry = 0;
     249              18 :                   *ptr1-- = val;
     250                 :                 }
     251               2 :               if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
     252                 :             }
     253                 : 
     254                 :           /* We now know the quotient digit. */
     255             211 :           *qptr++ =  qguess;
     256             211 :           qdig++;
     257                 :         }
     258                 :     }
     259                 : 
     260                 :   /* Clean up and return the number. */
     261              23 :   qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
     262              23 :   if (bc_is_zero (qval TSRMLS_CC)) qval->n_sign = PLUS;
     263              23 :   _bc_rm_leading_zeros (qval);
     264              23 :   bc_free_num (quot);
     265              23 :   *quot = qval;
     266                 : 
     267                 :   /* Clean up temporary storage. */
     268              23 :   efree (mval);
     269              23 :   efree (num1);
     270              23 :   efree (num2);
     271                 : 
     272              23 :   return 0;     /* Everything is OK. */
     273                 : }
     274                 : 

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:05 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.