1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-10 14:00:21 +02:00

Add four new sets of fast quotient and remainder operators

* libguile/numbers.c (scm_floor_divide, scm_floor_quotient,
  scm_floor_remainder, scm_ceiling_divide, scm_ceiling_quotient,
  scm_ceiling_remainder, scm_truncate_divide, scm_truncate_quotient,
  scm_truncate_remainder, scm_round_divide, scm_round_quotient,
  scm_round_remainder): New extensible procedures `floor/',
  `floor-quotient', `floor-remainder', `ceiling/', `ceiling-quotient',
  `ceiling-remainder', `truncate/', `truncate-quotient',
  `truncate-remainder', `round/', `round-quotient', and
  `round-remainder'.

* libguile/numbers.h: Add function prototypes.

* test-suite/tests/numbers.test: Add tests.

* doc/ref/api-data.texi (Arithmetic): Add documentation.

* NEWS: Add NEWS entry.
This commit is contained in:
Mark H Weaver 2011-02-13 09:16:27 -05:00 committed by Andy Wingo
parent 03ddd15bae
commit 8f9da3406b
5 changed files with 2451 additions and 3 deletions

28
NEWS
View file

@ -23,6 +23,34 @@ instead.
`define-once' is like Lisp's `defvar': it creates a toplevel binding,
but only if one does not exist already.
** Added four new sets of fast quotient and remainder operators
Added four new sets of fast quotient and remainder operators with
different semantics than the R5RS operators. They support not only
integers, but all reals, including exact rationals and inexact
floating point numbers.
These procedures accept two real numbers N and D, where the divisor D
must be non-zero. Each set of operators computes an integer quotient
Q and a real remainder R such that N = Q*D + R and |R| < |D|. They
differ only in how N/D is rounded to produce Q.
`floor-quotient' and `floor-remainder' compute Q and R, respectively,
where Q has been rounded toward negative infinity. `floor/' returns
both Q and R, and is more efficient than computing each separately.
Note that when applied to integers, `floor-remainder' is equivalent to
the R5RS integer-only `modulo' operator. `ceiling-quotient',
`ceiling-remainder', and `ceiling/' are similar except that Q is
rounded toward positive infinity.
For `truncate-quotient', `truncate-remainder', and `truncate/', Q is
rounded toward zero. Note that when applied to integers,
`truncate-quotient' and `truncate-remainder' are equivalent to the
R5RS integer-only operators `quotient' and `remainder'.
For `round-quotient', `round-remainder', and `round/', Q is rounded to
the nearest integer, with ties going to the nearest even integer.
** Improved exactness handling for complex number parsing
When parsing non-real complex numbers, exactness specifiers are now

View file

