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
ficl2UnsignedDivide(ficl2Unsigned q,ficlUnsigned y)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
ficl2IntegerIsNegative(ficl2Integer x)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
ficl2IntegerNegate(ficl2Integer x)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
ficl2UnsignedMultiplyAccumulate(ficl2Unsigned u,ficlUnsigned mul,ficlUnsigned add)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
ficl2IntegerMultiply(ficlInteger x,ficlInteger y)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
ficl2IntegerDecrement(ficl2Integer x)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
ficl2UnsignedAdd(ficl2Unsigned x,ficl2Unsigned y)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
ficl2UnsignedMultiply(ficlUnsigned x,ficlUnsigned y)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
ficl2UnsignedSubtract(ficl2Unsigned x,ficl2Unsigned y)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
ficl2UnsignedArithmeticShiftLeft(ficl2Unsigned x)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
ficl2UnsignedArithmeticShiftRight(ficl2Unsigned x)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
ficl2UnsignedOr(ficl2Unsigned x,ficl2Unsigned y)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
ficl2UnsignedCompare(ficl2Unsigned x,ficl2Unsigned y)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
ficl2UnsignedDivide(ficl2Unsigned q,ficlUnsigned y)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
ficl2IntegerDivideFloored(ficl2Integer num,ficlInteger den)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
ficl2IntegerDivideSymmetric(ficl2Integer num,ficlInteger den)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