unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
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

  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).