@ -907,7 +907,7 @@ sign as @var{n}. In all cases quotient and remainder satisfy
(remainder -13 4) @result{} -1
@end lisp
See also @code{euclidean-quotient}, @code{euclidean-remainder} and
See also @code{truncate-quotient}, @code{truncate-remainder} and
related operations in @ref{Arithmetic}.
@end deffn
@ -924,7 +924,7 @@ sign as @var{d}.
(modulo -13 -4) @result{} -1
@end lisp
See also @code{euclidean-quotient}, @code{euclidean-remainder} and
See also @code{floor-quotient}, @code{floor-remainder} and
related operations in @ref{Arithmetic}.
@end deffn
@ -1148,9 +1148,21 @@ Returns the magnitude or angle of @var{z} as a @code{double}.
@rnindex euclidean/
@rnindex euclidean-quotient
@rnindex euclidean-remainder
@rnindex floor/
@rnindex floor-quotient
@rnindex floor-remainder
@rnindex ceiling/
@rnindex ceiling-quotient
@rnindex ceiling-remainder
@rnindex truncate/
@rnindex truncate-quotient
@rnindex truncate-remainder
@rnindex centered/
@rnindex centered-quotient
@rnindex centered-remainder
@rnindex round/
@rnindex round-quotient
@rnindex round-remainder
The C arithmetic functions below always takes two arguments, while the
Scheme functions can take an arbitrary number. When you need to
@ -1281,6 +1293,93 @@ Note that these operators are equivalent to the R6RS operators
@end lisp
@end deftypefn
@deftypefn {Scheme Procedure} {} floor/ @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} floor-quotient @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} floor-remainder @var{x} @var{y}
@deftypefnx {C Function} void scm_floor_divide (SCM @var{x}, SCM @var{y}, SCM *@var{q}, SCM *@var{r})
@deftypefnx {C Function} SCM scm_floor_quotient (@var{x}, @var{y})
@deftypefnx {C Function} SCM scm_floor_remainder (@var{x}, @var{y})
These procedures accept two real numbers @var{x} and @var{y}, where the
divisor @var{y} must be non-zero. @code{floor-quotient} returns the
integer @var{q} and @code{floor-remainder} returns the real number
@var{r} such that @math{@var{q} = floor(@var{x}/@var{y})} and
@math{@var{x} = @var{q}*@var{y} + @var{r}}. @code{floor/} returns
both @var{q} and @var{r}, and is more efficient than computing each
separately. Note that @var{r}, if non-zero, will have the same sign
as @var{y}.
When @var{x} and @var{y} are integers, @code{floor-quotient} is
equivalent to the R5RS integer-only operator @code{modulo}.
@lisp
(floor-quotient 123 10) @result{} 12
(floor-remainder 123 10) @result{} 3
(floor/ 123 10) @result{} 12 and 3
(floor/ 123 -10) @result{} -13 and -7
(floor/ -123 10) @result{} -13 and 7
(floor/ -123 -10) @result{} 12 and -3
(floor/ -123.2 -63.5) @result{} 1.0 and -59.7
(floor/ 16/3 -10/7) @result{} -4 and -8/21
@end lisp
@end deftypefn
@deftypefn {Scheme Procedure} {} ceiling/ @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} ceiling-quotient @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} ceiling-remainder @var{x} @var{y}
@deftypefnx {C Function} void scm_ceiling_divide (SCM @var{x}, SCM @var{y}, SCM *@var{q}, SCM *@var{r})
@deftypefnx {C Function} SCM scm_ceiling_quotient (@var{x}, @var{y})
@deftypefnx {C Function} SCM scm_ceiling_remainder (@var{x}, @var{y})
These procedures accept two real numbers @var{x} and @var{y}, where the
divisor @var{y} must be non-zero. @code{ceiling-quotient} returns the
integer @var{q} and @code{ceiling-remainder} returns the real number
@var{r} such that @math{@var{q} = ceiling(@var{x}/@var{y})} and
@math{@var{x} = @var{q}*@var{y} + @var{r}}. @code{ceiling/} returns
both @var{q} and @var{r}, and is more efficient than computing each
separately. Note that @var{r}, if non-zero, will have the opposite sign
of @var{y}.
@lisp
(ceiling-quotient 123 10) @result{} 13
(ceiling-remainder 123 10) @result{} -7
(ceiling/ 123 10) @result{} 13 and -7
(ceiling/ 123 -10) @result{} -12 and 3
(ceiling/ -123 10) @result{} -12 and -3
(ceiling/ -123 -10) @result{} 13 and 7
(ceiling/ -123.2 -63.5) @result{} 2.0 and 3.8
(ceiling/ 16/3 -10/7) @result{} -3 and 22/21
@end lisp
@end deftypefn
@deftypefn {Scheme Procedure} {} truncate/ @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} truncate-quotient @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} truncate-remainder @var{x} @var{y}
@deftypefnx {C Function} void scm_truncate_divide (SCM @var{x}, SCM @var{y}, SCM *@var{q}, SCM *@var{r})
@deftypefnx {C Function} SCM scm_truncate_quotient (@var{x}, @var{y})
@deftypefnx {C Function} SCM scm_truncate_remainder (@var{x}, @var{y})
These procedures accept two real numbers @var{x} and @var{y}, where the
divisor @var{y} must be non-zero. @code{truncate-quotient} returns the
integer @var{q} and @code{truncate-remainder} returns the real number
@var{r} such that @var{q} is @math{@var{x}/@var{y}} rounded toward zero,
and @math{@var{x} = @var{q}*@var{y} + @var{r}}. @code{truncate/} returns
both @var{q} and @var{r}, and is more efficient than computing each
separately. Note that @var{r}, if non-zero, will have the same sign
as @var{x}.
When @var{x} and @var{y} are integers, these operators are equivalent to
the R5RS integer-only operators @code{quotient} and @code{remainder}.
@lisp
(truncate-quotient 123 10) @result{} 12
(truncate-remainder 123 10) @result{} 3
(truncate/ 123 10) @result{} 12 and 3
(truncate/ 123 -10) @result{} -12 and 3
(truncate/ -123 10) @result{} -12 and -3
(truncate/ -123 -10) @result{} 12 and -3
(truncate/ -123.2 -63.5) @result{} 1.0 and -59.7
(truncate/ 16/3 -10/7) @result{} -3 and 22/21
@end lisp
@end deftypefn
@deftypefn {Scheme Procedure} {} centered/ @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} centered-quotient @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} centered-remainder @var{x} @var{y}
@ -1313,11 +1412,56 @@ Note that these operators are equivalent to the R6RS operators
(centered/ 123 -10) @result{} -12 and 3
(centered/ -123 10) @result{} -12 and -3
(centered/ -123 -10) @result{} 12 and -3
(centered/ 125 10) @result{} 13 and -5
(centered/ 127 10) @result{} 13 and -3
(centered/ 135 10) @result{} 14 and -5
(centered/ -123.2 -63.5) @result{} 2.0 and 3.8
(centered/ 16/3 -10/7) @result{} -4 and -8/21
@end lisp
@end deftypefn
@deftypefn {Scheme Procedure} {} round/ @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} round-quotient @var{x} @var{y}
@deftypefnx {Scheme Procedure} {} round-remainder @var{x} @var{y}
@deftypefnx {C Function} void scm_round_divide (SCM @var{x}, SCM @var{y}, SCM *@var{q}, SCM *@var{r})
@deftypefnx {C Function} SCM scm_round_quotient (@var{x}, @var{y})
@deftypefnx {C Function} SCM scm_round_remainder (@var{x}, @var{y})
These procedures accept two real numbers @var{x} and @var{y}, where the
divisor @var{y} must be non-zero. @code{round-quotient} returns the
integer @var{q} and @code{round-remainder} returns the real number
@var{r} such that @math{@var{x} = @var{q}*@var{y} + @var{r}} and
@var{q} is @math{@var{x}/@var{y}} rounded to the nearest integer,
with ties going to the nearest even integer. @code{round/}
returns both @var{q} and @var{r}, and is more efficient than computing
each separately.
Note that @code{round/} and @code{centered/} are almost equivalent, but
their behavior differs when @math{@var{x}/@var{y}} lies exactly half-way
between two integers. In this case, @code{round/} chooses the nearest
even integer, whereas @code{centered/} chooses in such a way to satisfy
the constraint @math{-|@var{y}/2| <= @var{r} < |@var{y}/2|}, which
is stronger than the corresponding constraint for @code{round/},
@math{-|@var{y}/2| <= @var{r} <= |@var{y}/2|}. In particular,
when @var{x} and @var{y} are integers, the number of possible remainders
returned by @code{centered/} is @math{|@var{y}|}, whereas the number of
possible remainders returned by @code{round/} is @math{|@var{y}|+1} when
@var{y} is even.
@lisp
(round-quotient 123 10) @result{} 12
(round-remainder 123 10) @result{} 3
(round/ 123 10) @result{} 12 and 3
(round/ 123 -10) @result{} -12 and 3
(round/ -123 10) @result{} -12 and -3
(round/ -123 -10) @result{} 12 and -3
(round/ 125 10) @result{} 12 and 5
(round/ 127 10) @result{} 13 and -3
(round/ 135 10) @result{} 14 and -5
(round/ -123.2 -63.5) @result{} 2.0 and 3.8
(round/ 16/3 -10/7) @result{} -4 and -8/21
@end lisp
@end deftypefn
@node Scientific
@subsubsection Scientific Functions

