1*a1bf3f78SToomas Soome /* 2*a1bf3f78SToomas Soome * m a t h 6 4 . c 3*a1bf3f78SToomas Soome * Forth Inspired Command Language - 64 bit math support routines 4*a1bf3f78SToomas Soome * Authors: Michael A. Gauland (gaulandm@mdhost.cse.tek.com) 5*a1bf3f78SToomas Soome * Larry Hastings (larry@hastings.org) 6*a1bf3f78SToomas Soome * John Sadler (john_sadler@alum.mit.edu) 7*a1bf3f78SToomas Soome * Created: 25 January 1998 8*a1bf3f78SToomas Soome * Rev 2.03: Support for 128 bit DP math. This file really ouught to 9*a1bf3f78SToomas Soome * be renamed! 10*a1bf3f78SToomas Soome * $Id: double.c,v 1.2 2010/09/12 15:18:07 asau Exp $ 11*a1bf3f78SToomas Soome */ 12*a1bf3f78SToomas Soome /* 13*a1bf3f78SToomas Soome * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) 14*a1bf3f78SToomas Soome * All rights reserved. 15*a1bf3f78SToomas Soome * 16*a1bf3f78SToomas Soome * Get the latest Ficl release at http://ficl.sourceforge.net 17*a1bf3f78SToomas Soome * 18*a1bf3f78SToomas Soome * I am interested in hearing from anyone who uses Ficl. If you have 19*a1bf3f78SToomas Soome * a problem, a success story, a defect, an enhancement request, or 20*a1bf3f78SToomas Soome * if you would like to contribute to the Ficl release, please 21*a1bf3f78SToomas Soome * contact me by email at the address above. 22*a1bf3f78SToomas Soome * 23*a1bf3f78SToomas Soome * L I C E N S E and D I S C L A I M E R 24*a1bf3f78SToomas Soome * 25*a1bf3f78SToomas Soome * Redistribution and use in source and binary forms, with or without 26*a1bf3f78SToomas Soome * modification, are permitted provided that the following conditions 27*a1bf3f78SToomas Soome * are met: 28*a1bf3f78SToomas Soome * 1. Redistributions of source code must retain the above copyright 29*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer. 30*a1bf3f78SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 31*a1bf3f78SToomas Soome * notice, this list of conditions and the following disclaimer in the 32*a1bf3f78SToomas Soome * documentation and/or other materials provided with the distribution. 33*a1bf3f78SToomas Soome * 34*a1bf3f78SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 35*a1bf3f78SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36*a1bf3f78SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37*a1bf3f78SToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 38*a1bf3f78SToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39*a1bf3f78SToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40*a1bf3f78SToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41*a1bf3f78SToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42*a1bf3f78SToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43*a1bf3f78SToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44*a1bf3f78SToomas Soome * SUCH DAMAGE. 45*a1bf3f78SToomas Soome */ 46*a1bf3f78SToomas Soome 47*a1bf3f78SToomas Soome #include "ficl.h" 48*a1bf3f78SToomas Soome 49*a1bf3f78SToomas Soome #if FICL_PLATFORM_HAS_2INTEGER 50*a1bf3f78SToomas Soome ficl2UnsignedQR 51*a1bf3f78SToomas Soome ficl2UnsignedDivide(ficl2Unsigned q, ficlUnsigned y) 52*a1bf3f78SToomas Soome { 53*a1bf3f78SToomas Soome ficl2UnsignedQR result; 54*a1bf3f78SToomas Soome 55*a1bf3f78SToomas Soome result.quotient = q / y; 56*a1bf3f78SToomas Soome /* 57*a1bf3f78SToomas Soome * Once we have the quotient, it's cheaper to calculate the 58*a1bf3f78SToomas Soome * remainder this way than with % (mod). --lch 59*a1bf3f78SToomas Soome */ 60*a1bf3f78SToomas Soome result.remainder = (ficlInteger)(q - (result.quotient * y)); 61*a1bf3f78SToomas Soome 62*a1bf3f78SToomas Soome return (result); 63*a1bf3f78SToomas Soome } 64*a1bf3f78SToomas Soome 65*a1bf3f78SToomas Soome #else /* FICL_PLATFORM_HAS_2INTEGER */ 66*a1bf3f78SToomas Soome 67*a1bf3f78SToomas Soome #define FICL_CELL_HIGH_BIT ((uintmax_t)1 << (FICL_BITS_PER_CELL-1)) 68*a1bf3f78SToomas Soome #define UMOD_SHIFT (FICL_BITS_PER_CELL / 2) 69*a1bf3f78SToomas Soome #define UMOD_MASK ((1L << (FICL_BITS_PER_CELL / 2)) - 1) 70*a1bf3f78SToomas Soome 71*a1bf3f78SToomas Soome /* 72*a1bf3f78SToomas Soome * ficl2IntegerIsNegative 73*a1bf3f78SToomas Soome * Returns TRUE if the specified ficl2Unsigned has its sign bit set. 74*a1bf3f78SToomas Soome */ 75*a1bf3f78SToomas Soome int 76*a1bf3f78SToomas Soome ficl2IntegerIsNegative(ficl2Integer x) 77*a1bf3f78SToomas Soome { 78*a1bf3f78SToomas Soome return (x.high < 0); 79*a1bf3f78SToomas Soome } 80*a1bf3f78SToomas Soome 81*a1bf3f78SToomas Soome /* 82*a1bf3f78SToomas Soome * ficl2IntegerNegate 83*a1bf3f78SToomas Soome * Negates an ficl2Unsigned by complementing and incrementing. 84*a1bf3f78SToomas Soome */ 85*a1bf3f78SToomas Soome ficl2Integer 86*a1bf3f78SToomas Soome ficl2IntegerNegate(ficl2Integer x) 87*a1bf3f78SToomas Soome { 88*a1bf3f78SToomas Soome x.high = ~x.high; 89*a1bf3f78SToomas Soome x.low = ~x.low; 90*a1bf3f78SToomas Soome x.low ++; 91*a1bf3f78SToomas Soome if (x.low == 0) 92*a1bf3f78SToomas Soome x.high++; 93*a1bf3f78SToomas Soome 94*a1bf3f78SToomas Soome return (x); 95*a1bf3f78SToomas Soome } 96*a1bf3f78SToomas Soome 97*a1bf3f78SToomas Soome /* 98*a1bf3f78SToomas Soome * ficl2UnsignedMultiplyAccumulate 99*a1bf3f78SToomas Soome * Mixed precision multiply and accumulate primitive for number building. 100*a1bf3f78SToomas Soome * Multiplies ficl2Unsigned u by ficlUnsigned mul and adds ficlUnsigned add. 101*a1bf3f78SToomas Soome * Mul is typically the numeric base, and add represents a digit to be 102*a1bf3f78SToomas Soome * appended to the growing number. 103*a1bf3f78SToomas Soome * Returns the result of the operation 104*a1bf3f78SToomas Soome */ 105*a1bf3f78SToomas Soome ficl2Unsigned 106*a1bf3f78SToomas Soome ficl2UnsignedMultiplyAccumulate(ficl2Unsigned u, ficlUnsigned mul, 107*a1bf3f78SToomas Soome ficlUnsigned add) 108*a1bf3f78SToomas Soome { 109*a1bf3f78SToomas Soome ficl2Unsigned resultLo = ficl2UnsignedMultiply(u.low, mul); 110*a1bf3f78SToomas Soome ficl2Unsigned resultHi = ficl2UnsignedMultiply(u.high, mul); 111*a1bf3f78SToomas Soome resultLo.high += resultHi.low; 112*a1bf3f78SToomas Soome resultHi.low = resultLo.low + add; 113*a1bf3f78SToomas Soome 114*a1bf3f78SToomas Soome if (resultHi.low < resultLo.low) 115*a1bf3f78SToomas Soome resultLo.high++; 116*a1bf3f78SToomas Soome 117*a1bf3f78SToomas Soome resultLo.low = resultHi.low; 118*a1bf3f78SToomas Soome 119*a1bf3f78SToomas Soome return (resultLo); 120*a1bf3f78SToomas Soome } 121*a1bf3f78SToomas Soome 122*a1bf3f78SToomas Soome /* 123*a1bf3f78SToomas Soome * ficl2IntegerMultiply 124*a1bf3f78SToomas Soome * Multiplies a pair of ficlIntegers and returns an ficl2Integer result. 125*a1bf3f78SToomas Soome */ 126*a1bf3f78SToomas Soome ficl2Integer 127*a1bf3f78SToomas Soome ficl2IntegerMultiply(ficlInteger x, ficlInteger y) 128*a1bf3f78SToomas Soome { 129*a1bf3f78SToomas Soome ficl2Unsigned prod; 130*a1bf3f78SToomas Soome ficl2Integer result; 131*a1bf3f78SToomas Soome int sign = 1; 132*a1bf3f78SToomas Soome 133*a1bf3f78SToomas Soome if (x < 0) { 134*a1bf3f78SToomas Soome sign = -sign; 135*a1bf3f78SToomas Soome x = -x; 136*a1bf3f78SToomas Soome } 137*a1bf3f78SToomas Soome 138*a1bf3f78SToomas Soome if (y < 0) { 139*a1bf3f78SToomas Soome sign = -sign; 140*a1bf3f78SToomas Soome y = -y; 141*a1bf3f78SToomas Soome } 142*a1bf3f78SToomas Soome 143*a1bf3f78SToomas Soome prod = ficl2UnsignedMultiply(x, y); 144*a1bf3f78SToomas Soome FICL_2INTEGER_SET(FICL_2UNSIGNED_GET_HIGH(prod), 145*a1bf3f78SToomas Soome FICL_2UNSIGNED_GET_LOW(prod), result); 146*a1bf3f78SToomas Soome if (sign > 0) 147*a1bf3f78SToomas Soome return (result); 148*a1bf3f78SToomas Soome else 149*a1bf3f78SToomas Soome return (ficl2IntegerNegate(result)); 150*a1bf3f78SToomas Soome } 151*a1bf3f78SToomas Soome 152*a1bf3f78SToomas Soome ficl2Integer 153*a1bf3f78SToomas Soome ficl2IntegerDecrement(ficl2Integer x) 154*a1bf3f78SToomas Soome { 155*a1bf3f78SToomas Soome if (x.low == INTMAX_MIN) 156*a1bf3f78SToomas Soome x.high--; 157*a1bf3f78SToomas Soome x.low--; 158*a1bf3f78SToomas Soome 159*a1bf3f78SToomas Soome return (x); 160*a1bf3f78SToomas Soome } 161*a1bf3f78SToomas Soome 162*a1bf3f78SToomas Soome ficl2Unsigned 163*a1bf3f78SToomas Soome ficl2UnsignedAdd(ficl2Unsigned x, ficl2Unsigned y) 164*a1bf3f78SToomas Soome { 165*a1bf3f78SToomas Soome ficl2Unsigned result; 166*a1bf3f78SToomas Soome 167*a1bf3f78SToomas Soome result.high = x.high + y.high; 168*a1bf3f78SToomas Soome result.low = x.low + y.low; 169*a1bf3f78SToomas Soome 170*a1bf3f78SToomas Soome if (result.low < y.low) 171*a1bf3f78SToomas Soome result.high++; 172*a1bf3f78SToomas Soome 173*a1bf3f78SToomas Soome return (result); 174*a1bf3f78SToomas Soome } 175*a1bf3f78SToomas Soome 176*a1bf3f78SToomas Soome /* 177*a1bf3f78SToomas Soome * ficl2UnsignedMultiply 178*a1bf3f78SToomas Soome * Contributed by: 179*a1bf3f78SToomas Soome * Michael A. Gauland gaulandm@mdhost.cse.tek.com 180*a1bf3f78SToomas Soome */ 181*a1bf3f78SToomas Soome ficl2Unsigned 182*a1bf3f78SToomas Soome ficl2UnsignedMultiply(ficlUnsigned x, ficlUnsigned y) 183*a1bf3f78SToomas Soome { 184*a1bf3f78SToomas Soome ficl2Unsigned result = { 0, 0 }; 185*a1bf3f78SToomas Soome ficl2Unsigned addend; 186*a1bf3f78SToomas Soome 187*a1bf3f78SToomas Soome addend.low = y; 188*a1bf3f78SToomas Soome addend.high = 0; /* No sign extension--arguments are unsigned */ 189*a1bf3f78SToomas Soome 190*a1bf3f78SToomas Soome while (x != 0) { 191*a1bf3f78SToomas Soome if (x & 1) { 192*a1bf3f78SToomas Soome result = ficl2UnsignedAdd(result, addend); 193*a1bf3f78SToomas Soome } 194*a1bf3f78SToomas Soome x >>= 1; 195*a1bf3f78SToomas Soome addend = ficl2UnsignedArithmeticShiftLeft(addend); 196*a1bf3f78SToomas Soome } 197*a1bf3f78SToomas Soome return (result); 198*a1bf3f78SToomas Soome } 199*a1bf3f78SToomas Soome 200*a1bf3f78SToomas Soome /* 201*a1bf3f78SToomas Soome * ficl2UnsignedSubtract 202*a1bf3f78SToomas Soome */ 203*a1bf3f78SToomas Soome ficl2Unsigned 204*a1bf3f78SToomas Soome ficl2UnsignedSubtract(ficl2Unsigned x, ficl2Unsigned y) 205*a1bf3f78SToomas Soome { 206*a1bf3f78SToomas Soome ficl2Unsigned result; 207*a1bf3f78SToomas Soome 208*a1bf3f78SToomas Soome result.high = x.high - y.high; 209*a1bf3f78SToomas Soome result.low = x.low - y.low; 210*a1bf3f78SToomas Soome 211*a1bf3f78SToomas Soome if (x.low < y.low) { 212*a1bf3f78SToomas Soome result.high--; 213*a1bf3f78SToomas Soome } 214*a1bf3f78SToomas Soome 215*a1bf3f78SToomas Soome return (result); 216*a1bf3f78SToomas Soome } 217*a1bf3f78SToomas Soome 218*a1bf3f78SToomas Soome /* 219*a1bf3f78SToomas Soome * ficl2UnsignedArithmeticShiftLeft 220*a1bf3f78SToomas Soome * 64 bit left shift 221*a1bf3f78SToomas Soome */ 222*a1bf3f78SToomas Soome ficl2Unsigned 223*a1bf3f78SToomas Soome ficl2UnsignedArithmeticShiftLeft(ficl2Unsigned x) 224*a1bf3f78SToomas Soome { 225*a1bf3f78SToomas Soome ficl2Unsigned result; 226*a1bf3f78SToomas Soome 227*a1bf3f78SToomas Soome result.high = x.high << 1; 228*a1bf3f78SToomas Soome if (x.low & FICL_CELL_HIGH_BIT) { 229*a1bf3f78SToomas Soome result.high++; 230*a1bf3f78SToomas Soome } 231*a1bf3f78SToomas Soome 232*a1bf3f78SToomas Soome result.low = x.low << 1; 233*a1bf3f78SToomas Soome 234*a1bf3f78SToomas Soome return (result); 235*a1bf3f78SToomas Soome } 236*a1bf3f78SToomas Soome 237*a1bf3f78SToomas Soome /* 238*a1bf3f78SToomas Soome * ficl2UnsignedArithmeticShiftRight 239*a1bf3f78SToomas Soome * 64 bit right shift (unsigned - no sign extend) 240*a1bf3f78SToomas Soome */ 241*a1bf3f78SToomas Soome ficl2Unsigned 242*a1bf3f78SToomas Soome ficl2UnsignedArithmeticShiftRight(ficl2Unsigned x) 243*a1bf3f78SToomas Soome { 244*a1bf3f78SToomas Soome ficl2Unsigned result; 245*a1bf3f78SToomas Soome 246*a1bf3f78SToomas Soome result.low = x.low >> 1; 247*a1bf3f78SToomas Soome if (x.high & 1) { 248*a1bf3f78SToomas Soome result.low |= FICL_CELL_HIGH_BIT; 249*a1bf3f78SToomas Soome } 250*a1bf3f78SToomas Soome 251*a1bf3f78SToomas Soome result.high = x.high >> 1; 252*a1bf3f78SToomas Soome return (result); 253*a1bf3f78SToomas Soome } 254*a1bf3f78SToomas Soome 255*a1bf3f78SToomas Soome /* 256*a1bf3f78SToomas Soome * ficl2UnsignedOr 257*a1bf3f78SToomas Soome * 64 bit bitwise OR 258*a1bf3f78SToomas Soome */ 259*a1bf3f78SToomas Soome ficl2Unsigned 260*a1bf3f78SToomas Soome ficl2UnsignedOr(ficl2Unsigned x, ficl2Unsigned y) 261*a1bf3f78SToomas Soome { 262*a1bf3f78SToomas Soome ficl2Unsigned result; 263*a1bf3f78SToomas Soome 264*a1bf3f78SToomas Soome result.high = x.high | y.high; 265*a1bf3f78SToomas Soome result.low = x.low | y.low; 266*a1bf3f78SToomas Soome 267*a1bf3f78SToomas Soome return (result); 268*a1bf3f78SToomas Soome } 269*a1bf3f78SToomas Soome 270*a1bf3f78SToomas Soome /* 271*a1bf3f78SToomas Soome * ficl2UnsignedCompare 272*a1bf3f78SToomas Soome * Return -1 if x < y; 0 if x==y, and 1 if x > y. 273*a1bf3f78SToomas Soome */ 274*a1bf3f78SToomas Soome int 275*a1bf3f78SToomas Soome ficl2UnsignedCompare(ficl2Unsigned x, ficl2Unsigned y) 276*a1bf3f78SToomas Soome { 277*a1bf3f78SToomas Soome if (x.high > y.high) 278*a1bf3f78SToomas Soome return (1); 279*a1bf3f78SToomas Soome if (x.high < y.high) 280*a1bf3f78SToomas Soome return (-1); 281*a1bf3f78SToomas Soome 282*a1bf3f78SToomas Soome /* High parts are equal */ 283*a1bf3f78SToomas Soome 284*a1bf3f78SToomas Soome if (x.low > y.low) 285*a1bf3f78SToomas Soome return (1); 286*a1bf3f78SToomas Soome else if (x.low < y.low) 287*a1bf3f78SToomas Soome return (-1); 288*a1bf3f78SToomas Soome 289*a1bf3f78SToomas Soome return (0); 290*a1bf3f78SToomas Soome } 291*a1bf3f78SToomas Soome 292*a1bf3f78SToomas Soome /* 293*a1bf3f78SToomas Soome * ficl2UnsignedDivide 294*a1bf3f78SToomas Soome * Portable versions of ficl2Multiply and ficl2Divide in C 295*a1bf3f78SToomas Soome * Contributed by: 296*a1bf3f78SToomas Soome * Michael A. Gauland gaulandm@mdhost.cse.tek.com 297*a1bf3f78SToomas Soome */ 298*a1bf3f78SToomas Soome ficl2UnsignedQR 299*a1bf3f78SToomas Soome ficl2UnsignedDivide(ficl2Unsigned q, ficlUnsigned y) 300*a1bf3f78SToomas Soome { 301*a1bf3f78SToomas Soome ficl2UnsignedQR result; 302*a1bf3f78SToomas Soome ficl2Unsigned quotient; 303*a1bf3f78SToomas Soome ficl2Unsigned subtrahend; 304*a1bf3f78SToomas Soome ficl2Unsigned mask; 305*a1bf3f78SToomas Soome 306*a1bf3f78SToomas Soome quotient.low = 0; 307*a1bf3f78SToomas Soome quotient.high = 0; 308*a1bf3f78SToomas Soome 309*a1bf3f78SToomas Soome subtrahend.low = y; 310*a1bf3f78SToomas Soome subtrahend.high = 0; 311*a1bf3f78SToomas Soome 312*a1bf3f78SToomas Soome mask.low = 1; 313*a1bf3f78SToomas Soome mask.high = 0; 314*a1bf3f78SToomas Soome 315*a1bf3f78SToomas Soome while ((ficl2UnsignedCompare(subtrahend, q) < 0) && 316*a1bf3f78SToomas Soome (subtrahend.high & FICL_CELL_HIGH_BIT) == 0) { 317*a1bf3f78SToomas Soome mask = ficl2UnsignedArithmeticShiftLeft(mask); 318*a1bf3f78SToomas Soome subtrahend = ficl2UnsignedArithmeticShiftLeft(subtrahend); 319*a1bf3f78SToomas Soome } 320*a1bf3f78SToomas Soome 321*a1bf3f78SToomas Soome while (mask.low != 0 || mask.high != 0) { 322*a1bf3f78SToomas Soome if (ficl2UnsignedCompare(subtrahend, q) <= 0) { 323*a1bf3f78SToomas Soome q = ficl2UnsignedSubtract(q, subtrahend); 324*a1bf3f78SToomas Soome quotient = ficl2UnsignedOr(quotient, mask); 325*a1bf3f78SToomas Soome } 326*a1bf3f78SToomas Soome mask = ficl2UnsignedArithmeticShiftRight(mask); 327*a1bf3f78SToomas Soome subtrahend = ficl2UnsignedArithmeticShiftRight(subtrahend); 328*a1bf3f78SToomas Soome } 329*a1bf3f78SToomas Soome 330*a1bf3f78SToomas Soome result.quotient = quotient; 331*a1bf3f78SToomas Soome result.remainder = q.low; 332*a1bf3f78SToomas Soome return (result); 333*a1bf3f78SToomas Soome } 334*a1bf3f78SToomas Soome #endif /* !FICL_PLATFORM_HAS_2INTEGER */ 335*a1bf3f78SToomas Soome 336*a1bf3f78SToomas Soome /* 337*a1bf3f78SToomas Soome * ficl2IntegerDivideFloored 338*a1bf3f78SToomas Soome * 339*a1bf3f78SToomas Soome * FROM THE FORTH ANS... 340*a1bf3f78SToomas Soome * Floored division is integer division in which the remainder carries 341*a1bf3f78SToomas Soome * the sign of the divisor or is zero, and the quotient is rounded to 342*a1bf3f78SToomas Soome * its arithmetic floor. Symmetric division is integer division in which 343*a1bf3f78SToomas Soome * the remainder carries the sign of the dividend or is zero and the 344*a1bf3f78SToomas Soome * quotient is the mathematical quotient rounded towards zero or 345*a1bf3f78SToomas Soome * truncated. Examples of each are shown in tables 3.3 and 3.4. 346*a1bf3f78SToomas Soome * 347*a1bf3f78SToomas Soome * Table 3.3 - Floored Division Example 348*a1bf3f78SToomas Soome * Dividend Divisor Remainder Quotient 349*a1bf3f78SToomas Soome * -------- ------- --------- -------- 350*a1bf3f78SToomas Soome * 10 7 3 1 351*a1bf3f78SToomas Soome * -10 7 4 -2 352*a1bf3f78SToomas Soome * 10 -7 -4 -2 353*a1bf3f78SToomas Soome * -10 -7 -3 1 354*a1bf3f78SToomas Soome * 355*a1bf3f78SToomas Soome * 356*a1bf3f78SToomas Soome * Table 3.4 - Symmetric Division Example 357*a1bf3f78SToomas Soome * Dividend Divisor Remainder Quotient 358*a1bf3f78SToomas Soome * -------- ------- --------- -------- 359*a1bf3f78SToomas Soome * 10 7 3 1 360*a1bf3f78SToomas Soome * -10 7 -3 -1 361*a1bf3f78SToomas Soome * 10 -7 3 -1 362*a1bf3f78SToomas Soome * -10 -7 -3 1 363*a1bf3f78SToomas Soome */ 364*a1bf3f78SToomas Soome ficl2IntegerQR 365*a1bf3f78SToomas Soome ficl2IntegerDivideFloored(ficl2Integer num, ficlInteger den) 366*a1bf3f78SToomas Soome { 367*a1bf3f78SToomas Soome ficl2IntegerQR qr; 368*a1bf3f78SToomas Soome ficl2UnsignedQR uqr; 369*a1bf3f78SToomas Soome ficl2Unsigned u; 370*a1bf3f78SToomas Soome int signRem = 1; 371*a1bf3f78SToomas Soome int signQuot = 1; 372*a1bf3f78SToomas Soome 373*a1bf3f78SToomas Soome if (ficl2IntegerIsNegative(num)) { 374*a1bf3f78SToomas Soome num = ficl2IntegerNegate(num); 375*a1bf3f78SToomas Soome signQuot = -signQuot; 376*a1bf3f78SToomas Soome } 377*a1bf3f78SToomas Soome 378*a1bf3f78SToomas Soome if (den < 0) { 379*a1bf3f78SToomas Soome den = -den; 380*a1bf3f78SToomas Soome signRem = -signRem; 381*a1bf3f78SToomas Soome signQuot = -signQuot; 382*a1bf3f78SToomas Soome } 383*a1bf3f78SToomas Soome 384*a1bf3f78SToomas Soome FICL_2UNSIGNED_SET(FICL_2UNSIGNED_GET_HIGH(num), 385*a1bf3f78SToomas Soome FICL_2UNSIGNED_GET_LOW(num), u); 386*a1bf3f78SToomas Soome uqr = ficl2UnsignedDivide(u, (ficlUnsigned)den); 387*a1bf3f78SToomas Soome qr = FICL_2UNSIGNEDQR_TO_2INTEGERQR(uqr); 388*a1bf3f78SToomas Soome if (signQuot < 0) { 389*a1bf3f78SToomas Soome qr.quotient = ficl2IntegerNegate(qr.quotient); 390*a1bf3f78SToomas Soome if (qr.remainder != 0) { 391*a1bf3f78SToomas Soome qr.quotient = ficl2IntegerDecrement(qr.quotient); 392*a1bf3f78SToomas Soome qr.remainder = den - qr.remainder; 393*a1bf3f78SToomas Soome } 394*a1bf3f78SToomas Soome } 395*a1bf3f78SToomas Soome 396*a1bf3f78SToomas Soome if (signRem < 0) 397*a1bf3f78SToomas Soome qr.remainder = -qr.remainder; 398*a1bf3f78SToomas Soome 399*a1bf3f78SToomas Soome return (qr); 400*a1bf3f78SToomas Soome } 401*a1bf3f78SToomas Soome 402*a1bf3f78SToomas Soome /* 403*a1bf3f78SToomas Soome * ficl2IntegerDivideSymmetric 404*a1bf3f78SToomas Soome * Divide an ficl2Unsigned by a ficlInteger and return a ficlInteger quotient 405*a1bf3f78SToomas Soome * and a ficlInteger remainder. The absolute values of quotient and remainder 406*a1bf3f78SToomas Soome * are not affected by the signs of the numerator and denominator 407*a1bf3f78SToomas Soome * (the operation is symmetric on the number line) 408*a1bf3f78SToomas Soome */ 409*a1bf3f78SToomas Soome ficl2IntegerQR 410*a1bf3f78SToomas Soome ficl2IntegerDivideSymmetric(ficl2Integer num, ficlInteger den) 411*a1bf3f78SToomas Soome { 412*a1bf3f78SToomas Soome ficl2IntegerQR qr; 413*a1bf3f78SToomas Soome ficl2UnsignedQR uqr; 414*a1bf3f78SToomas Soome ficl2Unsigned u; 415*a1bf3f78SToomas Soome int signRem = 1; 416*a1bf3f78SToomas Soome int signQuot = 1; 417*a1bf3f78SToomas Soome 418*a1bf3f78SToomas Soome if (ficl2IntegerIsNegative(num)) { 419*a1bf3f78SToomas Soome num = ficl2IntegerNegate(num); 420*a1bf3f78SToomas Soome signRem = -signRem; 421*a1bf3f78SToomas Soome signQuot = -signQuot; 422*a1bf3f78SToomas Soome } 423*a1bf3f78SToomas Soome 424*a1bf3f78SToomas Soome if (den < 0) { 425*a1bf3f78SToomas Soome den = -den; 426*a1bf3f78SToomas Soome signQuot = -signQuot; 427*a1bf3f78SToomas Soome } 428*a1bf3f78SToomas Soome 429*a1bf3f78SToomas Soome FICL_2UNSIGNED_SET(FICL_2UNSIGNED_GET_HIGH(num), 430*a1bf3f78SToomas Soome FICL_2UNSIGNED_GET_LOW(num), u); 431*a1bf3f78SToomas Soome uqr = ficl2UnsignedDivide(u, (ficlUnsigned)den); 432*a1bf3f78SToomas Soome qr = FICL_2UNSIGNEDQR_TO_2INTEGERQR(uqr); 433*a1bf3f78SToomas Soome if (signRem < 0) 434*a1bf3f78SToomas Soome qr.remainder = -qr.remainder; 435*a1bf3f78SToomas Soome 436*a1bf3f78SToomas Soome if (signQuot < 0) 437*a1bf3f78SToomas Soome qr.quotient = ficl2IntegerNegate(qr.quotient); 438*a1bf3f78SToomas Soome 439*a1bf3f78SToomas Soome return (qr); 440*a1bf3f78SToomas Soome } 441