1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-29 08:20:20 +02:00

* numbers.c (scm_make_ratio): Rewritten to have a simpler

structure.  Previously, not all cases with a negative denominator
were covered.
This commit is contained in:
Marius Vollmer 2003-11-19 05:12:08 +00:00
parent 0b0c8e3b4c
commit c60e130c97

View file

@ -325,11 +325,10 @@ static SCM scm_divide2real (SCM x, SCM y);
SCM
scm_make_ratio (SCM numerator, SCM denominator)
#define FUNC_NAME "make-ratio"
{
#if 0
return scm_divide2real(numerator, denominator);
#else
#define FUNC_NAME "make-ratio"
/* First make sure the arguments are proper.
*/
if (SCM_INUMP (denominator))
{
if (SCM_EQ_P (denominator, SCM_INUM0))
@ -342,6 +341,20 @@ scm_make_ratio (SCM numerator, SCM denominator)
if (!(SCM_BIGP(denominator)))
SCM_WRONG_TYPE_ARG (2, denominator);
}
if (!SCM_INUMP (numerator) && !SCM_BIGP (numerator))
SCM_WRONG_TYPE_ARG (1, numerator);
/* Then flip signs so that the denominator is positive.
*/
if (SCM_NFALSEP (scm_negative_p (denominator)))
{
numerator = scm_difference (numerator, SCM_UNDEFINED);
denominator = scm_difference (denominator, SCM_UNDEFINED);
}
/* Now consider for each of the four fixnum/bignum combinations
whether the rational number is really an integer.
*/
if (SCM_INUMP (numerator))
{
if (SCM_EQ_P (numerator, SCM_INUM0))
@ -355,58 +368,33 @@ scm_make_ratio (SCM numerator, SCM denominator)
return SCM_MAKINUM(1);
if ((x % y) == 0)
return SCM_MAKINUM (x / y);
if (y < 0)
return scm_double_cell (scm_tc16_fraction, (scm_t_bits)SCM_MAKINUM(-x), (scm_t_bits)SCM_MAKINUM(-y), 0);
else return scm_double_cell (scm_tc16_fraction, (scm_t_bits)numerator, (scm_t_bits)denominator, 0);
}
}
else if (SCM_BIGP (numerator))
{
if (SCM_INUMP (denominator))
{
long yy = SCM_INUM (denominator);
if (mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), yy))
return scm_divide (numerator, denominator);
}
else
{
/* I assume bignums are actually big, so here there's no point in looking for a integer */
int sgn = mpz_sgn (SCM_I_BIG_MPZ (denominator));
if (sgn < 0) /* if denominator negative, flip signs */
return scm_double_cell (scm_tc16_fraction,
(scm_t_bits)scm_difference (numerator, SCM_UNDEFINED),
(scm_t_bits)scm_difference (denominator, SCM_UNDEFINED),
0);
else return scm_double_cell (scm_tc16_fraction, (scm_t_bits)numerator, (scm_t_bits)denominator, 0);
if (SCM_EQ_P (numerator, denominator))
return SCM_MAKINUM(1);
if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
SCM_I_BIG_MPZ (denominator)))
return scm_divide(numerator, denominator);
}
}
/* should this use SCM_UNPACK for the bignums? */
}
}
else
{
if (SCM_BIGP (numerator))
{
/* can't use scm_divide to find integer here */
if (SCM_INUMP (denominator))
{
long yy = SCM_INUM (denominator);
long abs_yy = yy < 0 ? -yy : yy;
int divisible_p = mpz_divisible_ui_p (SCM_I_BIG_MPZ (numerator), abs_yy);
if (divisible_p)
return scm_divide(numerator, denominator);
else return scm_double_cell (scm_tc16_fraction, (scm_t_bits)numerator, (scm_t_bits)denominator, 0);
}
else
{
/* both are bignums */
if (SCM_EQ_P (numerator, denominator))
return SCM_MAKINUM(1);
if (mpz_divisible_p (SCM_I_BIG_MPZ (numerator),
SCM_I_BIG_MPZ (denominator)))
return scm_divide(numerator, denominator);
else
return scm_double_cell (scm_tc16_fraction,
(scm_t_bits)numerator,
(scm_t_bits)denominator, 0);
}
}
else SCM_WRONG_TYPE_ARG (1, numerator);
}
return SCM_BOOL_F; /* won't happen */
#undef FUNC_NAME
#endif
/* No, it's a proper fraction.
*/
return scm_double_cell (scm_tc16_fraction,
SCM_UNPACK (numerator),
SCM_UNPACK (denominator), 0);
}
#undef FUNC_NAME
static void scm_i_fraction_reduce (SCM z)
{