X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Ffloat-tran.lisp;h=538ccc05b41206453a30bd4c5398c65f9c902977;hb=b63c4fb9b98fa8188e17ba926e150ba417a74635;hp=49b9cc7adc3cd073e65e951d5425e59ad10db556;hpb=57e21c4b62e8c1a1ee7ef59ed2abb0c864fb06bc;p=sbcl.git diff --git a/src/compiler/float-tran.lisp b/src/compiler/float-tran.lisp index 49b9cc7..538ccc0 100644 --- a/src/compiler/float-tran.lisp +++ b/src/compiler/float-tran.lisp @@ -50,41 +50,52 @@ ;;; through the code this way. It would be nice to move this into the ;;; same file as the other RANDOM definitions. (deftransform random ((num &optional state) - ((integer 1 #.(expt 2 32)) &optional *)) + ((integer 1 #.(expt 2 sb!vm::n-word-bits)) &optional *)) ;; FIXME: I almost conditionalized this as #!+sb-doc. Find some way ;; of automatically finding #!+sb-doc in proximity to DEFTRANSFORM ;; to let me scan for places that I made this mistake and didn't ;; catch myself. "use inline (UNSIGNED-BYTE 32) operations" - (let ((num-high (numeric-type-high (lvar-type num)))) - (when (null num-high) - (give-up-ir1-transform)) - (cond ((constant-lvar-p num) - ;; Check the worst case sum absolute error for the random number - ;; expectations. - (let ((rem (rem (expt 2 32) num-high))) - (unless (< (/ (* 2 rem (- num-high rem)) num-high (expt 2 32)) - (expt 2 (- sb!kernel::random-integer-extra-bits))) - (give-up-ir1-transform - "The random number expectations are inaccurate.")) - (if (= num-high (expt 2 32)) - '(random-chunk (or state *random-state*)) - #!-x86 '(rem (random-chunk (or state *random-state*)) num) - #!+x86 - ;; Use multiplication, which is faster. - '(values (sb!bignum::%multiply - (random-chunk (or state *random-state*)) - num))))) - ((> num-high random-fixnum-max) - (give-up-ir1-transform - "The range is too large to ensure an accurate result.")) - #!+x86 - ((< num-high (expt 2 32)) - '(values (sb!bignum::%multiply (random-chunk (or state - *random-state*)) - num))) - (t - '(rem (random-chunk (or state *random-state*)) num))))) + (let ((type (lvar-type num)) + (limit (expt 2 sb!vm::n-word-bits)) + (random-chunk (ecase sb!vm::n-word-bits + (32 'random-chunk) + (64 'sb!kernel::big-random-chunk)))) + (if (numeric-type-p type) + (let ((num-high (numeric-type-high (lvar-type num)))) + (aver num-high) + (cond ((constant-lvar-p num) + ;; Check the worst case sum absolute error for the + ;; random number expectations. + (let ((rem (rem limit num-high))) + (unless (< (/ (* 2 rem (- num-high rem)) + num-high limit) + (expt 2 (- sb!kernel::random-integer-extra-bits))) + (give-up-ir1-transform + "The random number expectations are inaccurate.")) + (if (= num-high limit) + `(,random-chunk (or state *random-state*)) + #!-(or x86 x86-64) + `(rem (,random-chunk (or state *random-state*)) num) + #!+(or x86 x86-64) + ;; Use multiplication, which is faster. + `(values (sb!bignum::%multiply + (,random-chunk (or state *random-state*)) + num))))) + ((> num-high random-fixnum-max) + (give-up-ir1-transform + "The range is too large to ensure an accurate result.")) + #!+(or x86 x86-64) + ((< num-high limit) + `(values (sb!bignum::%multiply + (,random-chunk (or state *random-state*)) + num))) + (t + `(rem (,random-chunk (or state *random-state*)) num)))) + ;; KLUDGE: a relatively conservative treatment, but better + ;; than a bug (reported by PFD sbcl-devel towards the end of + ;; 2004-11. + '(rem (random-chunk (or state *random-state*)) num)))) ;;;; float accessors @@ -137,10 +148,10 @@ (values double-float-significand double-float-int-exponent (integer -1 1)) (movable foldable flushable)) -(defknown scale-single-float (single-float fixnum) single-float +(defknown scale-single-float (single-float integer) single-float (movable foldable flushable)) -(defknown scale-double-float (double-float fixnum) double-float +(defknown scale-double-float (double-float integer) double-float (movable foldable flushable)) (deftransform decode-float ((x) (single-float) *) @@ -906,17 +917,21 @@ ((csubtypep y (specifier-type 'integer)) ;; A real raised to an integer power is well-defined. (merged-interval-expt x y)) + ;; A real raised to a non-integral power can be a float or a + ;; complex number. + ((or (csubtypep x (specifier-type '(rational 0))) + (csubtypep x (specifier-type '(float (0d0))))) + ;; But a positive real to any power is well-defined. + (merged-interval-expt x y)) + ((and (csubtypep x (specifier-type 'rational)) + (csubtypep x (specifier-type 'rational))) + ;; A rational to the power of a rational could be a rational + ;; or a possibly-complex single float + (specifier-type '(or rational single-float (complex single-float)))) (t - ;; A real raised to a non-integral power can be a float or a - ;; complex number. - (cond ((or (csubtypep x (specifier-type '(rational 0))) - (csubtypep x (specifier-type '(float (0d0))))) - ;; But a positive real to any power is well-defined. - (merged-interval-expt x y)) - (t - ;; a real to some power. The result could be a real - ;; or a complex. - (float-or-complex-float-type (numeric-contagion x y))))))) + ;; a real to some power. The result could be a real or a + ;; complex. + (float-or-complex-float-type (numeric-contagion x y))))) (defoptimizer (expt derive-type) ((x y)) (two-arg-derive-type x y #'expt-derive-type-aux #'expt)) @@ -1342,3 +1357,56 @@ (plusp number))) (values (1+ tru) (- rem ,defaulted-divisor)) (values tru rem))))) + +(defknown %unary-ftruncate (real) float (movable foldable flushable)) +(defknown %unary-ftruncate/single (single-float) single-float + (movable foldable flushable)) +(defknown %unary-ftruncate/double (double-float) double-float + (movable foldable flushable)) + +(defun %unary-ftruncate/single (x) + (declare (type single-float x)) + (declare (optimize speed (safety 0))) + (let* ((bits (single-float-bits x)) + (exp (ldb sb!vm:single-float-exponent-byte bits)) + (biased (the single-float-exponent + (- exp sb!vm:single-float-bias)))) + (declare (type (signed-byte 32) bits)) + (cond + ((= exp sb!vm:single-float-normal-exponent-max) x) + ((<= biased 0) (* x 0f0)) + ((>= biased (float-digits x)) x) + (t + (let ((frac-bits (- (float-digits x) biased))) + (setf bits (logandc2 bits (- (ash 1 frac-bits) 1))) + (make-single-float bits)))))) + +(defun %unary-ftruncate/double (x) + (declare (type double-float x)) + (declare (optimize speed (safety 0))) + (let* ((high (double-float-high-bits x)) + (low (double-float-low-bits x)) + (exp (ldb sb!vm:double-float-exponent-byte high)) + (biased (the double-float-exponent + (- exp sb!vm:double-float-bias)))) + (declare (type (signed-byte 32) high) + (type (unsigned-byte 32) low)) + (cond + ((= exp sb!vm:double-float-normal-exponent-max) x) + ((<= biased 0) (* x 0d0)) + ((>= biased (float-digits x)) x) + (t + (let ((frac-bits (- (float-digits x) biased))) + (cond ((< frac-bits 32) + (setf low (logandc2 low (- (ash 1 frac-bits) 1)))) + (t + (setf low 0) + (setf high (logandc2 high (- (ash 1 (- frac-bits 32)) 1))))) + (make-double-float high low)))))) + +(macrolet + ((def (float-type fun) + `(deftransform %unary-ftruncate ((x) (,float-type)) + '(,fun x)))) + (def single-float %unary-ftruncate/single) + (def double-float %unary-ftruncate/double))