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:
parent
03ddd15bae
commit
8f9da3406b
5 changed files with 2451 additions and 3 deletions
28
NEWS
28
NEWS
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
2187
libguile/numbers.c
2187
libguile/numbers.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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?)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue