[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Guile-commits] 41/69: Simplify implementation of min, max
From: |
Andy Wingo |
Subject: |
[Guile-commits] 41/69: Simplify implementation of min, max |
Date: |
Fri, 7 Jan 2022 08:27:12 -0500 (EST) |
wingo pushed a commit to branch wip-inline-digits
in repository guile.
commit 38942c0015f9315bf4685cefbbec146305fec2a4
Author: Andy Wingo <wingo@pobox.com>
AuthorDate: Tue Jan 4 14:42:13 2022 +0100
Simplify implementation of min, max
* libguile/numbers.c (scm_max, scm_min): Lean more on scm_is_less_than.
---
libguile/numbers.c | 330 ++++++++---------------------------------------------
1 file changed, 47 insertions(+), 283 deletions(-)
diff --git a/libguile/numbers.c b/libguile/numbers.c
index 54d2f0a51..60421fcb0 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5025,172 +5025,43 @@ SCM_PRIMITIVE_GENERIC (scm_i_max, "max", 0, 2, 1,
}
#undef FUNC_NAME
-#define s_max s_scm_i_max
-#define g_max g_scm_i_max
-
SCM
scm_max (SCM x, SCM y)
{
if (SCM_UNBNDP (y))
{
if (SCM_UNBNDP (x))
- return scm_wta_dispatch_0 (g_max, s_max);
- else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) ||
SCM_FRACTIONP(x))
+ return scm_wta_dispatch_0 (g_scm_i_max, s_scm_i_max);
+ else if (scm_is_real (x))
return x;
else
- return scm_wta_dispatch_1 (g_max, x, SCM_ARG1, s_max);
+ return scm_wta_dispatch_1 (g_scm_i_max, x, SCM_ARG1, s_scm_i_max);
}
- if (SCM_I_INUMP (x))
- {
- scm_t_inum xx = SCM_I_INUM (x);
- if (SCM_I_INUMP (y))
- {
- scm_t_inum yy = SCM_I_INUM (y);
- return (xx < yy) ? y : x;
- }
- else if (SCM_BIGP (y))
- {
- int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
- scm_remember_upto_here_1 (y);
- return (sgn < 0) ? x : y;
- }
- else if (SCM_REALP (y))
- {
- double xxd = xx;
- double yyd = SCM_REAL_VALUE (y);
-
- if (xxd > yyd)
- return scm_i_from_double (xxd);
- /* If y is a NaN, then "==" is false and we return the NaN */
- else if (SCM_LIKELY (!(xxd == yyd)))
- return y;
- /* Handle signed zeroes properly */
- else if (xx == 0)
- return flo0;
- else
- return y;
- }
- else if (SCM_FRACTIONP (y))
- {
- use_less:
- return (scm_is_false (scm_less_p (x, y)) ? x : y);
- }
- else
- return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
- }
- else if (SCM_BIGP (x))
- {
- if (SCM_I_INUMP (y))
- {
- int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
- scm_remember_upto_here_1 (x);
- return (sgn < 0) ? y : x;
- }
- else if (SCM_BIGP (y))
- {
- int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
- scm_remember_upto_here_2 (x, y);
- return (cmp > 0) ? x : y;
- }
- else if (SCM_REALP (y))
- {
- /* if y==NaN then xx>yy is false, so we return the NaN y */
- double xx, yy;
- big_real:
- xx = scm_i_big2dbl (x);
- yy = SCM_REAL_VALUE (y);
- return (xx > yy ? scm_i_from_double (xx) : y);
- }
- else if (SCM_FRACTIONP (y))
- {
- goto use_less;
- }
- else
- return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
- }
- else if (SCM_REALP (x))
- {
- if (SCM_I_INUMP (y))
- {
- scm_t_inum yy = SCM_I_INUM (y);
- double xxd = SCM_REAL_VALUE (x);
- double yyd = yy;
+ if (!scm_is_real (x))
+ return scm_wta_dispatch_2 (g_scm_i_max, x, y, SCM_ARG1, s_scm_i_max);
+ if (!scm_is_real (y))
+ return scm_wta_dispatch_2 (g_scm_i_max, x, y, SCM_ARG2, s_scm_i_max);
- if (yyd > xxd)
- return scm_i_from_double (yyd);
- /* If x is a NaN, then "==" is false and we return the NaN */
- else if (SCM_LIKELY (!(xxd == yyd)))
- return x;
- /* Handle signed zeroes properly */
- else if (yy == 0)
- return flo0;
- else
- return x;
- }
- else if (SCM_BIGP (y))
- {
- SCM_SWAP (x, y);
- goto big_real;
- }
- else if (SCM_REALP (y))
- {
- double xx = SCM_REAL_VALUE (x);
- double yy = SCM_REAL_VALUE (y);
+ if (scm_is_exact (x) && scm_is_exact (y))
+ return scm_is_less_than (x, y) ? y : x;
- /* For purposes of max: nan > +inf.0 > everything else,
- per the R6RS errata */
- if (xx > yy)
- return x;
- else if (SCM_LIKELY (xx < yy))
- return y;
- /* If neither (xx > yy) nor (xx < yy), then
- either they're equal or one is a NaN */
- else if (SCM_UNLIKELY (xx != yy))
- return (xx != xx) ? x : y; /* Return the NaN */
- /* xx == yy, but handle signed zeroes properly */
- else if (copysign (1.0, yy) < 0.0)
- return x;
- else
- return y;
- }
- else if (SCM_FRACTIONP (y))
- {
- double yy = scm_i_fraction2double (y);
- double xx = SCM_REAL_VALUE (x);
- return (xx < yy) ? scm_i_from_double (yy) : x;
- }
- else
- return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
- }
- else if (SCM_FRACTIONP (x))
- {
- if (SCM_I_INUMP (y))
- {
- goto use_less;
- }
- else if (SCM_BIGP (y))
- {
- goto use_less;
- }
- else if (SCM_REALP (y))
- {
- double xx = scm_i_fraction2double (x);
- /* if y==NaN then ">" is false, so we return the NaN y */
- return (xx > SCM_REAL_VALUE (y)) ? scm_i_from_double (xx) : y;
- }
- else if (SCM_FRACTIONP (y))
- {
- goto use_less;
- }
- else
- return scm_wta_dispatch_2 (g_max, x, y, SCM_ARGn, s_max);
- }
- else
- return scm_wta_dispatch_2 (g_max, x, y, SCM_ARG1, s_max);
+ x = SCM_REALP (x) ? x : scm_exact_to_inexact (x);
+ y = SCM_REALP (y) ? y : scm_exact_to_inexact (y);
+ double xx = SCM_REAL_VALUE (x);
+ double yy = SCM_REAL_VALUE (y);
+ if (isnan (xx))
+ return x;
+ if (isnan (yy))
+ return y;
+ if (xx < yy)
+ return y;
+ if (xx > yy)
+ return x;
+ // Distinguish -0.0 from 0.0.
+ return (copysign (1.0, xx) < 0) ? y : x;
}
-
SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
(SCM x, SCM y, SCM rest),
"Return the minimum of all parameter values.")
@@ -5205,148 +5076,41 @@ SCM_PRIMITIVE_GENERIC (scm_i_min, "min", 0, 2, 1,
}
#undef FUNC_NAME
-#define s_min s_scm_i_min
-#define g_min g_scm_i_min
-
SCM
scm_min (SCM x, SCM y)
{
if (SCM_UNBNDP (y))
{
if (SCM_UNBNDP (x))
- return scm_wta_dispatch_0 (g_min, s_min);
- else if (SCM_I_INUMP(x) || SCM_BIGP(x) || SCM_REALP(x) ||
SCM_FRACTIONP(x))
+ return scm_wta_dispatch_0 (g_scm_i_min, s_scm_i_min);
+ else if (scm_is_real (x))
return x;
else
- return scm_wta_dispatch_1 (g_min, x, SCM_ARG1, s_min);
+ return scm_wta_dispatch_1 (g_scm_i_min, x, SCM_ARG1, s_scm_i_min);
}
- if (SCM_I_INUMP (x))
- {
- scm_t_inum xx = SCM_I_INUM (x);
- if (SCM_I_INUMP (y))
- {
- scm_t_inum yy = SCM_I_INUM (y);
- return (xx < yy) ? x : y;
- }
- else if (SCM_BIGP (y))
- {
- int sgn = mpz_sgn (SCM_I_BIG_MPZ (y));
- scm_remember_upto_here_1 (y);
- return (sgn < 0) ? y : x;
- }
- else if (SCM_REALP (y))
- {
- double z = xx;
- /* if y==NaN then "<" is false and we return NaN */
- return (z < SCM_REAL_VALUE (y)) ? scm_i_from_double (z) : y;
- }
- else if (SCM_FRACTIONP (y))
- {
- use_less:
- return (scm_is_false (scm_less_p (x, y)) ? y : x);
- }
- else
- return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
- }
- else if (SCM_BIGP (x))
- {
- if (SCM_I_INUMP (y))
- {
- int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
- scm_remember_upto_here_1 (x);
- return (sgn < 0) ? x : y;
- }
- else if (SCM_BIGP (y))
- {
- int cmp = mpz_cmp (SCM_I_BIG_MPZ (x), SCM_I_BIG_MPZ (y));
- scm_remember_upto_here_2 (x, y);
- return (cmp > 0) ? y : x;
- }
- else if (SCM_REALP (y))
- {
- /* if y==NaN then xx<yy is false, so we return the NaN y */
- double xx, yy;
- big_real:
- xx = scm_i_big2dbl (x);
- yy = SCM_REAL_VALUE (y);
- return (xx < yy ? scm_i_from_double (xx) : y);
- }
- else if (SCM_FRACTIONP (y))
- {
- goto use_less;
- }
- else
- return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
- }
- else if (SCM_REALP (x))
- {
- if (SCM_I_INUMP (y))
- {
- double z = SCM_I_INUM (y);
- /* if x==NaN then "<" is false and we return NaN */
- return (z < SCM_REAL_VALUE (x)) ? scm_i_from_double (z) : x;
- }
- else if (SCM_BIGP (y))
- {
- SCM_SWAP (x, y);
- goto big_real;
- }
- else if (SCM_REALP (y))
- {
- double xx = SCM_REAL_VALUE (x);
- double yy = SCM_REAL_VALUE (y);
+ if (!scm_is_real (x))
+ return scm_wta_dispatch_2 (g_scm_i_min, x, y, SCM_ARG1, s_scm_i_min);
+ if (!scm_is_real (y))
+ return scm_wta_dispatch_2 (g_scm_i_min, x, y, SCM_ARG2, s_scm_i_min);
- /* For purposes of min: nan < -inf.0 < everything else,
- per the R6RS errata */
- if (xx < yy)
- return x;
- else if (SCM_LIKELY (xx > yy))
- return y;
- /* If neither (xx < yy) nor (xx > yy), then
- either they're equal or one is a NaN */
- else if (SCM_UNLIKELY (xx != yy))
- return (xx != xx) ? x : y; /* Return the NaN */
- /* xx == yy, but handle signed zeroes properly */
- else if (copysign (1.0, xx) < 0.0)
- return x;
- else
- return y;
- }
- else if (SCM_FRACTIONP (y))
- {
- double yy = scm_i_fraction2double (y);
- double xx = SCM_REAL_VALUE (x);
- return (yy < xx) ? scm_i_from_double (yy) : x;
- }
- else
- return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
- }
- else if (SCM_FRACTIONP (x))
- {
- if (SCM_I_INUMP (y))
- {
- goto use_less;
- }
- else if (SCM_BIGP (y))
- {
- goto use_less;
- }
- else if (SCM_REALP (y))
- {
- double xx = scm_i_fraction2double (x);
- /* if y==NaN then "<" is false, so we return the NaN y */
- return (xx < SCM_REAL_VALUE (y)) ? scm_i_from_double (xx) : y;
- }
- else if (SCM_FRACTIONP (y))
- {
- goto use_less;
- }
- else
- return scm_wta_dispatch_2 (g_min, x, y, SCM_ARGn, s_min);
- }
- else
- return scm_wta_dispatch_2 (g_min, x, y, SCM_ARG1, s_min);
+ if (scm_is_exact (x) && scm_is_exact (y))
+ return scm_is_less_than (x, y) ? x : y;
+
+ x = SCM_REALP (x) ? x : scm_exact_to_inexact (x);
+ y = SCM_REALP (y) ? y : scm_exact_to_inexact (y);
+ double xx = SCM_REAL_VALUE (x);
+ double yy = SCM_REAL_VALUE (y);
+ if (isnan (xx))
+ return x;
+ if (isnan (yy))
+ return y;
+ if (xx < yy)
+ return x;
+ if (xx > yy)
+ return y;
+ // Distinguish -0.0 from 0.0.
+ return (copysign (1.0, xx) < 0) ? x : y;
}
- [Guile-commits] 09/69: Implement ceiling-remainder with new integer lib, (continued)
- [Guile-commits] 09/69: Implement ceiling-remainder with new integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 22/69: Implement scm_logand with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 29/69: Reimplement integer-expt in Scheme, Andy Wingo, 2022/01/07
- [Guile-commits] 27/69: Implement scm_lognot with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 26/69: Implement scm_logbit_p with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 25/69: Implement scm_logtest with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 33/69: Integer library takes bignums via opaque struct pointer, Andy Wingo, 2022/01/07
- [Guile-commits] 37/69: Build scm_integer_p on scm_is_integer, not vice versa, Andy Wingo, 2022/01/07
- [Guile-commits] 36/69: Simplify scm_bigprint, Andy Wingo, 2022/01/07
- [Guile-commits] 38/69: Reimplement = on integer lib, clean up scm_num_eq_p, Andy Wingo, 2022/01/07
- [Guile-commits] 41/69: Simplify implementation of min, max,
Andy Wingo <=
- [Guile-commits] 46/69: Clean up scm_divide, Andy Wingo, 2022/01/07
- [Guile-commits] 48/69: Fix scm_integer_to_double_z to always round; clean ups, Andy Wingo, 2022/01/07
- [Guile-commits] 54/69: Remove unused conv-{u,}integer.i.c, Andy Wingo, 2022/01/07
- [Guile-commits] 58/69: Expose frexp from integers lib, Andy Wingo, 2022/01/07
- [Guile-commits] 18/69: Implement round-remainder with new integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 28/69: Implement scm_modulo_expt with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 21/69: Implement lcm with new integer lib, Andy Wingo, 2022/01/07
- [Guile-commits] 30/69: Implement scm_ash with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 32/69: Implement scm_logcount with new integer library, Andy Wingo, 2022/01/07
- [Guile-commits] 35/69: Implement integer-to-string with new integer library, Andy Wingo, 2022/01/07