diff tests/automated/lisp-tests.el @ 4678:b5e1d4f6b66f

Make #'floor, #'ceiling, #'round, #'truncate conform to Common Lisp. lisp/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * cl-extra.el (ceiling*, floor*, round*, truncate*): Implement these in terms of the C functions; mark them as obsolete. (mod*, rem*): Use #'nth-value with the C functions, not #'nth with the CL emulation functions. man/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * lispref/numbers.texi (Bigfloat Basics): Correct this documentation (ignoring for the moment that it breaks off in mid-sentence). tests/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * automated/lisp-tests.el: Test the new Common Lisp-compatible rounding functions available in C. (generate-rounding-output): Provide a function useful for generating the data for the rounding functions tests. src/ChangeLog addition: 2009-08-11 Aidan Kehoe <kehoea@parhasard.net> * floatfns.c (ROUNDING_CONVERT, CONVERT_WITH_NUMBER_TYPES) (CONVERT_WITHOUT_NUMBER_TYPES, MAYBE_TWO_ARGS_BIGNUM) (MAYBE_ONE_ARG_BIGNUM, MAYBE_TWO_ARGS_RATIO) (MAYBE_ONE_ARG_RATIO, MAYBE_TWO_ARGS_BIGFLOAT) (MAYBE_ONE_ARG_BIGFLOAT, MAYBE_EFF, MAYBE_CHAR_OR_MARKER): New macros, used in the implementation of the rounding functions. (ceiling_two_fixnum, ceiling_two_bignum, ceiling_two_ratio) (ceiling_two_bigfloat, ceiling_one_ratio, ceiling_one_bigfloat) (ceiling_two_float, ceiling_one_float, ceiling_one_mundane_arg) (floor_two_fixnum, floor_two_bignum, floor_two_ratio) (floor_two_bigfloat, floor_one_ratio, floor_one_bigfloat) (floor_two_float, floor_one_mundane_arg, round_two_fixnum) (round_two_bignum_1, round_two_bignum, round_two_ratio) (round_one_bigfloat_1, round_two_bigfloat, round_one_ratio) (round_one_bigfloat, round_two_float, round_one_float) (round_one_mundane_arg, truncate_two_fixnum) (truncate_two_bignum, truncate_two_ratio, truncate_two_bigfloat) (truncate_one_ratio, truncate_one_bigfloat, truncate_two_float) (truncate_one_float, truncate_one_mundane_arg): New functions, used in the implementation of the rounding functions. (Fceiling, Ffloor, Fround, Ftruncate, Ffceiling, Fffloor) (Ffround, Fftruncate): Revise to fully support Common Lisp conventions. This means: -- All functions have optional DIVISOR arguments -- All functions return multiple values; see #'values -- All functions do their arithmetic with the correct number types according to the contamination rules. -- #'round and #'fround always round towards the even number in ambiguous cases. * doprnt.c (emacs_doprnt_1): * number.c (internal_coerce_number): Call Ftruncate with two arguments, not one. * floatfns.c (Ffloat): Correct this, if NUMBER is a bignum. * lisp.h: Declare Ftruncate as taking two arguments. * number.c: Provide scratch_ratio2, init it appropriately. * number.h: Make scratch_ratio2 available. * number.h (BIGFLOAT_ARITH_RETURN): * number.h (BIGFLOAT_ARITH_RETURN1): Correct these functions.
author Aidan Kehoe <kehoea@parhasard.net>
date Tue, 11 Aug 2009 17:59:23 +0100
parents 1e3cf11fa27d
children 2c64d2bbb316
line wrap: on
line diff
--- a/tests/automated/lisp-tests.el	Sun Aug 16 20:55:49 2009 +0100
+++ b/tests/automated/lisp-tests.el	Tue Aug 11 17:59:23 2009 +0100
@@ -1368,5 +1368,574 @@
    (load test-file-name nil t nil)
    (delete-file test-file-name))
 
