1 /* file: "bignums.c" */
4 * Copyright 2004-2009 by Marc Feeley and Vincent St-Amour, All Rights Reserved.
7 #include "picobit-vm.h"
9 #ifdef INFINITE_PRECISION_BIGNUMS
11 // TODO clean up all this
13 integer
make_integer (digit lo
, integer hi
) {
14 /* if(!hi && lo <= MAX_FIXNUM && lo >= MIN_FIXNUM) */
15 /* return ENCODE_FIXNUM(lo);o */
16 // TODO won't work, and the bignum functions are unaware of fixnums
17 // TODO if I uncomment, segfaults every time this is called. no ill effect is noticed without it, but kept just in case
18 return alloc_ram_cell_init (BIGNUM_FIELD0
| (hi
>> 8), hi
, lo
>> 8, lo
);
21 integer
integer_hi (integer x
) {
23 return ram_get_car (x
);
25 return rom_get_car (x
);
26 else if (x
< (MIN_FIXNUM_ENCODING
- MIN_FIXNUM
))
27 return NEG1
; /* negative fixnum */
29 return ZERO
; /* nonnegative fixnum */
32 digit
integer_lo (integer x
) {
34 return (((digit
)ram_get_field2 (x
)) << 8) + ram_get_field3 (x
);
36 return (((digit
)rom_get_field2 (x
)) << 8) + rom_get_field3 (x
);
38 return DECODE_FIXNUM(x
);
41 integer
norm (obj prefix
, integer n
) {
42 /* norm(prefix,n) returns a normalized integer whose value is the
43 integer n prefixed with the digits in prefix (a list of digits) */
45 while (prefix
!= NIL
) {
46 digit d
= integer_lo (prefix
);
49 prefix
= integer_hi (temp
);
51 if (obj_eq (n
, ZERO
)) {
52 if (d
<= MAX_FIXNUM
) {
53 n
= ENCODE_FIXNUM ((uint8
)d
);
54 continue; // TODO with cast to unsigned, will it work for negative numbers ? or is it only handled in the next branch ?
57 else if (obj_eq (n
, NEG1
)) {
58 if (d
>= (1<<digit_width
) + MIN_FIXNUM
) {
59 n
= ENCODE_FIXNUM (d
- (1<<digit_width
)); // TODO had a cast, origianlly to int8, changed to uint8 which didn't work (obviously, we use -1 here), is a cast necessary at all ?
64 integer_hi_set (temp
, n
);
71 uint8
negp (integer x
) {
72 /* negp(x) returns true iff x is negative */
76 if (obj_eq (x
, ZERO
)) return false;
77 } while (!obj_eq (x
, NEG1
));
82 int8
cmp (integer x
, integer y
) {
83 /* cmp(x,y) return -1 when x<y, 1 when x>y, and 0 when x=y */
90 if (obj_eq (x
, ZERO
) || obj_eq (x
, NEG1
)) {
92 { if (negp (y
)) result
= 1; else result
= -1; }
96 if (obj_eq (y
, ZERO
) || obj_eq (y
, NEG1
)) {
97 if (negp (x
)) result
= -1; else result
= 1;
101 xlo
= integer_lo (x
);
102 ylo
= integer_lo (y
);
106 { if (xlo
< ylo
) result
= -1; else result
= 1; }
111 uint16
integer_length (integer x
) {
112 /* integer_length(x) returns the number of bits in the binary
113 representation of the nonnegative integer x */
119 while (!obj_eq ((next
= integer_hi (x
)), ZERO
)) {
120 result
+= digit_width
;
134 integer
shr (integer x
) { // TODO have shift_right
135 /* shr(x) returns the integer x shifted one bit to the right */
141 if (obj_eq (x
, ZERO
) || obj_eq (x
, NEG1
)) {
142 result
= norm (result
, x
);
148 result
= make_integer ((d
>> 1) |
149 ((integer_lo (x
) & 1) ? (1<<(digit_width
-1)) : 0),
156 integer
negative_carry (integer carry
) {
163 integer
shl (integer x
) {
164 /* shl(x) returns the integer x shifted one bit to the left */
166 integer negc
= ZERO
; /* negative carry */
172 if (obj_eq (x
, negc
)) {
173 result
= norm (result
, x
);
180 negc
= negative_carry (d
& (1<<(digit_width
-1))); // TODO right side is constant, and sixpic has no constant folding
181 result
= make_integer ((d
<< 1) | obj_eq (temp
, NEG1
), result
);
187 integer
shift_left (integer x
, uint16 n
) { // TODO have the primitves been changed for this and right ?
188 /* shift_left(x,n) returns the integer x shifted n bits to the left */
190 if (obj_eq (x
, ZERO
))
193 while (n
& (digit_width
-1)) {
199 x
= make_integer (0, x
);
206 integer
add (integer x
, integer y
) {
207 /* add(x,y) returns the sum of the integers x and y */
209 integer negc
= ZERO
; /* negative carry */
210 obj result
= NIL
; /* nil terminated for the norm function */
215 if (obj_eq (x
, negc
)) {
216 result
= norm (result
, y
);
220 if (obj_eq (y
, negc
)) {
221 result
= norm (result
, x
);
227 dx
= dx
+ dy
; /* may wrap around */
229 if (obj_eq (negc
, ZERO
))
230 negc
= negative_carry (dx
< dy
);
232 dx
++; /* may wrap around */
233 negc
= negative_carry (dx
<= dy
);
239 result
= make_integer (dx
, result
);
245 integer
invert (integer x
) {
246 if (obj_eq (x
, ZERO
))
252 integer
sub (integer x
, integer y
) {
253 /* sub(x,y) returns the difference of the integers x and y */
254 integer negc
= NEG1
; /* negative carry */
260 if (obj_eq (x
, negc
) && (obj_eq (y
, ZERO
) || obj_eq (y
, NEG1
))) {
261 result
= norm (result
, invert (y
));
265 if (obj_eq (y
, invert (negc
))) {
266 result
= norm (result
, x
);
271 dy
= ~integer_lo (y
);
272 dx
= dx
+ dy
; /* may wrap around */
274 if (obj_eq (negc
, ZERO
))
275 negc
= negative_carry (dx
< dy
);
277 dx
++; /* may wrap around */
278 negc
= negative_carry (dx
<= dy
);
284 result
= make_integer (dx
, result
);
290 integer
neg (integer x
) {
291 /* neg(x) returns the integer -x */
293 return sub (ZERO
, x
);
296 integer
scale (digit n
, integer x
) {
297 /* scale(n,x) returns the integer n*x */
303 if ((n
== 0) || obj_eq (x
, ZERO
))
313 if (obj_eq (x
, ZERO
)){
314 if (carry
<= MAX_FIXNUM
)
315 result
= norm (result
, ENCODE_FIXNUM ((uint8
)carry
));
317 result
= norm (result
, make_integer (carry
, ZERO
));
321 if (obj_eq (x
, NEG1
)) {
323 if (carry
>= ((1<<digit_width
) + MIN_FIXNUM
))
324 result
= norm (result
, ENCODE_FIXNUM ((uint8
)carry
));
326 result
= norm (result
, make_integer (carry
, NEG1
));
330 m
= (two_digit
)integer_lo (x
) * n
+ carry
;
333 carry
= m
>> digit_width
;
334 result
= make_integer ((digit
)m
, result
);
340 integer
mulnonneg (integer x
, integer y
) {
341 /* mulnonneg(x,y) returns the product of the integers x and y
342 where x is nonnegative */
345 integer s
= scale (integer_lo (x
), y
);
348 result
= make_integer (integer_lo (s
), result
);
352 if (obj_eq (x
, ZERO
))
355 s
= add (s
, scale (integer_lo (x
), y
));
358 return norm (result
, s
);
361 // TODO have functions mul and div that handle negative arguments ? currently, the logic is in prim_mul and prim_div
362 integer
divnonneg (integer x
, integer y
) {
363 /* divnonneg(x,y) returns the quotient and remainder of
364 the integers x and y where x and y are nonnegative */
366 integer result
= ZERO
;
367 uint16 lx
= integer_length (x
);
368 uint16 ly
= integer_length (y
);
373 y
= shift_left (y
, lx
);
376 result
= shl (result
);
377 if (cmp (x
, y
) >= 0) {
379 result
= add (POS1
, result
);
388 // used only in primitives that use small numbers only
389 // for example, vector primitives
390 int32
decode_int (obj o
) {
392 if (o
< MIN_FIXNUM_ENCODING
)
393 TYPE_ERROR("decode_int.0", "integer");
395 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
396 return DECODE_FIXNUM(o
);
400 TYPE_ERROR("decode_int.1", "integer");
401 return ram_get_field3 (o
);
403 else if (IN_ROM(o
)) {
405 TYPE_ERROR("decode_int.2", "integer");
406 return rom_get_field3 (o
);
409 TYPE_ERROR("decode_int.3", "integer");
412 // same purpose as decode_int
413 obj
encode_int (int32 n
) {
414 if (n
>= MIN_FIXNUM
&& n
<= MAX_FIXNUM
) {
415 return ENCODE_FIXNUM(n
);
418 return alloc_ram_cell_init (BIGNUM_FIELD0
, ENCODE_FIXNUM(0), n
>> 8, n
);