From: Kevin Ryde <user42@zip.com.au>
Cc: Bill Schottstaedt <bil@ccrma.stanford.edu>, guile-devel@gnu.org
Subject: Re: ratio implementation
Date: Wed, 15 Oct 2003 08:56:05 +1000 [thread overview]
Message-ID: <87r81fzawq.fsf@zip.com.au> (raw)
In-Reply-To: <ljr81gyovc.fsf@troy.dt.e-technik.uni-dortmund.de> (Marius Vollmer's message of "Tue, 14 Oct 2003 14:39:51 +0200")
[-- Attachment #1: Type: text/plain, Size: 819 bytes --]
Marius Vollmer <marius.vollmer@uni-dortmund.de> writes:
>
> (sqrt 4) => 2 (exact)
>
> I'm not sure whether exact square roots are imortant: they will only
> be useful when both the numerator and denominator are squares of
> integers and those pairs will be rare, I'd say.
I'd wondered if some sort of isqrt or isqrt+remainder would be of more
value to those wanting integer roots. (Though I'm aware r5rs says
exact results for exact perfect squares is desirable.)
> We could use GMP for
> computing bignum square roots...
Rob mentioned this to me at one stage, I actually started on an
attempt at it. Code below, which might sort of work, maybe.
One concern though is to ensure the root calculated is the same for a
"double" input (which uses sqrt()) as compared to some bignum root
(using gmp + conversions).
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sqrt.c --]
[-- Type: text/x-csrc, Size: 3815 bytes --]
/* sqrt and mpz_sqrt+mpz_get_d don't round the same
*/
#include <float.h>
#ifndef DBL_MANT_DIG
#define DBL_MANT_DIG 53 /* by default assume IEEE double */
#endif
SCM scm_sqrt (SCM x);
SCM_DEFINE (scm_sqrt, "sqrt", 1, 0, 0,
(SCM x),
"Return the square root of @var{x}.\n"
"\n"
"If @var{x} is exact and a perfect square then the return is\n"
"exact, otherwise the return is inexact (either real or\n"
"complex).")
#define FUNC_NAME s_scm_sqrt
{
double root_d;
SCM root;
int neg;
if (SCM_INUMP (x))
{
long x_l = SCM_INUM (x);
neg = (x_l < 0);
x_l = (neg ? -x_l : x_l);
/* inums which fit the mantissa of a double are handled with sqrt().
On 32-bit systems inums always fit, but on 64-bit systems we need
to check. */
#if SCM_I_FIXNUM_BIT > DBL_MANT_DIG
if ((unsigned long) x_l < (1UL << DBL_MANT_DIG))
#endif
{
root_d = sqrt ((double) x_l);
if (! neg && floor (root_d) == root_d)
{
/* perfect square, return as inum */
long root_l = (long) root_d;
return SCM_MAKINUM (neg ? -root_l : root_l);
}
goto inexact;
}
/* inums which don't fit the mantissa of a double are handled with the
bignum code, to ensure full accuracy in the result */
root = scm_i_mkbig ();
mpz_set_si (SCM_I_BIG_MPZ (root), x_l);
x = root;
goto big;
}
else if (SCM_BIGP (x))
{
int scale;
root = scm_i_mkbig ();
big:
if (mpz_perfect_square_p (SCM_I_BIG_MPZ (x)))
{
/* Perfect square, return as exact.
Enhancement: mpz_perfect_square_p already calculates the root
when proving squareness, it'd be nice to have some sort of
"square root if perfect square" function. */
mpz_sqrt (SCM_I_BIG_MPZ (root), SCM_I_BIG_MPZ (x));
scm_remember_upto_here_1 (x);
return scm_i_normbig (root);
}
neg = (mpz_sgn (SCM_I_BIG_MPZ (x)) < 0);
mpz_abs (SCM_I_BIG_MPZ (root), SCM_I_BIG_MPZ (x));
scm_remember_upto_here_1 (x);
/* We need DBL_MANT_DIG bits of root, which means twice that of
operand. If we've got less, then pad with zeros, effectively
generating fractional bits for the root. If we've got more, then
truncate so as to save work in mpz_sqrt. */
scale = ((long) mpz_sizeinbase (SCM_I_BIG_MPZ (root), 2)
- 1 - 2*DBL_MANT_DIG) / 2;
if (scale > 0)
mpz_tdiv_q_2exp (SCM_I_BIG_MPZ (root), SCM_I_BIG_MPZ (root),
2 * scale);
else
mpz_mul_2exp (SCM_I_BIG_MPZ (root), SCM_I_BIG_MPZ (root),
- 2 * scale);
mpz_sqrt (SCM_I_BIG_MPZ (root), SCM_I_BIG_MPZ (root));
root_d = ldexp (mpz_get_d (SCM_I_BIG_MPZ (root)), scale);
scm_remember_upto_here_1 (root);
goto inexact;
}
else if (SCM_REALP (x))
{
double x_d = SCM_REAL_VALUE (x);
neg = (x_d < 0.0);
root_d = sqrt (fabs (x_d));
inexact:
if (neg)
return scm_make_complex (0.0, root_d);
else
return scm_make_real (root_d);
}
else if (SCM_COMPLEXP (x))
{
/* sqrt(x) = (make-polar (sqrt (magnitude x)) (/ (angle x) 2))
ENHANCE-ME: Use csqrt() when available. */
double re = SCM_COMPLEX_REAL (x);
double im = SCM_COMPLEX_IMAG (x);
double mag = sqrt (hypot (re, im));
double ang = atan2 (re, im) / 2.0;
double s, c;
#if HAVE_SINCOS
sincos (ang, &s, &c);
#else
s = sin (ang);
c = cos (ang);
#endif
return scm_make_complex (mag * c, mag * s);
}
else
SCM_WRONG_TYPE_ARG (SCM_ARG1, x);
}
#undef FUNC_NAME
[-- Attachment #3: Type: text/plain, Size: 142 bytes --]
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel
next prev parent reply other threads:[~2003-10-14 22:56 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-07-28 11:24 ratio implementation Bill Schottstaedt
2003-07-28 12:08 ` Han-Wen Nienhuys
2003-07-29 0:41 ` Kevin Ryde
2003-07-29 11:57 ` Bill Schottstaedt
2003-07-30 22:42 ` Kevin Ryde
2003-09-15 10:35 ` Marius Vollmer
2003-09-15 16:19 ` Rob Browning
2003-09-15 22:06 ` Dirk Herrmann
2003-09-15 22:59 ` Kevin Ryde
2003-09-16 11:39 ` Bill Schottstaedt
2003-09-16 21:36 ` Rob Browning
2003-09-18 21:09 ` Dirk Herrmann
2003-10-07 15:26 ` Marius Vollmer
2003-10-13 10:58 ` Bill Schottstaedt
2003-10-14 8:57 ` Marius Vollmer
2004-02-18 14:25 ` fractions.test Bill Schottstaedt
2003-10-14 12:39 ` ratio implementation Marius Vollmer
2003-10-14 22:56 ` Kevin Ryde [this message]
2003-10-14 13:03 ` Marius Vollmer
2003-10-14 23:37 ` Kevin Ryde
2003-10-16 11:49 ` Bill Schottstaedt
2003-10-17 10:09 ` Marius Vollmer
2003-10-17 11:47 ` Bill Schottstaedt
2003-10-17 15:04 ` Rob Browning
2003-10-18 0:45 ` Kevin Ryde
2003-10-15 12:57 ` Bill Schottstaedt
2003-10-17 10:20 ` Marius Vollmer
2003-10-17 15:14 ` Rob Browning
2003-10-17 15:42 ` Marius Vollmer
2003-10-14 23:01 ` Kevin Ryde
2003-10-18 0:55 ` ash using shifts (was: ratio implementation) Kevin Ryde
2003-10-07 15:24 ` ratio implementation Marius Vollmer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87r81fzawq.fsf@zip.com.au \
--to=user42@zip.com.au \
--cc=bil@ccrma.stanford.edu \
--cc=guile-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).