The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/ficl/math64.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*******************************************************************
    2 ** m a t h 6 4 . c
    3 ** Forth Inspired Command Language - 64 bit math support routines
    4 ** Author: John Sadler (john_sadler@alum.mit.edu)
    5 ** Created: 25 January 1998
    6 ** Rev 2.03: Support for 128 bit DP math. This file really ouught to
    7 ** be renamed!
    8 ** $Id: math64.c,v 1.9 2001/12/05 07:21:34 jsadler Exp $
    9 *******************************************************************/
   10 /*
   11 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
   12 ** All rights reserved.
   13 **
   14 ** Get the latest Ficl release at http://ficl.sourceforge.net
   15 **
   16 ** I am interested in hearing from anyone who uses ficl. If you have
   17 ** a problem, a success story, a defect, an enhancement request, or
   18 ** if you would like to contribute to the ficl release, please
   19 ** contact me by email at the address above.
   20 **
   21 ** L I C E N S E  and  D I S C L A I M E R
   22 ** 
   23 ** Redistribution and use in source and binary forms, with or without
   24 ** modification, are permitted provided that the following conditions
   25 ** are met:
   26 ** 1. Redistributions of source code must retain the above copyright
   27 **    notice, this list of conditions and the following disclaimer.
   28 ** 2. Redistributions in binary form must reproduce the above copyright
   29 **    notice, this list of conditions and the following disclaimer in the
   30 **    documentation and/or other materials provided with the distribution.
   31 **
   32 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   33 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   34 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   35 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   36 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   37 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   38 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   39 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   40 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   41 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   42 ** SUCH DAMAGE.
   43 */
   44 
   45 /* $FreeBSD$ */
   46 
   47 #include "ficl.h"
   48 #include "math64.h"
   49 
   50 
   51 /**************************************************************************
   52                         m 6 4 A b s
   53 ** Returns the absolute value of an DPINT
   54 **************************************************************************/
   55 DPINT m64Abs(DPINT x)
   56 {
   57     if (m64IsNegative(x))
   58         x = m64Negate(x);
   59 
   60     return x;
   61 }
   62 
   63 
   64 /**************************************************************************
   65                         m 6 4 F l o o r e d D i v I
   66 ** 
   67 ** FROM THE FORTH ANS...
   68 ** Floored division is integer division in which the remainder carries
   69 ** the sign of the divisor or is zero, and the quotient is rounded to
   70 ** its arithmetic floor. Symmetric division is integer division in which
   71 ** the remainder carries the sign of the dividend or is zero and the
   72 ** quotient is the mathematical quotient rounded towards zero or
   73 ** truncated. Examples of each are shown in tables 3.3 and 3.4. 
   74 ** 
   75 ** Table 3.3 - Floored Division Example
   76 ** Dividend        Divisor Remainder       Quotient
   77 ** --------        ------- ---------       --------
   78 **  10                7       3                1
   79 ** -10                7       4               -2
   80 **  10               -7      -4               -2
   81 ** -10               -7      -3                1
   82 ** 
   83 ** 
   84 ** Table 3.4 - Symmetric Division Example
   85 ** Dividend        Divisor Remainder       Quotient
   86 ** --------        ------- ---------       --------
   87 **  10                7       3                1
   88 ** -10                7      -3               -1
   89 **  10               -7       3               -1
   90 ** -10               -7      -3                1
   91 **************************************************************************/
   92 INTQR m64FlooredDivI(DPINT num, FICL_INT den)
   93 {
   94     INTQR qr;
   95     UNSQR uqr;
   96     int signRem = 1;
   97     int signQuot = 1;
   98 
   99     if (m64IsNegative(num))
  100     {
  101         num = m64Negate(num);
  102         signQuot = -signQuot;
  103     }
  104 
  105     if (den < 0)
  106     {
  107         den      = -den;
  108         signRem  = -signRem;
  109         signQuot = -signQuot;
  110     }
  111 
  112     uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den);
  113     qr = m64CastQRUI(uqr);
  114     if (signQuot < 0)
  115     {
  116         qr.quot = -qr.quot;
  117         if (qr.rem != 0)
  118         {
  119             qr.quot--;
  120             qr.rem = den - qr.rem;
  121         }
  122     }
  123 
  124     if (signRem < 0)
  125         qr.rem = -qr.rem;
  126 
  127     return qr;
  128 }
  129 
  130 
  131 /**************************************************************************
  132                         m 6 4 I s N e g a t i v e
  133 ** Returns TRUE if the specified DPINT has its sign bit set.
  134 **************************************************************************/
  135 int m64IsNegative(DPINT x)
  136 {
  137     return (x.hi < 0);
  138 }
  139 
  140 
  141 /**************************************************************************
  142                         m 6 4 M a c
  143 ** Mixed precision multiply and accumulate primitive for number building.
  144 ** Multiplies DPUNS u by FICL_UNS mul and adds FICL_UNS add. Mul is typically
  145 ** the numeric base, and add represents a digit to be appended to the 
  146 ** growing number. 
  147 ** Returns the result of the operation
  148 **************************************************************************/
  149 DPUNS m64Mac(DPUNS u, FICL_UNS mul, FICL_UNS add)
  150 {
  151     DPUNS resultLo = ficlLongMul(u.lo, mul);
  152     DPUNS resultHi = ficlLongMul(u.hi, mul);
  153     resultLo.hi += resultHi.lo;
  154     resultHi.lo = resultLo.lo + add;
  155 
  156     if (resultHi.lo < resultLo.lo)
  157         resultLo.hi++;
  158 
  159     resultLo.lo = resultHi.lo;
  160 
  161     return resultLo;
  162 }
  163 
  164 
  165 /**************************************************************************
  166                         m 6 4 M u l I
  167 ** Multiplies a pair of FICL_INTs and returns an DPINT result.
  168 **************************************************************************/
  169 DPINT m64MulI(FICL_INT x, FICL_INT y)
  170 {
  171     DPUNS prod;
  172     int sign = 1;
  173 
  174     if (x < 0)
  175     {
  176         sign = -sign;
  177         x = -x;
  178     }
  179 
  180     if (y < 0)
  181     {
  182         sign = -sign;
  183         y = -y;
  184     }
  185 
  186     prod = ficlLongMul(x, y);
  187     if (sign > 0)
  188         return m64CastUI(prod);
  189     else
  190         return m64Negate(m64CastUI(prod));
  191 }
  192 
  193 
  194 /**************************************************************************
  195                         m 6 4 N e g a t e
  196 ** Negates an DPINT by complementing and incrementing.
  197 **************************************************************************/
  198 DPINT m64Negate(DPINT x)
  199 {
  200     x.hi = ~x.hi;
  201     x.lo = ~x.lo;
  202     x.lo ++;
  203     if (x.lo == 0)
  204         x.hi++;
  205 
  206     return x;
  207 }
  208 
  209 
  210 /**************************************************************************
  211                         m 6 4 P u s h
  212 ** Push an DPINT onto the specified stack in the order required
  213 ** by ANS Forth (most significant cell on top)
  214 ** These should probably be macros...
  215 **************************************************************************/
  216 void  i64Push(FICL_STACK *pStack, DPINT i64)
  217 {
  218     stackPushINT(pStack, i64.lo);
  219     stackPushINT(pStack, i64.hi);
  220     return;
  221 }
  222 
  223 void  u64Push(FICL_STACK *pStack, DPUNS u64)
  224 {
  225     stackPushINT(pStack, u64.lo);
  226     stackPushINT(pStack, u64.hi);
  227     return;
  228 }
  229 
  230 
  231 /**************************************************************************
  232                         m 6 4 P o p
  233 ** Pops an DPINT off the stack in the order required by ANS Forth
  234 ** (most significant cell on top)
  235 ** These should probably be macros...
  236 **************************************************************************/
  237 DPINT i64Pop(FICL_STACK *pStack)
  238 {
  239     DPINT ret;
  240     ret.hi = stackPopINT(pStack);
  241     ret.lo = stackPopINT(pStack);
  242     return ret;
  243 }
  244 
  245 DPUNS u64Pop(FICL_STACK *pStack)
  246 {
  247     DPUNS ret;
  248     ret.hi = stackPopINT(pStack);
  249     ret.lo = stackPopINT(pStack);
  250     return ret;
  251 }
  252 
  253 
  254 /**************************************************************************
  255                         m 6 4 S y m m e t r i c D i v
  256 ** Divide an DPINT by a FICL_INT and return a FICL_INT quotient and a
  257 ** FICL_INT remainder. The absolute values of quotient and remainder are not
  258 ** affected by the signs of the numerator and denominator (the operation
  259 ** is symmetric on the number line)
  260 **************************************************************************/
  261 INTQR m64SymmetricDivI(DPINT num, FICL_INT den)
  262 {
  263     INTQR qr;
  264     UNSQR uqr;
  265     int signRem = 1;
  266     int signQuot = 1;
  267 
  268     if (m64IsNegative(num))
  269     {
  270         num = m64Negate(num);
  271         signRem  = -signRem;
  272         signQuot = -signQuot;
  273     }
  274 
  275     if (den < 0)
  276     {
  277         den      = -den;
  278         signQuot = -signQuot;
  279     }
  280 
  281     uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den);
  282     qr = m64CastQRUI(uqr);
  283     if (signRem < 0)
  284         qr.rem = -qr.rem;
  285 
  286     if (signQuot < 0)
  287         qr.quot = -qr.quot;
  288 
  289     return qr;
  290 }
  291 
  292 
  293 /**************************************************************************
  294                         m 6 4 U M o d
  295 ** Divides a DPUNS by base (an UNS16) and returns an UNS16 remainder.
  296 ** Writes the quotient back to the original DPUNS as a side effect.
  297 ** This operation is typically used to convert an DPUNS to a text string
  298 ** in any base. See words.c:numberSignS, for example.
  299 ** Mechanics: performs 4 ficlLongDivs, each of which produces 16 bits
  300 ** of the quotient. C does not provide a way to divide an FICL_UNS by an
  301 ** UNS16 and get an FICL_UNS quotient (ldiv is closest, but it's signed,
  302 ** unfortunately), so I've used ficlLongDiv.
  303 **************************************************************************/
  304 #if (BITS_PER_CELL == 32)
  305 
  306 #define UMOD_SHIFT 16
  307 #define UMOD_MASK 0x0000ffff
  308 
  309 #elif (BITS_PER_CELL == 64)
  310 
  311 #define UMOD_SHIFT 32
  312 #define UMOD_MASK 0x00000000ffffffff
  313 
  314 #endif
  315 
  316 UNS16 m64UMod(DPUNS *pUD, UNS16 base)
  317 {
  318     DPUNS ud;
  319     UNSQR qr;
  320     DPUNS result;
  321 
  322     result.hi = result.lo = 0;
  323 
  324     ud.hi = 0;
  325     ud.lo = pUD->hi >> UMOD_SHIFT;
  326     qr = ficlLongDiv(ud, (FICL_UNS)base);
  327     result.hi = qr.quot << UMOD_SHIFT;
  328 
  329     ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->hi & UMOD_MASK);
  330     qr = ficlLongDiv(ud, (FICL_UNS)base);
  331     result.hi |= qr.quot & UMOD_MASK;
  332 
  333     ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo >> UMOD_SHIFT);
  334     qr = ficlLongDiv(ud, (FICL_UNS)base);
  335     result.lo = qr.quot << UMOD_SHIFT;
  336 
  337     ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo & UMOD_MASK);
  338     qr = ficlLongDiv(ud, (FICL_UNS)base);
  339     result.lo |= qr.quot & UMOD_MASK;
  340 
  341     *pUD = result;
  342 
  343     return (UNS16)(qr.rem);
  344 }
  345 
  346 
  347 /**************************************************************************
  348 ** Contributed by
  349 ** Michael A. Gauland   gaulandm@mdhost.cse.tek.com  
  350 **************************************************************************/
  351 #if PORTABLE_LONGMULDIV != 0
  352 /**************************************************************************
  353                         m 6 4 A d d
  354 ** 
  355 **************************************************************************/
  356 DPUNS m64Add(DPUNS x, DPUNS y)
  357 {
  358     DPUNS result;
  359     int carry;
  360     
  361     result.hi = x.hi + y.hi;
  362     result.lo = x.lo + y.lo;
  363 
  364 
  365     carry  = ((x.lo | y.lo) & CELL_HI_BIT) && !(result.lo & CELL_HI_BIT);
  366     carry |= ((x.lo & y.lo) & CELL_HI_BIT);
  367 
  368     if (carry)
  369     {
  370         result.hi++;
  371     }
  372 
  373     return result;
  374 }
  375 
  376 
  377 /**************************************************************************
  378                         m 6 4 S u b
  379 ** 
  380 **************************************************************************/
  381 DPUNS m64Sub(DPUNS x, DPUNS y)
  382 {
  383     DPUNS result;
  384     
  385     result.hi = x.hi - y.hi;
  386     result.lo = x.lo - y.lo;
  387 
  388     if (x.lo < y.lo) 
  389     {
  390         result.hi--;
  391     }
  392 
  393     return result;
  394 }
  395 
  396 
  397 /**************************************************************************
  398                         m 6 4 A S L
  399 ** 64 bit left shift
  400 **************************************************************************/
  401 DPUNS m64ASL( DPUNS x )
  402 {
  403     DPUNS result;
  404     
  405     result.hi = x.hi << 1;
  406     if (x.lo & CELL_HI_BIT) 
  407     {
  408         result.hi++;
  409     }
  410 
  411     result.lo = x.lo << 1;
  412 
  413     return result;
  414 }
  415 
  416 
  417 /**************************************************************************
  418                         m 6 4 A S R
  419 ** 64 bit right shift (unsigned - no sign extend)
  420 **************************************************************************/
  421 DPUNS m64ASR( DPUNS x )
  422 {
  423     DPUNS result;
  424     
  425     result.lo = x.lo >> 1;
  426     if (x.hi & 1) 
  427     {
  428         result.lo |= CELL_HI_BIT;
  429     }
  430 
  431     result.hi = x.hi >> 1;
  432     return result;
  433 }
  434 
  435 
  436 /**************************************************************************
  437                         m 6 4 O r
  438 ** 64 bit bitwise OR
  439 **************************************************************************/
  440 DPUNS m64Or( DPUNS x, DPUNS y )
  441 {
  442     DPUNS result;
  443     
  444     result.hi = x.hi | y.hi;
  445     result.lo = x.lo | y.lo;
  446     
  447     return result;
  448 }
  449 
  450 
  451 /**************************************************************************
  452                         m 6 4 C o m p a r e
  453 ** Return -1 if x < y; 0 if x==y, and 1 if x > y.
  454 **************************************************************************/
  455 int m64Compare(DPUNS x, DPUNS y)
  456 {
  457     int result;
  458     
  459     if (x.hi > y.hi) 
  460     {
  461         result = +1;
  462     } 
  463     else if (x.hi < y.hi) 
  464     {
  465         result = -1;
  466     } 
  467     else 
  468     {
  469         /* High parts are equal */
  470         if (x.lo > y.lo) 
  471         {
  472             result = +1;
  473         } 
  474         else if (x.lo < y.lo) 
  475         {
  476             result = -1;
  477         } 
  478         else 
  479         {
  480             result = 0;
  481         }
  482     }
  483     
  484     return result;
  485 }
  486 
  487 
  488 /**************************************************************************
  489                         f i c l L o n g M u l
  490 ** Portable versions of ficlLongMul and ficlLongDiv in C
  491 ** Contributed by:
  492 ** Michael A. Gauland   gaulandm@mdhost.cse.tek.com  
  493 **************************************************************************/
  494 DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y)
  495 {
  496     DPUNS result = { 0, 0 };
  497     DPUNS addend;
  498     
  499     addend.lo = y;
  500     addend.hi = 0; /* No sign extension--arguments are unsigned */
  501     
  502     while (x != 0) 
  503     {
  504         if ( x & 1) 
  505         {
  506             result = m64Add(result, addend);
  507         }
  508         x >>= 1;
  509         addend = m64ASL(addend);
  510     }
  511     return result;
  512 }
  513 
  514 
  515 /**************************************************************************
  516                         f i c l L o n g D i v
  517 ** Portable versions of ficlLongMul and ficlLongDiv in C
  518 ** Contributed by:
  519 ** Michael A. Gauland   gaulandm@mdhost.cse.tek.com  
  520 **************************************************************************/
  521 UNSQR ficlLongDiv(DPUNS q, FICL_UNS y)
  522 {
  523     UNSQR result;
  524     DPUNS quotient;
  525     DPUNS subtrahend;
  526     DPUNS mask;
  527 
  528     quotient.lo = 0;
  529     quotient.hi = 0;
  530     
  531     subtrahend.lo = y;
  532     subtrahend.hi = 0;
  533     
  534     mask.lo = 1;
  535     mask.hi = 0;
  536     
  537     while ((m64Compare(subtrahend, q) < 0) &&
  538            (subtrahend.hi & CELL_HI_BIT) == 0)
  539     {
  540         mask = m64ASL(mask);
  541         subtrahend = m64ASL(subtrahend);
  542     }
  543     
  544     while (mask.lo != 0 || mask.hi != 0) 
  545     {
  546         if (m64Compare(subtrahend, q) <= 0) 
  547         {
  548             q = m64Sub( q, subtrahend);
  549             quotient = m64Or(quotient, mask);
  550         }
  551         mask = m64ASR(mask);
  552         subtrahend = m64ASR(subtrahend);
  553     }
  554     
  555     result.quot = quotient.lo;
  556     result.rem = q.lo;
  557     return result;
  558 }
  559 
  560 #endif
  561 

Cache object: 5d464dcc6abce5d2d7932ccde9f7d1e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.