arith.scm 4.0 KB

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