+(flet ((cl-floor (x &optional y)
+	 (let ((q (floor x y)))
+	   (list q (- x (if y (* y q) q)))))
+       (cl-ceiling (x &optional y)
+	 (let ((res (cl-floor x y)))
+	   (if (= (car (cdr res)) 0) res
+	     (list (1+ (car res)) (- (car (cdr res)) (or y 1))))))
+       (cl-truncate (x &optional y)
+	 (if (eq (>= x 0) (or (null y) (>= y 0)))
+	     (cl-floor x y) (cl-ceiling x y)))
+       (cl-round (x &optional y)
+	 (if y
+	     (if (and (integerp x) (integerp y))
+		 (let* ((hy (/ y 2))
+			(res (cl-floor (+ x hy) y)))
+		   (if (and (= (car (cdr res)) 0)
+			    (= (+ hy hy) y)
+			    (/= (% (car res) 2) 0))
+		       (list (1- (car res)) hy)
+		     (list (car res) (- (car (cdr res)) hy))))
+	       (let ((q (round (/ x y))))
+		 (list q (- x (* q y)))))
+	   (if (integerp x) (list x 0)
+	     (let ((q (round x)))
+	       (list q (- x q))))))
+       (Assert-rounding (first second &key
+			 one-floor-result two-floor-result 
+			 one-ffloor-result two-ffloor-result 
+			 one-ceiling-result two-ceiling-result
+			 one-fceiling-result two-fceiling-result
+			 one-round-result two-round-result
+			 one-fround-result two-fround-result
+			 one-truncate-result two-truncate-result
+			 one-ftruncate-result two-ftruncate-result)
+	 (Assert (equal one-floor-result (multiple-value-list
+					  (floor first)))
+		 (format "checking (floor %S) gives %S"
+			 first one-floor-result))
+	 (Assert (equal one-floor-result (multiple-value-list
+					  (floor first 1)))
+		 (format "checking (floor %S 1) gives %S"
+			 first one-floor-result))
+	 (Check-Error arith-error (floor first 0))
+	 (Check-Error arith-error (floor first 0.0))
+	 (Assert (equal two-floor-result (multiple-value-list
+					  (floor first second)))
+		 (format
+		  "checking (floor %S %S) gives %S"
+		  first second two-floor-result))
+	 (Assert (equal (cl-floor first second)
+			(multiple-value-list (floor first second)))
+		 (format
+		  "checking (floor %S %S) gives the same as the old code"
+		  first second))
+	 (Assert (equal one-ffloor-result (multiple-value-list
+					   (ffloor first)))
+		 (format "checking (ffloor %S) gives %S"
+			 first one-ffloor-result))
+	 (Assert (equal one-ffloor-result (multiple-value-list
+					   (ffloor first 1)))
+		 (format "checking (ffloor %S 1) gives %S"
+			 first one-ffloor-result))
+	 (Check-Error arith-error (ffloor first 0))
+	 (Check-Error arith-error (ffloor first 0.0))
+	 (Assert (equal two-ffloor-result (multiple-value-list
+					   (ffloor first second)))
+		 (format "checking (ffloor %S %S) gives %S"
+			 first second two-ffloor-result))
+	 (Assert (equal one-ceiling-result (multiple-value-list
+					    (ceiling first)))
+		 (format "checking (ceiling %S) gives %S"
+			 first one-ceiling-result))
+	 (Assert (equal one-ceiling-result (multiple-value-list
+					    (ceiling first 1)))
+		 (format "checking (ceiling %S 1) gives %S"
+			 first one-ceiling-result))
+	 (Check-Error arith-error (ceiling first 0))
+	 (Check-Error arith-error (ceiling first 0.0))
+	 (Assert (equal two-ceiling-result (multiple-value-list
+					    (ceiling first second)))
+		 (format "checking (ceiling %S %S) gives %S"
+			 first second two-ceiling-result))
+	 (Assert (equal (cl-ceiling first second)
+			(multiple-value-list (ceiling first second)))
+		 (format
+		  "checking (ceiling %S %S) gives the same as the old code"
+		  first second))
+	 (Assert (equal one-fceiling-result (multiple-value-list
+					     (fceiling first)))
+		 (format "checking (fceiling %S) gives %S"
+			 first one-fceiling-result))
+	 (Assert (equal one-fceiling-result (multiple-value-list
+					     (fceiling first 1)))
+		 (format "checking (fceiling %S 1) gives %S"
+			 first one-fceiling-result))
+	 (Check-Error arith-error (fceiling first 0))
+	 (Check-Error arith-error (fceiling first 0.0))
+	 (Assert (equal two-fceiling-result (multiple-value-list
+					  (fceiling first second)))
+		 (format "checking (fceiling %S %S) gives %S"
+			 first second two-fceiling-result))
+	 (Assert (equal one-round-result (multiple-value-list
+					  (round first)))
+		 (format "checking (round %S) gives %S"
+			 first one-round-result))
+	 (Assert (equal one-round-result (multiple-value-list
+					  (round first 1)))
+		 (format "checking (round %S 1) gives %S, types %S, actual %S, types %S"
+			 first one-round-result (mapcar #'type-of one-round-result)
+			 (multiple-value-list (round first 1))
+			 (mapcar #'type-of (multiple-value-list (round first 1)))))
 
+	 (Check-Error arith-error (round first 0))
+	 (Check-Error arith-error (round first 0.0))
+	 (Assert (equal two-round-result (multiple-value-list
+					  (round first second)))
+		 (format "checking (round %S %S) gives %S"
+			 first second two-round-result))
+	 (Assert (equal one-fround-result (multiple-value-list
+					   (fround first)))
+		 (format "checking (fround %S) gives %S"
+			 first one-fround-result))
+	 (Assert (equal one-fround-result (multiple-value-list
+					   (fround first 1)))
+		 (format "checking (fround %S 1) gives %S"
+			 first one-fround-result))
+	 (Check-Error arith-error (fround first 0))
+	 (Check-Error arith-error (fround first 0.0))
+	 (Assert (equal two-fround-result (multiple-value-list
+					   (fround first second)))
+		 (format "checking (fround %S %S) gives %S"
+			 first second two-fround-result))
+	 (Assert (equal (cl-round first second)
+			(multiple-value-list (round first second)))
+		 (format
+		  "checking (round %S %S) gives the same as the old code"
+		  first second))
+	 (Assert (equal one-truncate-result (multiple-value-list
+					     (truncate first)))
+		 (format "checking (truncate %S) gives %S"
+			 first one-truncate-result))
+	 (Assert (equal one-truncate-result (multiple-value-list
+					     (truncate first 1)))
+		 (format "checking (truncate %S 1) gives %S"
+			 first one-truncate-result))
+	 (Check-Error arith-error (truncate first 0))
+	 (Check-Error arith-error (truncate first 0.0))
+	 (Assert (equal two-truncate-result (multiple-value-list
+					     (truncate first second)))
+		 (format "checking (truncate %S %S) gives %S"
+			 first second two-truncate-result))
+	 (Assert (equal (cl-truncate first second)
+			(multiple-value-list (truncate first second)))
+		 (format
+		  "checking (truncate %S %S) gives the same as the old code"
+		  first second))
+	 (Assert (equal one-ftruncate-result (multiple-value-list
+					      (ftruncate first)))
+		 (format "checking (ftruncate %S) gives %S"
+			 first one-ftruncate-result))
+	 (Assert (equal one-ftruncate-result (multiple-value-list
+					      (ftruncate first 1)))
+		 (format "checking (ftruncate %S 1) gives %S"
+			 first one-ftruncate-result))
+	 (Check-Error arith-error (ftruncate first 0))
+	 (Check-Error arith-error (ftruncate first 0.0))
+	 (Assert (equal two-ftruncate-result (multiple-value-list
+					      (ftruncate first second)))
+		 (format "checking (ftruncate %S %S) gives %S"
+			 first second two-ftruncate-result)))
+       (Assert-rounding-floating (pie ee)
+	 (let ((pie-type (type-of pie)))
+	   (assert (eq pie-type (type-of ee)) t
+		   "This code assumes the two arguments have the same type.")
+	   (Assert-rounding pie ee
+  	    :one-floor-result (list 3 (- pie 3))
+            :two-floor-result (list 1 (- pie (* 1 ee)))
+            :one-ffloor-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-ffloor-result (list (coerce 1 pie-type) (- pie (* 1.0 ee)))
+            :one-ceiling-result (list 4 (- pie 4))
+            :two-ceiling-result (list 2 (- pie (* 2 ee)))
+            :one-fceiling-result (list (coerce 4 pie-type) (- pie 4.0))
+            :two-fceiling-result (list (coerce 2 pie-type) (- pie (* 2.0 ee)))
+            :one-round-result (list 3 (- pie 3))
+            :two-round-result (list 1 (- pie (* 1 ee)))
+            :one-fround-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-fround-result (list (coerce 1 pie-type) (- pie (* 1.0 ee)))
+            :one-truncate-result (list 3 (- pie 3))
+            :two-truncate-result (list 1 (- pie (* 1 ee)))
+            :one-ftruncate-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-ftruncate-result (list (coerce 1 pie-type)
+					(- pie (* 1.0 ee))))
+  	 (Assert-rounding pie (- ee)
+            :one-floor-result (list 3 (- pie 3))
+            :two-floor-result (list -2 (- pie (* -2 (- ee))))
+            :one-ffloor-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-ffloor-result (list (coerce -2 pie-type)
+				     (- pie (* -2.0 (- ee))))
+            :one-ceiling-result (list 4 (- pie 4))
+            :two-ceiling-result (list -1 (- pie (* -1 (- ee))))
+            :one-fceiling-result (list (coerce 4 pie-type) (- pie 4.0))
+            :two-fceiling-result (list (coerce -1 pie-type)
+				       (- pie (* -1.0 (- ee))))
+            :one-round-result (list 3 (- pie 3))
+            :two-round-result (list -1 (- pie (* -1 (- ee))))
+            :one-fround-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-fround-result (list (coerce -1 pie-type)
+				     (- pie (* -1.0 (- ee))))
+            :one-truncate-result (list 3 (- pie 3))
+            :two-truncate-result (list -1 (- pie (* -1 (- ee))))
+            :one-ftruncate-result (list (coerce 3 pie-type) (- pie 3.0))
+            :two-ftruncate-result (list (coerce -1 pie-type)
+					(- pie (* -1.0 (- ee)))))
+  	 (Assert-rounding (- pie) ee
+            :one-floor-result (list -4 (- (- pie) -4))
+            :two-floor-result (list -2 (- (- pie) (* -2 ee)))
+            :one-ffloor-result (list (coerce -4 pie-type) (- (- pie) -4.0))
+            :two-ffloor-result (list (coerce -2 pie-type)
+				     (- (- pie) (* -2.0 ee)))
+            :one-ceiling-result (list -3 (- (- pie) -3))
+            :two-ceiling-result (list -1 (- (- pie) (* -1 ee)))
+            :one-fceiling-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-fceiling-result (list (coerce -1 pie-type)
+				       (- (- pie) (* -1.0 ee)))
+            :one-round-result (list -3 (- (- pie) -3))
+            :two-round-result (list -1 (- (- pie) (* -1 ee)))
+            :one-fround-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-fround-result (list (coerce -1 pie-type)
+				     (- (- pie) (* -1.0 ee)))
+            :one-truncate-result (list -3 (- (- pie) -3))
+            :two-truncate-result (list -1 (- (- pie) (* -1 ee)))
+            :one-ftruncate-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-ftruncate-result (list (coerce -1 pie-type)
+					(- (- pie) (* -1.0 ee))))
+  	 (Assert-rounding (- pie) (- ee)
+            :one-floor-result (list -4 (- (- pie) -4))
+            :two-floor-result (list 1 (- (- pie) (* 1 (- ee))))
+            :one-ffloor-result (list (coerce -4 pie-type) (- (- pie) -4.0))
+            :two-ffloor-result (list (coerce 1 pie-type)
+				     (- (- pie) (* 1.0 (- ee))))
+            :one-ceiling-result (list -3 (- (- pie) -3))
+            :two-ceiling-result (list 2 (- (- pie) (* 2 (- ee))))
+            :one-fceiling-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-fceiling-result (list (coerce 2 pie-type)
+				       (- (- pie) (* 2.0 (- ee))))
+            :one-round-result (list -3 (- (- pie) -3))
+            :two-round-result (list 1 (- (- pie) (* 1 (- ee))))
+            :one-fround-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-fround-result (list (coerce 1 pie-type)
+				     (- (- pie) (* 1.0 (- ee))))
+            :one-truncate-result (list -3 (- (- pie) -3))
+            :two-truncate-result (list 1 (- (- pie) (* 1 (- ee))))
+            :one-ftruncate-result (list (coerce -3 pie-type) (- (- pie) -3.0))
+            :two-ftruncate-result (list (coerce 1 pie-type)
+					(- (- pie) (* 1.0 (- ee)))))
+  	 (Assert-rounding ee pie
+            :one-floor-result (list 2 (- ee 2))
+            :two-floor-result (list 0 ee)
+            :one-ffloor-result (list (coerce 2 pie-type) (- ee 2.0))
+            :two-ffloor-result (list (coerce 0 pie-type) ee)
+            :one-ceiling-result (list 3 (- ee 3))
+            :two-ceiling-result (list 1 (- ee pie))
+            :one-fceiling-result (list (coerce 3 pie-type) (- ee 3.0))
+            :two-fceiling-result (list (coerce 1 pie-type) (- ee pie))
+            :one-round-result (list 3 (- ee 3))
+            :two-round-result (list 1 (- ee (* 1 pie)))
+            :one-fround-result (list (coerce 3 pie-type) (- ee 3.0))
+            :two-fround-result (list (coerce 1 pie-type) (- ee (* 1.0 pie)))
+            :one-truncate-result (list 2 (- ee 2))
+            :two-truncate-result (list 0 ee)
+            :one-ftruncate-result (list (coerce 2 pie-type) (- ee 2.0))
+            :two-ftruncate-result (list (coerce 0 pie-type) ee))
+  	 (Assert-rounding ee (- pie)
+            :one-floor-result (list 2 (- ee 2))
+            :two-floor-result (list -1 (- ee (* -1 (- pie))))
+            :one-ffloor-result (list (coerce 2 pie-type) (- ee 2.0))
+            :two-ffloor-result (list (coerce -1 pie-type)
+				     (- ee (* -1.0 (- pie))))
+            :one-ceiling-result (list 3 (- ee 3))
+            :two-ceiling-result (list 0 ee)
+            :one-fceiling-result (list (coerce 3 pie-type) (- ee 3.0))
+            :two-fceiling-result (list (coerce 0 pie-type) ee)
+            :one-round-result (list 3 (- ee 3))
+            :two-round-result (list -1 (- ee (* -1 (- pie))))
+            :one-fround-result (list (coerce 3 pie-type) (- ee 3.0))
+            :two-fround-result (list (coerce -1 pie-type)
+				     (- ee (* -1.0 (- pie))))
+            :one-truncate-result (list 2 (- ee 2))
+            :two-truncate-result (list 0 ee)
+            :one-ftruncate-result (list (coerce 2 pie-type) (- ee 2.0))
+            :two-ftruncate-result (list (coerce 0 pie-type) ee)))))
+    ;; First, two integers: 
+  (Assert-rounding 27 8 :one-floor-result '(27 0) :two-floor-result '(3 3)
+    :one-ffloor-result '(27.0 0) :two-ffloor-result '(3.0 3)
+    :one-ceiling-result '(27 0) :two-ceiling-result '(4 -5)
+    :one-fceiling-result '(27.0 0) :two-fceiling-result '(4.0 -5)
+    :one-round-result '(27 0) :two-round-result '(3 3)
+    :one-fround-result '(27.0 0) :two-fround-result '(3.0 3)
+    :one-truncate-result '(27 0) :two-truncate-result '(3 3)
+    :one-ftruncate-result '(27.0 0) :two-ftruncate-result '(3.0 3))
+  (Assert-rounding 27 -8 :one-floor-result '(27 0)  :two-floor-result '(-4 -5)
+    :one-ffloor-result '(27.0 0) :two-ffloor-result '(-4.0 -5) 
+    :one-ceiling-result '(27 0) :two-ceiling-result '(-3 3)
+    :one-fceiling-result '(27.0 0)  :two-fceiling-result '(-3.0 3)
+    :one-round-result '(27 0) :two-round-result '(-3 3)
+    :one-fround-result '(27.0 0) :two-fround-result '(-3.0 3)
+    :one-truncate-result '(27 0) :two-truncate-result '(-3 3)
+    :one-ftruncate-result '(27.0 0)  :two-ftruncate-result '(-3.0 3))
+  (Assert-rounding -27 8
+    :one-floor-result '(-27 0) :two-floor-result '(-4 5)
+    :one-ffloor-result '(-27.0 0) :two-ffloor-result '(-4.0 5)
+    :one-ceiling-result '(-27 0) :two-ceiling-result '(-3 -3)
+    :one-fceiling-result '(-27.0 0) :two-fceiling-result '(-3.0 -3)
+    :one-round-result '(-27 0) :two-round-result '(-3 -3)
+    :one-fround-result '(-27.0 0) :two-fround-result '(-3.0 -3)
+    :one-truncate-result '(-27 0) :two-truncate-result '(-3 -3)
+    :one-ftruncate-result '(-27.0 0) :two-ftruncate-result '(-3.0 -3))
+  (Assert-rounding -27 -8
+    :one-floor-result '(-27 0) :two-floor-result '(3 -3)
+    :one-ffloor-result '(-27.0 0) :two-ffloor-result '(3.0 -3)
+    :one-ceiling-result '(-27 0) :two-ceiling-result '(4 5)
+    :one-fceiling-result '(-27.0 0) :two-fceiling-result '(4.0 5)
+    :one-round-result '(-27 0) :two-round-result '(3 -3)
+    :one-fround-result '(-27.0 0) :two-fround-result '(3.0 -3)
+    :one-truncate-result '(-27 0) :two-truncate-result '(3 -3)
+    :one-ftruncate-result '(-27.0 0) :two-ftruncate-result '(3.0 -3))
+  (Assert-rounding 8 27
+    :one-floor-result '(8 0) :two-floor-result '(0 8)
+    :one-ffloor-result '(8.0 0) :two-ffloor-result '(0.0 8)
+    :one-ceiling-result '(8 0) :two-ceiling-result '(1 -19)
+    :one-fceiling-result '(8.0 0) :two-fceiling-result '(1.0 -19)
+    :one-round-result '(8 0) :two-round-result '(0 8)
+    :one-fround-result '(8.0 0) :two-fround-result '(0.0 8)
+    :one-truncate-result '(8 0) :two-truncate-result '(0 8)
+    :one-ftruncate-result '(8.0 0) :two-ftruncate-result '(0.0 8))
+  (Assert-rounding 8 -27
+    :one-floor-result '(8 0) :two-floor-result '(-1 -19)
+    :one-ffloor-result '(8.0 0) :two-ffloor-result '(-1.0 -19)
+    :one-ceiling-result '(8 0) :two-ceiling-result '(0 8)
+    :one-fceiling-result '(8.0 0) :two-fceiling-result '(0.0 8)
+    :one-round-result '(8 0) :two-round-result '(0 8)
+    :one-fround-result '(8.0 0) :two-fround-result '(0.0 8)
+    :one-truncate-result '(8 0) :two-truncate-result '(0 8)
+    :one-ftruncate-result '(8.0 0) :two-ftruncate-result '(0.0 8))
+  (Assert-rounding -8 27
+    :one-floor-result '(-8 0) :two-floor-result '(-1 19)
+    :one-ffloor-result '(-8.0 0) :two-ffloor-result '(-1.0 19)
+    :one-ceiling-result '(-8 0) :two-ceiling-result '(0 -8)
+    :one-fceiling-result '(-8.0 0) :two-fceiling-result '(0.0 -8)
+    :one-round-result '(-8 0) :two-round-result '(0 -8)
+    :one-fround-result '(-8.0 0) :two-fround-result '(0.0 -8)
+    :one-truncate-result '(-8 0) :two-truncate-result '(0 -8)
+    :one-ftruncate-result '(-8.0 0) :two-ftruncate-result '(0.0 -8))
+  (Assert-rounding -8 -27
+    :one-floor-result '(-8 0) :two-floor-result '(0 -8)
+    :one-ffloor-result '(-8.0 0) :two-ffloor-result '(0.0 -8)
+    :one-ceiling-result '(-8 0) :two-ceiling-result '(1 19)
+    :one-fceiling-result '(-8.0 0) :two-fceiling-result '(1.0 19)
+    :one-round-result '(-8 0) :two-round-result '(0 -8)
+    :one-fround-result '(-8.0 0) :two-fround-result '(0.0 -8)
+    :one-truncate-result '(-8 0) :two-truncate-result '(0 -8)
+    :one-ftruncate-result '(-8.0 0) :two-ftruncate-result '(0.0 -8))
+  (Assert-rounding 32 4
+    :one-floor-result '(32 0) :two-floor-result '(8 0)
+    :one-ffloor-result '(32.0 0) :two-ffloor-result '(8.0 0)
+    :one-ceiling-result '(32 0) :two-ceiling-result '(8 0)
+    :one-fceiling-result '(32.0 0) :two-fceiling-result '(8.0 0)
+    :one-round-result '(32 0) :two-round-result '(8 0)
+    :one-fround-result '(32.0 0) :two-fround-result '(8.0 0)
+    :one-truncate-result '(32 0) :two-truncate-result '(8 0)
+    :one-ftruncate-result '(32.0 0) :two-ftruncate-result '(8.0 0))
+  (Assert-rounding 32 -4
+    :one-floor-result '(32 0) :two-floor-result '(-8 0)
+    :one-ffloor-result '(32.0 0) :two-ffloor-result '(-8.0 0)
+    :one-ceiling-result '(32 0) :two-ceiling-result '(-8 0)
+    :one-fceiling-result '(32.0 0) :two-fceiling-result '(-8.0 0)
+    :one-round-result '(32 0) :two-round-result '(-8 0)
+    :one-fround-result '(32.0 0) :two-fround-result '(-8.0 0)
+    :one-truncate-result '(32 0) :two-truncate-result '(-8 0)
+    :one-ftruncate-result '(32.0 0) :two-ftruncate-result '(-8.0 0))
+  (Assert-rounding 12 9
+    :one-floor-result '(12 0) :two-floor-result '(1 3)
+    :one-ffloor-result '(12.0 0) :two-ffloor-result '(1.0 3)
+    :one-ceiling-result '(12 0) :two-ceiling-result '(2 -6)
+    :one-fceiling-result '(12.0 0) :two-fceiling-result '(2.0 -6)
+    :one-round-result '(12 0) :two-round-result '(1 3)
+    :one-fround-result '(12.0 0) :two-fround-result '(1.0 3)
+    :one-truncate-result '(12 0) :two-truncate-result '(1 3)
+    :one-ftruncate-result '(12.0 0) :two-ftruncate-result '(1.0 3))
+  (Assert-rounding 10 4
+    :one-floor-result '(10 0) :two-floor-result '(2 2)
+    :one-ffloor-result '(10.0 0) :two-ffloor-result '(2.0 2)
+    :one-ceiling-result '(10 0) :two-ceiling-result '(3 -2)
+    :one-fceiling-result '(10.0 0) :two-fceiling-result '(3.0 -2)
+    :one-round-result '(10 0) :two-round-result '(2 2)
+    :one-fround-result '(10.0 0) :two-fround-result '(2.0 2)
+    :one-truncate-result '(10 0) :two-truncate-result '(2 2)
+    :one-ftruncate-result '(10.0 0) :two-ftruncate-result '(2.0 2))
+  (Assert-rounding 14 4
+    :one-floor-result '(14 0) :two-floor-result '(3 2)
+    :one-ffloor-result '(14.0 0) :two-ffloor-result '(3.0 2)
+    :one-ceiling-result '(14 0) :two-ceiling-result '(4 -2)
+    :one-fceiling-result '(14.0 0) :two-fceiling-result '(4.0 -2)
+    :one-round-result '(14 0) :two-round-result '(4 -2)
+    :one-fround-result '(14.0 0) :two-fround-result '(4.0 -2)
+    :one-truncate-result '(14 0) :two-truncate-result '(3 2)
+    :one-ftruncate-result '(14.0 0) :two-ftruncate-result '(3.0 2))
+  ;; Now, two floats:
+  (Assert-rounding-floating pi e)
+  (when (featurep 'bigfloat)
+    (Assert-rounding-floating (coerce pi 'bigfloat) (coerce e 'bigfloat)))
+  (when (featurep 'bignum)
+    (assert (not (evenp most-positive-fixnum)) t
+      "In the unlikely event that most-positive-fixnum is even, rewrite this.")
+    (Assert-rounding (1+ most-positive-fixnum) (* 2 most-positive-fixnum)
+      :one-floor-result `(,(1+ most-positive-fixnum) 0)
+      :two-floor-result `(0 ,(1+ most-positive-fixnum))
+      :one-ffloor-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-ffloor-result `(0.0 ,(1+ most-positive-fixnum))
+      :one-ceiling-result `(,(1+ most-positive-fixnum) 0)
+      :two-ceiling-result `(1 ,(1+ (- most-positive-fixnum)))
+      :one-fceiling-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-fceiling-result `(1.0 ,(1+ (- most-positive-fixnum)))
+      :one-round-result `(,(1+ most-positive-fixnum) 0)
+      :two-round-result `(1 ,(1+ (- most-positive-fixnum)))
+      :one-fround-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-fround-result `(1.0 ,(1+ (- most-positive-fixnum)))
+      :one-truncate-result `(,(1+ most-positive-fixnum) 0)
+      :two-truncate-result `(0 ,(1+ most-positive-fixnum))
+      :one-ftruncate-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-ftruncate-result `(0.0 ,(1+ most-positive-fixnum)))
+    (Assert-rounding (1+ most-positive-fixnum) (- (* 2 most-positive-fixnum))
+      :one-floor-result `(,(1+ most-positive-fixnum) 0)
+      :two-floor-result `(-1 ,(1+ (- most-positive-fixnum)))
+      :one-ffloor-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-ffloor-result `(-1.0 ,(1+ (- most-positive-fixnum)))
+      :one-ceiling-result `(,(1+ most-positive-fixnum) 0)
+      :two-ceiling-result `(0 ,(1+ most-positive-fixnum))
+      :one-fceiling-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-fceiling-result `(0.0 ,(1+ most-positive-fixnum))
+      :one-round-result `(,(1+ most-positive-fixnum) 0)
+      :two-round-result `(-1 ,(1+ (- most-positive-fixnum)))
+      :one-fround-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-fround-result `(-1.0 ,(1+ (- most-positive-fixnum)))
+      :one-truncate-result `(,(1+ most-positive-fixnum) 0)
+      :two-truncate-result `(0 ,(1+ most-positive-fixnum))
+      :one-ftruncate-result `(,(float (1+ most-positive-fixnum)) 0)
+      :two-ftruncate-result `(0.0 ,(1+ most-positive-fixnum)))
+    (Assert-rounding (- (1+ most-positive-fixnum)) (* 2 most-positive-fixnum)
+      :one-floor-result `(,(- (1+ most-positive-fixnum)) 0)
+      :two-floor-result `(-1 ,(1- most-positive-fixnum))
+      :one-ffloor-result `(,(float (- (1+ most-positive-fixnum))) 0)
+      :two-ffloor-result `(-1.0 ,(1- most-positive-fixnum))
+      :one-ceiling-result `(,(- (1+ most-positive-fixnum)) 0)
+      :two-ceiling-result `(0 ,(- (1+ most-positive-fixnum)))
+      :one-fceiling-result `(,(float (- (1+ most-positive-fixnum))) 0)
+      :two-fceiling-result `(0.0 ,(- (1+ most-positive-fixnum)))
+      :one-round-result `(,(- (1+ most-positive-fixnum)) 0)
+      :two-round-result `(-1 ,(1- most-positive-fixnum))
+      :one-fround-result `(,(float (- (1+ most-positive-fixnum))) 0)
+      :two-fround-result `(-1.0 ,(1- most-positive-fixnum))
+      :one-truncate-result `(,(- (1+ most-positive-fixnum)) 0)
+      :two-truncate-result `(0 ,(- (1+ most-positive-fixnum)))
+      :one-ftruncate-result `(,(float (- (1+ most-positive-fixnum))) 0)
+      :two-ftruncate-result `(0.0 ,(- (1+ most-positive-fixnum))))
+    ;; Test the handling of values with .5: 
+    (Assert-rounding (1+ (* 2 most-positive-fixnum)) 2
+      :one-floor-result `(,(1+ (* 2 most-positive-fixnum)) 0)
+      :two-floor-result `(,most-positive-fixnum 1)
+      :one-ffloor-result `(,(float (1+ (* 2 most-positive-fixnum))) 0)
+      ;; We can't just call #'float here; we must use code that converts a
+      ;; bignum with value most-positive-fixnum (the creation of which is
+      ;; not directly possible in Lisp) to a float, not code that converts
+      ;; the fixnum with value most-positive-fixnum to a float. The eval is
+      ;; to avoid compile-time optimisation that can break this.
+      :two-ffloor-result `(,(eval '(- (1+ most-positive-fixnum) 1 0.0)) 1)
+      :one-ceiling-result `(,(1+ (* 2 most-positive-fixnum)) 0)
+      :two-ceiling-result `(,(1+ most-positive-fixnum) -1)
+      :one-fceiling-result `(,(float (1+ (* 2 most-positive-fixnum))) 0)
+      :two-fceiling-result `(,(float (1+ most-positive-fixnum)) -1)
+      :one-round-result `(,(1+ (* 2 most-positive-fixnum)) 0)
+      :two-round-result `(,(1+ most-positive-fixnum) -1)
+      :one-fround-result `(,(float (1+ (* 2 most-positive-fixnum))) 0)
+      :two-fround-result `(,(float (1+ most-positive-fixnum)) -1)
+      :one-truncate-result `(,(1+ (* 2 most-positive-fixnum)) 0)
+      :two-truncate-result `(,most-positive-fixnum 1)
+      :one-ftruncate-result `(,(float (1+ (* 2 most-positive-fixnum))) 0)
+      ;; See the comment above on :two-ffloor-result:
+      :two-ftruncate-result `(,(eval '(- (1+ most-positive-fixnum) 1 0.0)) 1))
+    (Assert-rounding (1+ (* 2 (1- most-positive-fixnum))) 2
+      :one-floor-result `(,(1+ (* 2 (1- most-positive-fixnum))) 0)
+      :two-floor-result `(,(1- most-positive-fixnum) 1)
+      :one-ffloor-result `(,(float (1+ (* 2 (1- most-positive-fixnum)))) 0)
+      ;; See commentary above on float conversions.
+      :two-ffloor-result `(,(eval '(- (1+ most-positive-fixnum) 2 0.0)) 1)
+      :one-ceiling-result `(,(1+ (* 2 (1- most-positive-fixnum))) 0)
+      :two-ceiling-result `(,most-positive-fixnum -1)
+      :one-fceiling-result `(,(float (1+ (* 2 (1- most-positive-fixnum)))) 0)
+      :two-fceiling-result `(,(eval '(- (1+ most-positive-fixnum) 1 0.0)) -1)
+      :one-round-result `(,(1+ (* 2 (1- most-positive-fixnum))) 0)
+      :two-round-result `(,(1- most-positive-fixnum) 1)
+      :one-fround-result `(,(float (1+ (* 2 (1- most-positive-fixnum)))) 0)
+      :two-fround-result `(,(eval '(- (1+ most-positive-fixnum) 2 0.0)) 1)
+      :one-truncate-result `(,(1+ (* 2 (1- most-positive-fixnum))) 0)
+      :two-truncate-result `(,(1- most-positive-fixnum) 1)
+      :one-ftruncate-result `(,(float (1+ (* 2 (1- most-positive-fixnum)))) 0)
+      ;; See commentary above
+      :two-ftruncate-result `(,(eval '(- (1+ most-positive-fixnum) 2 0.0))
+			      1)))
+  (when (featurep 'ratio)
+    (Assert-rounding (read "4/3") (read "8/7")
+     :one-floor-result '(1 1/3) :two-floor-result '(1 4/21)
+     :one-ffloor-result '(1.0 1/3) :two-ffloor-result '(1.0 4/21)
+     :one-ceiling-result '(2 -2/3) :two-ceiling-result '(2 -20/21)
+     :one-fceiling-result '(2.0 -2/3) :two-fceiling-result '(2.0 -20/21)
+     :one-round-result '(1 1/3) :two-round-result '(1 4/21)
+     :one-fround-result '(1.0 1/3) :two-fround-result '(1.0 4/21)
+     :one-truncate-result '(1 1/3) :two-truncate-result '(1 4/21)
+     :one-ftruncate-result '(1.0 1/3) :two-ftruncate-result '(1.0 4/21))
+    (Assert-rounding (read "-4/3") (read "8/7")
+     :one-floor-result '(-2 2/3) :two-floor-result '(-2 20/21)
+     :one-ffloor-result '(-2.0 2/3) :two-ffloor-result '(-2.0 20/21)
+     :one-ceiling-result '(-1 -1/3) :two-ceiling-result '(-1 -4/21)
+     :one-fceiling-result '(-1.0 -1/3) :two-fceiling-result '(-1.0 -4/21)
+     :one-round-result '(-1 -1/3) :two-round-result '(-1 -4/21)
+     :one-fround-result '(-1.0 -1/3) :two-fround-result '(-1.0 -4/21)
+     :one-truncate-result '(-1 -1/3) :two-truncate-result '(-1 -4/21)
+     :one-ftruncate-result '(-1.0 -1/3) :two-ftruncate-result '(-1.0 -4/21))))
 
+;; Run this function in a Common Lisp with two arguments to get results that
+;; we should compare against, above. Though note the dancing-around with the
+;; bigfloats and bignums above, too; you can't necessarily just use the
+;; output here.
+
+(defun generate-rounding-output (first second)
+  (let ((print-readably t))
+    (princ first)
+    (princ " ")
+    (princ second)
+    (princ " :one-floor-result ")
+    (princ (list 'quote (multiple-value-list (floor first))))
+    (princ " :two-floor-result ")
+    (princ (list 'quote (multiple-value-list (floor first second))))
+    (princ " :one-ffloor-result ")
+    (princ (list 'quote (multiple-value-list (ffloor first))))
+    (princ " :two-ffloor-result ")
+    (princ (list 'quote (multiple-value-list (ffloor first second))))
+    (princ " :one-ceiling-result ")
+    (princ (list 'quote (multiple-value-list (ceiling first))))
+    (princ " :two-ceiling-result ")
+    (princ (list 'quote (multiple-value-list (ceiling first second))))
+    (princ " :one-fceiling-result ")
+    (princ (list 'quote (multiple-value-list (fceiling first))))
+    (princ " :two-fceiling-result ")
+    (princ (list 'quote (multiple-value-list (fceiling first second))))
+    (princ " :one-round-result ")
+    (princ (list 'quote (multiple-value-list (round first))))
+    (princ " :two-round-result ")
+    (princ (list 'quote (multiple-value-list (round first second))))
+    (princ " :one-fround-result ")
+    (princ (list 'quote (multiple-value-list (fround first))))
+    (princ " :two-fround-result ")
+    (princ (list 'quote (multiple-value-list (fround first second))))
+    (princ " :one-truncate-result ")
+    (princ (list 'quote (multiple-value-list (truncate first))))
+    (princ " :two-truncate-result ")
+    (princ (list 'quote (multiple-value-list (truncate first second))))
+    (princ " :one-ftruncate-result ")
+    (princ (list 'quote (multiple-value-list (ftruncate first))))
+    (princ " :two-ftruncate-result ")
+    (princ (list 'quote (multiple-value-list (ftruncate first second))))))