1 /*******************************************************************
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
8 ** $Id: math64.c,v 1.9 2001/12/05 07:21:34 jsadler Exp $
9 *******************************************************************/
11 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
12 ** All rights reserved.
14 ** Get the latest Ficl release at http://ficl.sourceforge.net
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.
21 ** L I C E N S E and D I S C L A I M E R
23 ** Redistribution and use in source and binary forms, with or without
24 ** modification, are permitted provided that the following conditions
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.
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
50 /**************************************************************************
52 ** Returns the absolute value of an DPINT
53 **************************************************************************/
63 /**************************************************************************
64 m 6 4 F l o o r e d D i v I
66 ** FROM THE FORTH ANS...
67 ** Floored division is integer division in which the remainder carries
68 ** the sign of the divisor or is zero, and the quotient is rounded to
69 ** its arithmetic floor. Symmetric division is integer division in which
70 ** the remainder carries the sign of the dividend or is zero and the
71 ** quotient is the mathematical quotient rounded towards zero or
72 ** truncated. Examples of each are shown in tables 3.3 and 3.4.
74 ** Table 3.3 - Floored Division Example
75 ** Dividend Divisor Remainder Quotient
76 ** -------- ------- --------- --------
83 ** Table 3.4 - Symmetric Division Example
84 ** Dividend Divisor Remainder Quotient
85 ** -------- ------- --------- --------
90 **************************************************************************/
91 INTQR
m64FlooredDivI(DPINT num
, FICL_INT den
)
98 if (m64IsNegative(num
))
100 num
= m64Negate(num
);
101 signQuot
= -signQuot
;
108 signQuot
= -signQuot
;
111 uqr
= ficlLongDiv(m64CastIU(num
), (FICL_UNS
)den
);
112 qr
= m64CastQRUI(uqr
);
119 qr
.rem
= den
- qr
.rem
;
130 /**************************************************************************
131 m 6 4 I s N e g a t i v e
132 ** Returns TRUE if the specified DPINT has its sign bit set.
133 **************************************************************************/
134 int m64IsNegative(DPINT x
)
140 /**************************************************************************
142 ** Mixed precision multiply and accumulate primitive for number building.
143 ** Multiplies DPUNS u by FICL_UNS mul and adds FICL_UNS add. Mul is typically
144 ** the numeric base, and add represents a digit to be appended to the
146 ** Returns the result of the operation
147 **************************************************************************/
148 DPUNS
m64Mac(DPUNS u
, FICL_UNS mul
, FICL_UNS add
)
150 DPUNS resultLo
= ficlLongMul(u
.lo
, mul
);
151 DPUNS resultHi
= ficlLongMul(u
.hi
, mul
);
152 resultLo
.hi
+= resultHi
.lo
;
153 resultHi
.lo
= resultLo
.lo
+ add
;
155 if (resultHi
.lo
< resultLo
.lo
)
158 resultLo
.lo
= resultHi
.lo
;
164 /**************************************************************************
166 ** Multiplies a pair of FICL_INTs and returns an DPINT result.
167 **************************************************************************/
168 DPINT
m64MulI(FICL_INT x
, FICL_INT y
)
185 prod
= ficlLongMul(x
, y
);
187 return m64CastUI(prod
);
189 return m64Negate(m64CastUI(prod
));
193 /**************************************************************************
195 ** Negates an DPINT by complementing and incrementing.
196 **************************************************************************/
197 DPINT
m64Negate(DPINT x
)
209 /**************************************************************************
211 ** Push an DPINT onto the specified stack in the order required
212 ** by ANS Forth (most significant cell on top)
213 ** These should probably be macros...
214 **************************************************************************/
215 void i64Push(FICL_STACK
*pStack
, DPINT i64
)
217 stackPushINT(pStack
, i64
.lo
);
218 stackPushINT(pStack
, i64
.hi
);
222 void u64Push(FICL_STACK
*pStack
, DPUNS u64
)
224 stackPushINT(pStack
, u64
.lo
);
225 stackPushINT(pStack
, u64
.hi
);
230 /**************************************************************************
232 ** Pops an DPINT off the stack in the order required by ANS Forth
233 ** (most significant cell on top)
234 ** These should probably be macros...
235 **************************************************************************/
236 DPINT
i64Pop(FICL_STACK
*pStack
)
239 ret
.hi
= stackPopINT(pStack
);
240 ret
.lo
= stackPopINT(pStack
);
244 DPUNS
u64Pop(FICL_STACK
*pStack
)
247 ret
.hi
= stackPopINT(pStack
);
248 ret
.lo
= stackPopINT(pStack
);
253 /**************************************************************************
254 m 6 4 S y m m e t r i c D i v
255 ** Divide an DPINT by a FICL_INT and return a FICL_INT quotient and a
256 ** FICL_INT remainder. The absolute values of quotient and remainder are not
257 ** affected by the signs of the numerator and denominator (the operation
258 ** is symmetric on the number line)
259 **************************************************************************/
260 INTQR
m64SymmetricDivI(DPINT num
, FICL_INT den
)
267 if (m64IsNegative(num
))
269 num
= m64Negate(num
);
271 signQuot
= -signQuot
;
277 signQuot
= -signQuot
;
280 uqr
= ficlLongDiv(m64CastIU(num
), (FICL_UNS
)den
);
281 qr
= m64CastQRUI(uqr
);
292 /**************************************************************************
294 ** Divides a DPUNS by base (an UNS16) and returns an UNS16 remainder.
295 ** Writes the quotient back to the original DPUNS as a side effect.
296 ** This operation is typically used to convert an DPUNS to a text string
297 ** in any base. See words.c:numberSignS, for example.
298 ** Mechanics: performs 4 ficlLongDivs, each of which produces 16 bits
299 ** of the quotient. C does not provide a way to divide an FICL_UNS by an
300 ** UNS16 and get an FICL_UNS quotient (ldiv is closest, but it's signed,
301 ** unfortunately), so I've used ficlLongDiv.
302 **************************************************************************/
303 #if (BITS_PER_CELL == 32)
305 #define UMOD_SHIFT 16
306 #define UMOD_MASK 0x0000ffff
308 #elif (BITS_PER_CELL == 64)
310 #define UMOD_SHIFT 32
311 #define UMOD_MASK 0x00000000ffffffff
315 UNS16
m64UMod(DPUNS
*pUD
, UNS16 base
)
321 result
.hi
= result
.lo
= 0;
324 ud
.lo
= pUD
->hi
>> UMOD_SHIFT
;
325 qr
= ficlLongDiv(ud
, (FICL_UNS
)base
);
326 result
.hi
= qr
.quot
<< UMOD_SHIFT
;
328 ud
.lo
= (qr
.rem
<< UMOD_SHIFT
) | (pUD
->hi
& UMOD_MASK
);
329 qr
= ficlLongDiv(ud
, (FICL_UNS
)base
);
330 result
.hi
|= qr
.quot
& UMOD_MASK
;
332 ud
.lo
= (qr
.rem
<< UMOD_SHIFT
) | (pUD
->lo
>> UMOD_SHIFT
);
333 qr
= ficlLongDiv(ud
, (FICL_UNS
)base
);
334 result
.lo
= qr
.quot
<< UMOD_SHIFT
;
336 ud
.lo
= (qr
.rem
<< UMOD_SHIFT
) | (pUD
->lo
& UMOD_MASK
);
337 qr
= ficlLongDiv(ud
, (FICL_UNS
)base
);
338 result
.lo
|= qr
.quot
& UMOD_MASK
;
342 return (UNS16
)(qr
.rem
);
346 /**************************************************************************
348 ** Michael A. Gauland gaulandm@mdhost.cse.tek.com
349 **************************************************************************/
350 #if PORTABLE_LONGMULDIV != 0
351 /**************************************************************************
354 **************************************************************************/
355 DPUNS
m64Add(DPUNS x
, DPUNS y
)
360 result
.hi
= x
.hi
+ y
.hi
;
361 result
.lo
= x
.lo
+ y
.lo
;
364 carry
= ((x
.lo
| y
.lo
) & CELL_HI_BIT
) && !(result
.lo
& CELL_HI_BIT
);
365 carry
|= ((x
.lo
& y
.lo
) & CELL_HI_BIT
);
376 /**************************************************************************
379 **************************************************************************/
380 DPUNS
m64Sub(DPUNS x
, DPUNS y
)
384 result
.hi
= x
.hi
- y
.hi
;
385 result
.lo
= x
.lo
- y
.lo
;
396 /**************************************************************************
399 **************************************************************************/
400 DPUNS
m64ASL( DPUNS x
)
404 result
.hi
= x
.hi
<< 1;
405 if (x
.lo
& CELL_HI_BIT
)
410 result
.lo
= x
.lo
<< 1;
416 /**************************************************************************
418 ** 64 bit right shift (unsigned - no sign extend)
419 **************************************************************************/
420 DPUNS
m64ASR( DPUNS x
)
424 result
.lo
= x
.lo
>> 1;
427 result
.lo
|= CELL_HI_BIT
;
430 result
.hi
= x
.hi
>> 1;
435 /**************************************************************************
438 **************************************************************************/
439 DPUNS
m64Or( DPUNS x
, DPUNS y
)
443 result
.hi
= x
.hi
| y
.hi
;
444 result
.lo
= x
.lo
| y
.lo
;
450 /**************************************************************************
452 ** Return -1 if x < y; 0 if x==y, and 1 if x > y.
453 **************************************************************************/
454 int m64Compare(DPUNS x
, DPUNS y
)
462 else if (x
.hi
< y
.hi
)
468 /* High parts are equal */
473 else if (x
.lo
< y
.lo
)
487 /**************************************************************************
488 f i c l L o n g M u l
489 ** Portable versions of ficlLongMul and ficlLongDiv in C
491 ** Michael A. Gauland gaulandm@mdhost.cse.tek.com
492 **************************************************************************/
493 DPUNS
ficlLongMul(FICL_UNS x
, FICL_UNS y
)
495 DPUNS result
= { 0, 0 };
499 addend
.hi
= 0; /* No sign extension--arguments are unsigned */
505 result
= m64Add(result
, addend
);
508 addend
= m64ASL(addend
);
514 /**************************************************************************
515 f i c l L o n g D i v
516 ** Portable versions of ficlLongMul and ficlLongDiv in C
518 ** Michael A. Gauland gaulandm@mdhost.cse.tek.com
519 **************************************************************************/
520 UNSQR
ficlLongDiv(DPUNS q
, FICL_UNS y
)
536 while ((m64Compare(subtrahend
, q
) < 0) &&
537 (subtrahend
.hi
& CELL_HI_BIT
) == 0)
540 subtrahend
= m64ASL(subtrahend
);
543 while (mask
.lo
!= 0 || mask
.hi
!= 0)
545 if (m64Compare(subtrahend
, q
) <= 0)
547 q
= m64Sub( q
, subtrahend
);
548 quotient
= m64Or(quotient
, mask
);
551 subtrahend
= m64ASR(subtrahend
);
554 result
.quot
= quotient
.lo
;