File diff suppressed because it is too large Load diff

View file

@ -181,9 +181,21 @@ SCM_API SCM scm_modulo (SCM x, SCM y);
SCM_API void scm_euclidean_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_euclidean_quotient (SCM x, SCM y);
SCM_API SCM scm_euclidean_remainder (SCM x, SCM y);
SCM_API void scm_floor_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_floor_quotient (SCM x, SCM y);
SCM_API SCM scm_floor_remainder (SCM x, SCM y);
SCM_API void scm_ceiling_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_ceiling_quotient (SCM x, SCM y);
SCM_API SCM scm_ceiling_remainder (SCM x, SCM y);
SCM_API void scm_truncate_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_truncate_quotient (SCM x, SCM y);
SCM_API SCM scm_truncate_remainder (SCM x, SCM y);
SCM_API void scm_centered_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_centered_quotient (SCM x, SCM y);
SCM_API SCM scm_centered_remainder (SCM x, SCM y);
SCM_API void scm_round_divide (SCM x, SCM y, SCM *q, SCM *r);
SCM_API SCM scm_round_quotient (SCM x, SCM y);
SCM_API SCM scm_round_remainder (SCM x, SCM y);
SCM_API SCM scm_gcd (SCM x, SCM y);
SCM_API SCM scm_lcm (SCM n1, SCM n2);
SCM_API SCM scm_logand (SCM n1, SCM n2);
@ -200,7 +212,11 @@ SCM_API SCM scm_logcount (SCM n);
SCM_API SCM scm_integer_length (SCM n);
SCM_INTERNAL SCM scm_i_euclidean_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_floor_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_ceiling_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_truncate_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_centered_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_round_divide (SCM x, SCM y);
SCM_INTERNAL SCM scm_i_gcd (SCM x, SCM y, SCM rest);
SCM_INTERNAL SCM scm_i_lcm (SCM x, SCM y, SCM rest);

