File: arith.scm

package info (click to toggle)
scheme48 1.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 18,232 kB
  • sloc: lisp: 88,907; ansic: 87,519; sh: 3,224; makefile: 771
file content (142 lines) | stat: -rw-r--r-- 4,146 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
; Part of Scheme 48 1.9.  See file COPYING for notices and license.

; Authors: Richard Kelsey, Jonathan Rees


; Arithmetic that checks for overflow

(define (carefully op)
  (lambda (x y succ fail)
    (let ((z (op (extract-fixnum x)
		 (extract-fixnum y))))
      (if (or (too-big-for-fixnum? z)
	      (too-small-for-fixnum? z))
	  (goto fail x y)
	  (goto succ (enter-fixnum z))))))

(define add-carefully (carefully +))
(define subtract-carefully (carefully -))

(define half-word-size (quotient bits-per-cell 2))
(define half-word-mask (- (shift-left 1 half-word-size) 1))
(define max-middle (shift-left 1 (- (- bits-per-fixnum 1) half-word-size)))

; Uses SMALL* to do half-word multiplies.  Some implementations
; really care about this.

(define (multiply-carefully x y succ fail)
  (let* ((a (extract-fixnum x))
         (b (extract-fixnum y))
         (positive-result? (if (>= a 0)
                               (>= b 0)
                               (< b 0)))
         (a (abs a))
         (b (abs b))
	 (lo-a (bitwise-and half-word-mask a))
	 (lo-b (bitwise-and half-word-mask b))
         (hi-a (bitwise-and half-word-mask (high-bits a half-word-size)))
         (hi-b (bitwise-and half-word-mask (high-bits b half-word-size)))
	 (lo-c (small* lo-a lo-b))
	 (mid-c (+ (small* lo-a hi-b) (small* lo-b hi-a)))
	 (c (+ lo-c (shift-left mid-c half-word-size))))
    (cond ((or (and (> hi-a 0) (> hi-b 0))
	       (too-big-for-fixnum? lo-c)
               (> 0 lo-c)
	       (> mid-c max-middle))
	   (goto fail x y))
	  (positive-result?
	   (goto succ c))
	  (else
	   (goto succ (- 0 c))))))

(define small*
  (external "SMALL_MULTIPLY" (=> (integer integer) integer) *))

; Test cases for bits-per-cell = 28, bits-per-fixnum = 26

;   (do ((i 2 (* i 2))
;        (j (* -2 (expt 2 23)) (/ j 2)))
;       ((>= j 0) 'ok)
;     (write `((* ,i ,j) ?=? ,(* i j)))
;     (newline))

(define (divide-carefully x y succ fail)
  (if (= y (enter-fixnum 0))
      (goto fail x y)
      (let* ((a (extract-fixnum x))
	     (b (extract-fixnum y))
	     (positive-result? (if (>= a 0)
				   (>= b 0)
				   (< b 0)))
	     (a (abs a))
	     (b (abs b))
	     (c (quotient a b)))
	(cond ((not (= 0 (remainder a b)))
	       (goto fail x y))
	      ((not positive-result?)
	       (goto succ (- 0 c)))
	      (else
	       (goto succ c))))))

; Watch out for (quotient least-fixnum -1)
(define (quotient-carefully x y succ fail)
  (if (= y (enter-fixnum 0))
      (fail x y)
      (let* ((a (extract-fixnum x))
	     (b (extract-fixnum y))
	     (positive-result? (if (>= a 0)
				   (>= b 0)
				   (< b 0)))
	     (a (abs a))
	     (b (abs b))
	     (c (quotient a b)))
	(cond ((not positive-result?)
	       (goto succ (enter-fixnum (- 0 c))))
	      ((too-big-for-fixnum? c)  ; (quotient least-fixnum -1)
	       (goto fail x y))
	      (else
	       (goto succ (enter-fixnum c)))))))

; Overflow check not necessary
(define (remainder-carefully x y succ fail)
  (if (= y (enter-fixnum 0))
      (goto fail x y)
      (let* ((a (extract-fixnum x))
	     (b (extract-fixnum y))
	     (positive-result? (>= a 0))
	     (a (abs a))
	     (b (abs b))
	     (c (remainder a b)))
	(goto succ (enter-fixnum (if positive-result? c (- 0 c)))))))

(define (shift-carefully value+tag count+tag succ fail)
  (let ((value (extract-fixnum value+tag))
	(count (extract-fixnum count+tag)))
    (if (<= count 0)
	(goto succ (arithmetic-shift-right value (- 0 count)))
	(let ((result (shift-left value count)))
	  (if (and (< count bits-per-fixnum)
		   (= value (arithmetic-shift-right result count))
		   (if (>= value 0)
		       (>= result 0)
		       (< result 0)))
	      (goto succ result)
	      (goto fail value+tag count+tag))))))

; beware of (abs least-fixnum)
(define (abs-carefully n succ fail)
  (let ((r (abs (extract-fixnum n))))
    (if (too-big-for-fixnum? r)
	(goto fail n)
	(goto succ (enter-fixnum r)))))

(define (fixnum-bit-count x)
  (let* ((x (extract-fixnum x))
	 (x (if (< x 0) 
		(bitwise-not x)
		x)))
    (do ((x x (arithmetic-shift-right x 1))
	 (count 0 (+ count (bitwise-and x 1))))
	((= x 0)
	 (enter-fixnum count)))))