arith.scm 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees
  3. ; Arithmetic that checks for overflow
  4. (define (carefully op)
  5. (lambda (x y succ fail)
  6. (let ((z (op (extract-fixnum x)
  7. (extract-fixnum y))))
  8. (if (or (too-big-for-fixnum? z)
  9. (too-small-for-fixnum? z))
  10. (goto fail x y)
  11. (goto succ (enter-fixnum z))))))
  12. (define add-carefully (carefully +))
  13. (define subtract-carefully (carefully -))
  14. (define half-word-size (quotient bits-per-cell 2))
  15. (define half-word-mask (- (shift-left 1 half-word-size) 1))
  16. (define max-middle (shift-left 1 (- (- bits-per-fixnum 1) half-word-size)))
  17. ; Uses SMALL* to do half-word multiplies. Some implementations
  18. ; really care about this.
  19. (define (multiply-carefully x y succ fail)
  20. (let* ((a (extract-fixnum x))
  21. (b (extract-fixnum y))
  22. (positive-result? (if (>= a 0)
  23. (>= b 0)
  24. (< b 0)))
  25. (a (abs a))
  26. (b (abs b))
  27. (lo-a (bitwise-and half-word-mask a))
  28. (lo-b (bitwise-and half-word-mask b))
  29. (hi-a (bitwise-and half-word-mask (high-bits a half-word-size)))
  30. (hi-b (bitwise-and half-word-mask (high-bits b half-word-size)))
  31. (lo-c (small* lo-a lo-b))
  32. (mid-c (+ (small* lo-a hi-b) (small* lo-b hi-a)))
  33. (c (+ lo-c (shift-left mid-c half-word-size))))
  34. (cond ((or (and (> hi-a 0) (> hi-b 0))
  35. (too-big-for-fixnum? lo-c)
  36. (> 0 lo-c)
  37. (> mid-c max-middle))
  38. (goto fail x y))
  39. (positive-result?
  40. (goto succ c))
  41. (else
  42. (goto succ (- 0 c))))))
  43. (define small*
  44. (external "SMALL_MULTIPLY" (=> (integer integer) integer) *))
  45. ; Test cases for bits-per-cell = 28, bits-per-fixnum = 26
  46. ; (do ((i 2 (* i 2))
  47. ; (j (* -2 (expt 2 23)) (/ j 2)))
  48. ; ((>= j 0) 'ok)
  49. ; (write `((* ,i ,j) ?=? ,(* i j)))
  50. ; (newline))
  51. (define (divide-carefully x y succ fail)
  52. (if (= y (enter-fixnum 0))
  53. (goto fail x y)
  54. (let* ((a (extract-fixnum x))
  55. (b (extract-fixnum y))
  56. (positive-result? (if (>= a 0)
  57. (>= b 0)
  58. (< b 0)))
  59. (a (abs a))
  60. (b (abs b))
  61. (c (quotient a b)))
  62. (cond ((not (= 0 (remainder a b)))
  63. (goto fail x y))
  64. ((not positive-result?)
  65. (goto succ (- 0 c)))
  66. (else
  67. (goto succ c))))))
  68. ; Watch out for (quotient least-fixnum -1)
  69. (define (quotient-carefully x y succ fail)
  70. (if (= y (enter-fixnum 0))
  71. (fail x y)
  72. (let* ((a (extract-fixnum x))
  73. (b (extract-fixnum y))
  74. (positive-result? (if (>= a 0)
  75. (>= b 0)
  76. (< b 0)))
  77. (a (abs a))
  78. (b (abs b))
  79. (c (quotient a b)))
  80. (cond ((not positive-result?)
  81. (goto succ (enter-fixnum (- 0 c))))
  82. ((too-big-for-fixnum? c) ; (quotient least-fixnum -1)
  83. (goto fail x y))
  84. (else
  85. (goto succ (enter-fixnum c)))))))
  86. ; Overflow check not necessary
  87. (define (remainder-carefully x y succ fail)
  88. (if (= y (enter-fixnum 0))
  89. (goto fail x y)
  90. (let* ((a (extract-fixnum x))
  91. (b (extract-fixnum y))
  92. (positive-result? (>= a 0))
  93. (a (abs a))
  94. (b (abs b))
  95. (c (remainder a b)))
  96. (goto succ (enter-fixnum (if positive-result? c (- 0 c)))))))
  97. (define (shift-carefully value+tag count+tag succ fail)
  98. (let ((value (extract-fixnum value+tag))
  99. (count (extract-fixnum count+tag)))
  100. (if (<= count 0)
  101. (goto succ (arithmetic-shift-right value (- 0 count)))
  102. (let ((result (shift-left value count)))
  103. (if (and (< count bits-per-fixnum)
  104. (= value (arithmetic-shift-right result count))
  105. (if (>= value 0)
  106. (>= result 0)
  107. (< result 0)))
  108. (goto succ result)
  109. (goto fail value+tag count+tag))))))
  110. ; beware of (abs least-fixnum)
  111. (define (abs-carefully n succ fail)
  112. (let ((r (abs (extract-fixnum n))))
  113. (if (too-big-for-fixnum? r)
  114. (goto fail n)
  115. (goto succ (enter-fixnum r)))))
  116. (define (fixnum-bit-count x)
  117. (let* ((x (extract-fixnum x))
  118. (x (if (< x 0)
  119. (bitwise-not x)
  120. x)))
  121. (do ((x x (arithmetic-shift-right x 1))
  122. (count 0 (+ count (bitwise-and x 1))))
  123. ((= x 0)
  124. (enter-fixnum count)))))