View file

@ -4148,6 +4148,42 @@
(test-within-range? 0 <= r < (abs y)))
(test-eqv? q (/ x y)))))
(define (valid-floor-answer? x y q r)
(and (eq? (exact? q)
(exact? r)
(and (exact? x) (exact? y)))
(test-eqv? r (- x (* q y)))
(if (and (finite? x) (finite? y))
(and (integer? q)
(if (> y 0)
(test-within-range? 0 <= r < y)
(test-within-range? y < r <= 0)))
(test-eqv? q (/ x y)))))
(define (valid-ceiling-answer? x y q r)
(and (eq? (exact? q)
(exact? r)
(and (exact? x) (exact? y)))
(test-eqv? r (- x (* q y)))
(if (and (finite? x) (finite? y))
(and (integer? q)
(if (> y 0)
(test-within-range? (- y) < r <= 0)
(test-within-range? 0 <= r < (- y))))
(test-eqv? q (/ x y)))))
(define (valid-truncate-answer? x y q r)
(and (eq? (exact? q)
(exact? r)
(and (exact? x) (exact? y)))
(test-eqv? r (- x (* q y)))
(if (and (finite? x) (finite? y))
(and (integer? q)
(if (> x 0)
(test-within-range? 0 <= r < (abs y))
(test-within-range? (- (abs y)) < r <= 0)))
(test-eqv? q (/ x y)))))
(define (valid-centered-answer? x y q r)
(and (eq? (exact? q)
(exact? r)
@ -4159,6 +4195,19 @@
(* -1/2 (abs y)) <= r < (* +1/2 (abs y))))
(test-eqv? q (/ x y)))))
(define (valid-round-answer? x y q r)
(and (eq? (exact? q)
(exact? r)
(and (exact? x) (exact? y)))
(test-eqv? r (- x (* q y)))
(if (and (finite? x) (finite? y))
(and (integer? q)
(let ((ay/2 (/ (abs y) 2)))
(if (even? q)
(test-within-range? (- ay/2) <= r <= ay/2)
(test-within-range? (- ay/2) < r < ay/2))))
(test-eqv? q (/ x y)))))
(define (for lsts f) (apply for-each f lsts))
(define big (expt 10 (1+ (inexact->exact (ceiling (log10 fixnum-max))))))
@ -4284,8 +4333,32 @@
euclidean-remainder
valid-euclidean-answer?))
(with-test-prefix "floor/"
(run-division-tests floor/
floor-quotient
floor-remainder
valid-floor-answer?))
(with-test-prefix "ceiling/"
(run-division-tests ceiling/
ceiling-quotient
ceiling-remainder
valid-ceiling-answer?))
(with-test-prefix "truncate/"
(run-division-tests truncate/
truncate-quotient
truncate-remainder
valid-truncate-answer?))
(with-test-prefix "centered/"
(run-division-tests centered/
centered-quotient
centered-remainder
valid-centered-answer?)))
valid-centered-answer?))
(with-test-prefix "round/"
(run-division-tests round/
round-quotient
round-remainder
valid-round-answer?)))