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 integer
make_integer (digit lo
, integer hi
) {
12 return alloc_ram_cell_init (BIGNUM_FIELD0
| (hi
>> 8), hi
, lo
>> 8, lo
);
15 integer
integer_hi (integer x
) {
17 return ram_get_car (x
);
19 return rom_get_car (x
);
20 else if (x
< (MIN_FIXNUM_ENCODING
- MIN_FIXNUM
))
21 return NEG1
; /* negative fixnum */
23 return ZERO
; /* nonnegative fixnum */
26 digit
integer_lo (integer x
) {
29 f2
= ram_get_field2 (x
);
30 return (f2
<< 8) + ram_get_field3 (x
);
33 f2
= rom_get_field2 (x
);
34 return (f2
<< 8) + rom_get_field3 (x
);
37 return DECODE_FIXNUM(x
);
40 integer
norm (obj prefix
, integer n
) {
41 /* norm(prefix,n) returns a normalized integer whose value is the
42 integer n prefixed with the digits in prefix (a list of digits) */
44 while (prefix
!= NIL
) {
45 digit d
= integer_lo (prefix
);
48 prefix
= integer_hi (temp
);
50 if (obj_eq (n
, ZERO
)) {
51 if (d
<= MAX_FIXNUM
) {
52 n
= ENCODE_FIXNUM (d
& 0xff);
56 else if (obj_eq (n
, NEG1
)) {
57 // -1 is an illegal literal in SIXPIC, thus the double negative
58 if (d
>= (1<<digit_width
) - (- MIN_FIXNUM
)) {
59 n
= ENCODE_FIXNUM (d
- (1<<digit_width
));
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 uint8
cmp (integer x
, integer y
) {
83 /* cmp(x,y) return 0 when x<y, 2 when x>y, and 1 when x=y */
90 if (obj_eq (x
, ZERO
) || obj_eq (x
, NEG1
)) {
92 { if (negp (y
)) result
= 2; else result
= 0; }
96 if (obj_eq (y
, ZERO
) || obj_eq (y
, NEG1
)) {
97 if (negp (x
)) result
= 0; else result
= 2;
101 xlo
= integer_lo (x
);
102 ylo
= integer_lo (y
);
106 { if (xlo
< ylo
) result
= 0; else result
= 2; }
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)));
181 result
= make_integer ((d
<< 1) | obj_eq (temp
, NEG1
), result
);
187 integer
shift_left (integer x
, uint16 n
) {
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
scale (digit n
, integer x
) {
291 /* scale(n,x) returns the integer n*x */
297 if ((n
== 0) || obj_eq (x
, ZERO
))
307 if (obj_eq (x
, ZERO
)){
308 if (carry
<= MAX_FIXNUM
)
309 result
= norm (result
, ENCODE_FIXNUM (carry
& 0xff));
311 result
= norm (result
, make_integer (carry
, ZERO
));
315 if (obj_eq (x
, NEG1
)) {
317 // -1 as a literal is wrong with SIXPIC, thus the double negative
318 if (carry
>= ((1<<digit_width
) - (- MIN_FIXNUM
)))
319 result
= norm (result
, ENCODE_FIXNUM (carry
& 0xff));
321 result
= norm (result
, make_integer (carry
, NEG1
));
329 carry
= m
>> digit_width
;
330 result
= make_integer (m
, result
);
336 integer
mulnonneg (integer x
, integer y
) {
337 /* mulnonneg(x,y) returns the product of the integers x and y
338 where x is nonnegative */
341 integer s
= scale (integer_lo (x
), y
);
344 result
= make_integer (integer_lo (s
), result
);
348 if (obj_eq (x
, ZERO
))
351 s
= add (s
, scale (integer_lo (x
), y
));
354 return norm (result
, s
);
357 // TODO have functions mul and div that handle negative arguments ? currently, the logic is in prim_mul and prim_div
358 integer
divnonneg (integer x
, integer y
) {
359 /* divnonneg(x,y) returns the quotient and remainder of
360 the integers x and y where x and y are nonnegative */
362 integer result
= ZERO
;
363 uint16 lx
= integer_length (x
);
364 uint16 ly
= integer_length (y
);
369 y
= shift_left (y
, lx
);
372 result
= shl (result
);
373 if (cmp (x
, y
) >= 1) {
375 result
= add (POS1
, result
);
384 integer
bitwise_ior (integer x
, integer y
) {
385 /* returns the bitwise inclusive or of x and y */
391 return norm(result
, y
);
393 return norm(result
, x
);
394 result
= make_integer(integer_lo(x
) | integer_lo(y
),
401 integer
bitwise_xor (integer x
, integer y
) { // TODO similar to ior (only diff is the test), abstract ?
402 /* returns the bitwise inclusive or of x and y */
408 return norm(result
, y
);
410 return norm(result
, x
);
411 result
= make_integer(integer_lo(x
) ^ integer_lo(y
),
418 // used only in primitives that use small numbers only
419 // for example, vector primitives
420 uint16
decode_int (obj o
) {
422 if (o
< MIN_FIXNUM_ENCODING
)
423 TYPE_ERROR("decode_int.0", "integer");
425 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
426 return DECODE_FIXNUM(o
);
430 TYPE_ERROR("decode_int.1", "integer");
431 return ram_get_field3 (o
);
433 else if (IN_ROM(o
)) {
435 TYPE_ERROR("decode_int.2", "integer");
436 return rom_get_field3 (o
);
439 TYPE_ERROR("decode_int.3", "integer");
442 // same purpose as decode_int
443 obj
encode_int (uint16 n
) {
444 if (n
<= MAX_FIXNUM
) {
445 return ENCODE_FIXNUM(n
);
448 return alloc_ram_cell_init (BIGNUM_FIELD0
, ENCODE_FIXNUM(0), n
>> 8, n
);
453 // regular (finite, 24 bits) bignums
455 uint16
decode_int (obj o
) {
456 uint16 u
; // TODO should be 32, but is lost anyway since this returns a uint16
460 if (o
< MIN_FIXNUM_ENCODING
)
461 TYPE_ERROR("decode_int.0", "integer");
463 if (o
<= (MIN_FIXNUM_ENCODING
+ (MAX_FIXNUM
- MIN_FIXNUM
)))
464 return DECODE_FIXNUM(o
);
468 TYPE_ERROR("decode_int.1", "integer");
470 u
= ram_get_field1 (o
);
471 h
= ram_get_field2 (o
);
472 l
= ram_get_field3 (o
);
474 else if (IN_ROM(o
)) {
476 TYPE_ERROR("decode_int.2", "integer");
478 u
= rom_get_field1 (o
);
479 h
= rom_get_field2 (o
);
480 l
= rom_get_field3 (o
);
483 TYPE_ERROR("decode_int.3", "integer");
485 if (u
>= 128) // negative
486 return ((((u
- 256) << 8) + h
) << 8) + l
; // TODO ints are all 16 bits, 24 bits won't work
488 return (((u
<< 8) + h
) << 8) + l
;
491 obj
encode_int (uint16 n
) { // TODO does not use the full 24 bits
492 if (n
>= MIN_FIXNUM
&& n
<= MAX_FIXNUM
)
493 return ENCODE_FIXNUM(n
);
495 return alloc_ram_cell_init (BIGNUM_FIELD0
, n
>> 16, n
>> 8, n
);
500 // useful for some primitives
501 void decode_2_int_args () {
502 a1
= decode_int (arg1
);
503 a2
= decode_int (arg2
);