Re: fix for expt bug

2010-11-21 Thread Ludovic Courtès
Hi,

Andy Wingo wi...@pobox.com writes:

 There is also Mike Sperber's paper a few years ago about Scheme's
 numeric tower being borked.

 Anyway, just to say that you're in good company :)

Heh, good to know, and interesting link!

Ludo’.




Re: fix for expt bug

2010-11-20 Thread Andy Wingo
Hi,

On Mon 08 Nov 2010 22:08, l...@gnu.org (Ludovic Courtès) writes:

 Mark H Weaver m...@netris.org writes:

 No, (integer? 3.0) returns #t, as it should, according to R5RS.
 R5RS's description of integer? gives this precise example, and
 guile's implementation agrees.

 Damn, I had never realized that, shame on me.

Bill Schottstaedt has a nice rant on
https://ccrma.stanford.edu/software/snd/snd/s7.html. I think all of his
examples are taken from Guile...

I can't find the right tone for this section; this is the 400-th
revision; I wish I were a better writer! I think the exact/inexact
distinction in Scheme is confused and useless, and leads to verbose
and buggy code. In some Schemes, rational means could possibly be
expressed equally well as a ratio (floats are approximations). In
s7 it's: is actually expressed as a ratio (or an integer of
course); otherwise rational? is the same as real?:

(not-s7-scheme) (rational? (sqrt 2))
#t

As I understand it, inexact originally meant floating point, and
exact meant integer or ratio of integers. But words have a life of
their own. 0.0 somehow became an inexact integer (although it can
be represented exactly in floating point). +inf.0 must be an integer
— its fractional part is explicitly zero! But +nan.0... And then
there's:

(not-s7-scheme) (integer? 9007199254740993.1)
#t

When does this matter? I often need to index into a vector, but the
index is a float (a real in Scheme-speak: its fractional part can
be non-zero). In one scheme:

(not-s7-scheme) (vector-ref #(0) (floor 0.1))
ERROR: Wrong type (expecting exact integer): 0.0   ; [why?  it's probably 
a programmer mistake!]

Not to worry, I'll use inexact-exact:

(not-s7-scheme) (inexact-exact 0.1)  ; [why? floats are 
ratios!]
3602879701896397/36028797018963968

So I end up using the verbose (floor (inexact-exact ...))
everywhere, and even then I have no guarantee that I'll get a legal
vector index. When I started work on s7, I thought perhaps exact
could mean is represented exactly in the computer. We'd have
integers and ratios exact; reals and complex exact if they are
exactly represented in the current floating point
implementation. 0.0 and 0.5 might be exact if the printout isn't
misleading, and 0.1 is inexact. integer? and friends would refer
instead to the programmer's point of view. That is, if the
programmer uses 1 or if the thing prints as 1, it is the integer 1,
whereas 1.0 means floating point (not integer!). And to keep
exactness in view, we'd have to monitor which operations introduce
inexactness — a kind of interval arithmetic. But then what would
inexact-exact do? If we discard the exact/inexact distinction, we
can maintain backwards compatibility via:

(define exact? rational?)
(define (inexact? x) (not (rational? x)))
(define inexact-exact rationalize) ; or floor
(define (exact-inexact x) (* x 1.0))

There is also Mike Sperber's paper a few years ago about Scheme's
numeric tower being borked.

Anyway, just to say that you're in good company :)

Andy
-- 
http://wingolog.org/



Re: fix for expt bug

2010-11-08 Thread Ludovic Courtès
Hi Mark!

Mark H Weaver m...@netris.org writes:

 No, (integer? 3.0) returns #t, as it should, according to R5RS.
 R5RS's description of integer? gives this precise example, and
 guile's implementation agrees.

Damn, I had never realized that, shame on me.

Ludo’.




Re: fix for expt bug

2010-11-04 Thread Mark H Weaver
l...@gnu.org (Ludovic Courtès) writes:
 I just realized that there is a better way to fix these bugs.  We don't
 need a new top-level case in expt after all.  Instead, we generalize the
 scm_integer_expt case to support inexact integer exponents.

 You mean “inexact number”, right?

No, I meant inexact integer, for example 3.0.

 However, an integer is necessarily an exact number,

No, (integer? 3.0) returns #t, as it should, according to R5RS.
R5RS's description of integer? gives this precise example, and
guile's implementation agrees.

 So I suspect that your patch doesn’t work because ‘inexact-exact’
 returns something that’s obviously not necessarily an integer:

I'm only talking about inexact integers such as 3.0, so that

  (expt 2 3.0) == (integer-expt 2.0 3) == 8.0

However, I have since realized that it is not enough to convert the base
to inexact; I must also convert integer-expt's result to inexact,
because there is one case where making the base inexact is not enough:

  (expt 3 0.0) == (integer-expt 3.0 0) == 1

Though (expt 3 0.0) should reduce to 1.0.  So the code needs to coerce
the result of integer-expt to inexact.

I am working on a patch to fix these and some other problems.

Mark



Re: fix for expt bug

2010-11-03 Thread Ramakrishnan Muthukrishnan
Thanks again, Mark and Ludovic.

Attached is an updated patch.

thanks
-- 
  Ramakrishnan
From a1dd2da8562ddeb2052f2994ad0302bcc8d5d1a2 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan vu3...@gmail.com
Date: Sun, 31 Oct 2010 23:22:52 +0530
Subject: [PATCH] Adding a case for `expt' when base is negative.

* libguile/numbers.c (scm_expt): Add a case when base is a
  negative number. Also fix the bug for the case when exponent
  is an inexact number.

* test-suite/tests/numbers.test (expt): Add tests for the cases
  when base is an integer and exponent is an inexact number, base
  is an integer and exponent is a rational number, base and
  exponent are both inexact and so on.
---
 libguile/numbers.c|   18 +-
 test-suite/tests/numbers.test |   13 -
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index fbc6cc8..e4b03aa 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5445,12 +5445,28 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
 	Return @var{x} raised to the power of @var{y}.) 
 #define FUNC_NAME s_scm_expt
 {
-  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
+  if (scm_is_true (scm_exact_p (y))  scm_is_integer (y))
 return scm_integer_expt (x, y);
   else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
 }
+  else if (scm_is_real (x)  scm_is_integer (y)  (scm_to_double (x)  0))
+{
+  double result;
+
+  /* If base is negative, expt needs to find -x^n = (-1^n) * (x^n).
+ We find x^n and then if n is odd, we also multiply the result
+ with -1. These changes apply only for cases where n is an
+ integer.
+  */
+  result = pow (-scm_to_double (x), scm_to_double (y));
+
+  if (scm_is_true (scm_odd_p (y)))
+return scm_from_double (-result);
+  else
+return scm_from_double (result);
+}
   else
 return scm_exp (scm_product (scm_log (x), y));
 }
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 3c3e14f..97c58c9 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -2892,7 +2892,18 @@
   (pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
   (pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
   (pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
-  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
+  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
+  ;; tests for non zero values of base and exponent.
+  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
+  (pass-if (eqv-loosely? (* -2742638075.5 -2742638075.5)
+ (expt -2742638075.5 2)))
+  (pass-if (eqv-loosely? 4.0 (expt -2.0 2.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2.0 -3.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2 -3.0)))
+  (pass-if (eqv-loosely? 0.25 (expt 2.0 -2.0)))
+  (pass-if (eqv-loosely? +i (expt -1 0.5)))
+  (pass-if (eqv-loosely? +i (expt -1 1/2)))
+  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3
 
 ;;;
 ;;; asinh
-- 
1.7.2.3



Re: fix for expt bug

2010-11-03 Thread Mark H Weaver
Hi Ramakrishnan,

We're almost there, but you neglected one of the comments I made about
your previous patch.

 +  /* If base is negative, expt needs to find -x^n = (-1^n) * (x^n).
 + We find x^n and then if n is odd, we also multiply the result
 + with -1. These changes apply only for cases where n is an
 + integer.
 +  */

I repeat: In the equation above, -x^n parses as -(x^n), but it should be
(-x)^n.  Same problem with (-1^n).  Exponentiation has higher precedence
than negation.

The equation above should be:  (-x)^n = (-1)^n * x^n

Feel free to add more parentheses if you like, but the ones I have
included are essential and must not be removed.

Everything else looks good to me.

Thanks,
  Mark



Re: fix for expt bug

2010-11-03 Thread Mark H Weaver
Ramakrishnan and others,

I just realized that there is a better way to fix these bugs.  We don't
need a new top-level case in expt after all.  Instead, we generalize the
scm_integer_expt case to support inexact integer exponents.

Within that case, if the exponent is an inexact integer, then we make it
exact and make the base inexact, and then call scm_integer_expt.

I think this strategy is better for these reasons:

* Fewer top-level cases to check, thus making expt faster.
* More precise answers in the case of inexact integer exponents.
* More cases handled without spurious imaginary parts turning up, for
  example (expt +234234234.5i 4.0)
* Simpler code

Something like the code below.  (WARNING: UNTESTED!)

What do you all think?  Can you see any problems with this strategy?

Best,
 Mark


index fbc6cc8..f38772e 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5445,8 +5445,14 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
Return @var{x} raised to the power of @var{y}.) 
 #define FUNC_NAME s_scm_expt
 {
-  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
-return scm_integer_expt (x, y);
+  if (scm_is_integer (y))
+{
+  if (scm_is_true (scm_exact_p (y)))
+   return scm_integer_expt (x, y);
+  else
+   return scm_integer_expt (scm_exact_to_inexact(x),
+scm_inexact_to_exact(y));
+}
   else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));



Re: fix for expt bug

2010-11-03 Thread Ramakrishnan Muthukrishnan
On Wed, Nov 3, 2010 at 9:02 PM, Mark H Weaver m...@netris.org wrote:
 Hi Ramakrishnan,

 We're almost there, but you neglected one of the comments I made about
 your previous patch.

Sorry, I should pay more attention. :-(

Attaching the modified patch.
-- 
  Ramakrishnan
From 6cca8a66a3daedb551f4f80170966d74b6143ba6 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan vu3...@gmail.com
Date: Sun, 31 Oct 2010 23:22:52 +0530
Subject: [PATCH] Adding a case for `expt' when base is negative.

* libguile/numbers.c (scm_expt): Add a case when base is a
  negative number. Also fix the bug for the case when exponent
  is an inexact number.

* test-suite/tests/numbers.test (expt): Add tests for the cases
  when base is an integer and exponent is an inexact number, base
  is an integer and exponent is a rational number, base and
  exponent are both inexact and so on.
---
 libguile/numbers.c|   18 +-
 test-suite/tests/numbers.test |   13 -
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index fbc6cc8..f07f53d 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5445,12 +5445,28 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
 	Return @var{x} raised to the power of @var{y}.) 
 #define FUNC_NAME s_scm_expt
 {
-  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
+  if (scm_is_true (scm_exact_p (y))  scm_is_integer (y))
 return scm_integer_expt (x, y);
   else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
 }
+  else if (scm_is_real (x)  scm_is_integer (y)  (scm_to_double (x)  0))
+{
+  double result;
+
+  /* If base is negative, expt needs to find (-x)^n = (-1^n) * (x^n).
+ We find x^n and then if n is odd, we also multiply the result
+ with -1. These changes apply only for cases where n is an
+ integer.
+  */
+  result = pow (-scm_to_double (x), scm_to_double (y));
+
+  if (scm_is_true (scm_odd_p (y)))
+return scm_from_double (-result);
+  else
+return scm_from_double (result);
+}
   else
 return scm_exp (scm_product (scm_log (x), y));
 }
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 3c3e14f..97c58c9 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -2892,7 +2892,18 @@
   (pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
   (pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
   (pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
-  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
+  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
+  ;; tests for non zero values of base and exponent.
+  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
+  (pass-if (eqv-loosely? (* -2742638075.5 -2742638075.5)
+ (expt -2742638075.5 2)))
+  (pass-if (eqv-loosely? 4.0 (expt -2.0 2.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2.0 -3.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2 -3.0)))
+  (pass-if (eqv-loosely? 0.25 (expt 2.0 -2.0)))
+  (pass-if (eqv-loosely? +i (expt -1 0.5)))
+  (pass-if (eqv-loosely? +i (expt -1 1/2)))
+  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3
 
 ;;;
 ;;; asinh
-- 
1.7.2.3



Re: fix for expt bug

2010-11-03 Thread Ramakrishnan Muthukrishnan
On Wed, Nov 3, 2010 at 9:52 PM, Mark H Weaver m...@netris.org wrote:
 Ramakrishnan and others,

 I just realized that there is a better way to fix these bugs.  We don't
 need a new top-level case in expt after all.  Instead, we generalize the
 scm_integer_expt case to support inexact integer exponents.

 Within that case, if the exponent is an inexact integer, then we make it
 exact and make the base inexact, and then call scm_integer_expt.

Mark,

Why do we need to convert the base to inexact? is there any problem if
they are just as it is and we convert only the exponent to exact when
they are exact?

-- 
  Ramakrishnan



Re: fix for expt bug

2010-11-03 Thread Ramakrishnan Muthukrishnan
On Wed, Nov 3, 2010 at 11:23 PM, Ramakrishnan Muthukrishnan
vu3...@gmail.com wrote:
 On Wed, Nov 3, 2010 at 9:52 PM, Mark H Weaver m...@netris.org wrote:
 Ramakrishnan and others,

 I just realized that there is a better way to fix these bugs.  We don't
 need a new top-level case in expt after all.  Instead, we generalize the
 scm_integer_expt case to support inexact integer exponents.

 Within that case, if the exponent is an inexact integer, then we make it
 exact and make the base inexact, and then call scm_integer_expt.

 Mark,

 Why do we need to convert the base to inexact? is there any problem if
 they are just as it is and we convert only the exponent to exact when
 they are exact?

scheme@(guile-user) (integer-expt (exact-inexact 3/2) (inexact-exact 4.0))
$17 = 5.0625
scheme@(guile-user) (integer-expt 3/2 (inexact-exact 4.0))
$18 = 81/16
scheme@(guile-user) (integer-expt (exact-inexact 3/2) (inexact-exact 4.0))
$19 = 5.0625

We want an output representation in an inexact form. For that reason,
we would want to do exact to inexact conversion of base. Is that
correct?

Mark, I guess your patch solves the problem in a much more efficient way.

thanks
-- 
  Ramakrishnan



Re: fix for expt bug

2010-11-03 Thread Ludovic Courtès
Hi Mark,

Mark H Weaver m...@netris.org writes:

 I just realized that there is a better way to fix these bugs.  We don't
 need a new top-level case in expt after all.  Instead, we generalize the
 scm_integer_expt case to support inexact integer exponents.

You mean “inexact number”, right?

The doc for ‘integer-expt’ makes the same mistake:

  Return @var{n} raised to the power @var{k}.  @var{k} must be an\n
  exact integer, @var{n} can be any number.\n

However, an integer is necessarily an exact number, whereas the converse
isn’t true:

--8---cut here---start-8---
scheme@(guile-user) [25] (exact? 2/3)
$4 = #t
scheme@(guile-user) [25] (integer? 2/3)
$5 = #f
--8---cut here---end---8---

In actuality, ‘integer-expt’ expects K to be an integer (fixnum or
bignum).

So I suspect that your patch doesn’t work because ‘inexact-exact’
returns something that’s obviously not necessarily an integer:

--8---cut here---start-8---
scheme@(guile-user) [25] (inexact-exact 2.3)
$6 = 2589569785738035/1125899906842624
--8---cut here---end---8---

Does that make sense?

Thanks,
Ludo’.




Re: fix for expt bug

2010-11-02 Thread Mark H Weaver
Hi Ramakrishnan,

The code in your latest patch looks good to me, though the commit
message has some problems, and I'd add more test cases:

 * libguile/numbers.c: If base is negative, expt needs to find
   -x^n = (-1^n) * (|x|^n). We find x^n and then if n is odd, we
   also multiply the result with -1. These changes apply only for
   cases where n is an integer.

In the equation above, -x^n parses as -(x^n), but it should be (-x)^n.
Same problem with (-1^n).  Also, the absolute value should be removed.
It is superfluous for the case you are handling (x0), and for other
cases it is erroneous.

The equation above should be:  (-x)^n = (-1)^n * x^n

Also, I would add a couple more test cases:

* Test the case from Ludovic's original bug report:
  (expt -2742638075.5 2) should loosely equal
  7.52206361318235e18

* Test that (expt -1 0.5) is loosely equal to +i.
  (I believe this would have failed with your second patch)

Thanks,
  Mark



Re: fix for expt bug

2010-11-02 Thread Mark H Weaver
Hi Ramakrishnan,

I noticed one more problem with your commit message.  It should mention
the other included bug fix, for when the exponent is an inexact integer,
e.g. (expt 2 2.0).

   Thanks,
 Mark



Re: fix for expt bug

2010-11-01 Thread Ramakrishnan Muthukrishnan
I reworked the patch a bit as per Mark's comments. It takes care of
the sign part and handles integer power values properly. It also fixes
another bug with the current expt implementation where base is an
integer and the power value is not (eg: (expt 2 2.0) gives an error in
the current git master. The patch fixes this too.)

Also adds some test cases. Please review.

Thanks
Ramakrishnan
From 025bde78d4c199dee1d2857e913d69ce4d7c2e59 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan vu3...@gmail.com
Date: Sun, 31 Oct 2010 23:22:52 +0530
Subject: [PATCH] Fix for bug #31464. expt needs to treat negative bases specially.

* libguile/numbers.c: If base is negative, expt needs to find
  -x^n = (-1^n) * (|x|^n). We find x^n and then if n is odd, we
  also multiply the result with -1. These changes apply only for
  cases where n is an integer.

* test-suite/tests/numbers.test: Two new test cases for expt. For
  cases where the base is negative and the power to be raised is
  not an integer, the result should be a complex number.
---
 libguile/numbers.c|   20 +++-
 test-suite/tests/numbers.test |   15 ++-
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index fbc6cc8..5bbf4b0 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5445,12 +5445,30 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
 	Return @var{x} raised to the power of @var{y}.) 
 #define FUNC_NAME s_scm_expt
 {
-  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
+  if (scm_is_true (scm_exact_p (x)) 
+  scm_is_true (scm_exact_p (y)) 
+  !SCM_FRACTIONP (y))
 return scm_integer_expt (x, y);
   else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
 }
+  else if (scm_is_real (x) 
+   scm_is_real (y) 
+   (scm_to_double (x)  0) 
+   !SCM_FRACTIONP (y))
+{
+  SCM x_abs, result;
+
+  x_abs = scm_abs (x);
+  result = scm_from_double (pow (scm_to_double (x_abs), scm_to_double (y)));
+
+  if (scm_is_true (scm_equal_p (y, scm_floor (y))) 
+  scm_is_true (scm_odd_p (y)))
+return scm_product (scm_from_double (-1.0), result);
+  else
+return result;
+}
   else
 return scm_exp (scm_product (scm_log (x), y));
 }
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 3c3e14f..637449f 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -2892,7 +2892,20 @@
   (pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
   (pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
   (pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
-  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
+  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
+  ;; tests for non zero values of base and exponent.
+  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1))
+(eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
+  (pass-if (eqv-loosely? 4.0 (expt -2.0 2.0))
+   (eqv-loosely? 4.0 (expt -2.0 2.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2.0 -3.0))
+   (eqv-loosely? -0.125 (expt -2.0 -3.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2 -3.0))
+   (eqv-loosely? -0.125 (expt -2 -3.0)))
+  (pass-if (eqv-loosely? 0.25 (expt 2.0 -2.0))
+   (eqv-loosely? 0.25 (expt 2.0 -2.0)))
+  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3))
+(eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3
 
 ;;;
 ;;; asinh
-- 
1.7.2.3



Re: fix for expt bug

2010-11-01 Thread Mark H Weaver
Hi Ramakrishnan,

Thanks for the revised patch.  There are still some problems:

 diff --git a/libguile/numbers.c b/libguile/numbers.c
 index fbc6cc8..5bbf4b0 100644
 --- a/libguile/numbers.c
 +++ b/libguile/numbers.c
 @@ -5445,12 +5445,30 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
   Return @var{x} raised to the power of @var{y}.) 
  #define FUNC_NAME s_scm_expt
  {
 -  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
 +  if (scm_is_true (scm_exact_p (x)) 
 +  scm_is_true (scm_exact_p (y)) 
 +  !SCM_FRACTIONP (y))
  return scm_integer_expt (x, y);

This is an improvement, but isn't quite right.  scm_integer_expt
requires that y be an exact integer, but x is allowed to be any scheme
number whatsoever.  So the scm_exact_p (x) doesn't belong.  It should
simply be changed to scm_exact_p (y) instead.

The other problem is that !SCM_FRACTIONP is not the right test.
Although it is currently true that the only exact numbers in guile are
integers and rationals, there's no guarantee that other exact numbers
won't be added in the future.

The test above should be this:

if (scm_is_true (scm_exact_p (y))  scm_is_integer (y))

else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
  {
return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
  }
 +  else if (scm_is_real (x) 
 +   scm_is_real (y) 
 +   (scm_to_double (x)  0) 
 +   !SCM_FRACTIONP (y))

The !SCM_FRACTIONP (y) does not belong here.  Instead, you should test
scm_is_integer (y), which will also make the scm_is_real (y) test
redundant.  As is, your code will produce the wrong answer if y is an
inexact floating-point number such as 0.5.  SCM_FRACTIONP returns true
only for exact rational numbers.

So the above test should be:

  else if (scm_is_real (x)  scm_is_integer (y)  scm_to_double (x)  0)

 +{
 +  SCM x_abs, result;
 +
 +  x_abs = scm_abs (x);

You've already established that x is a negative real, so it is wasteful
to do another test in scm_abs.  Just negate x.

Also, it's inefficient to create so many intermediate floating-point SCM
values, since it involves allocating heap cells.  You don't need x_abs,
and result can be a C double.  See my suggested code below.

 +  result = scm_from_double (pow (scm_to_double (x_abs), scm_to_double 
 (y)));
 +
 +  if (scm_is_true (scm_equal_p (y, scm_floor (y))) 

The test above is better replaced by scm_is_integer (y), but it's needed
in the outer conditional anyway, so you can drop it here.

 +  scm_is_true (scm_odd_p (y)))
 +return scm_product (scm_from_double (-1.0), result);
 +  else
 +return result;
 +}

In summary, I think the new clause should be something like: (UNTESTED!)

  else if (scm_is_real (x)  scm_is_integer (y)  scm_to_double (x)  0)
  {
double result;

result = pow (-scm_to_double (x), scm_to_double (y));
if (scm_is_true (scm_odd_p (y)))
  result = -result;
return scm_from_double (result);
  }

 Best,
  Mark



Re: fix for expt bug

2010-11-01 Thread Ramakrishnan Muthukrishnan
Here is the updated patch.

thanks
Ramakrishnan
From e320d79c8f3cd8b7ddcb9c2d13356e34a3346cfe Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan vu3...@gmail.com
Date: Sun, 31 Oct 2010 23:22:52 +0530
Subject: [PATCH] Fix for bug #31464. expt needs to treat negative bases specially.

* libguile/numbers.c: If base is negative, expt needs to find
  -x^n = (-1^n) * (|x|^n). We find x^n and then if n is odd, we
  also multiply the result with -1. These changes apply only for
  cases where n is an integer.

* test-suite/tests/numbers.test: Two new test cases for expt. For
  cases where the base is negative and the power to be raised is
  not an integer, the result should be a complex number.
---
 libguile/numbers.c|   13 -
 test-suite/tests/numbers.test |   15 ++-
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index fbc6cc8..4b81d98 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5445,12 +5445,23 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
 	Return @var{x} raised to the power of @var{y}.) 
 #define FUNC_NAME s_scm_expt
 {
-  if (scm_is_true (scm_exact_p (x))  scm_is_integer (y))
+  if (scm_is_true (scm_exact_p (y))  scm_is_integer (y))
 return scm_integer_expt (x, y);
   else if (scm_is_real (x)  scm_is_real (y)  scm_to_double (x) = 0.0)
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
 }
+  else if (scm_is_real (x)  scm_is_integer (y)  (scm_to_double (x)  0))
+{
+  double result;
+  
+  result = pow (-scm_to_double (x), scm_to_double (y));
+
+  if (scm_is_true (scm_odd_p (y)))
+return scm_from_double (-result);
+  else
+return scm_from_double (result);
+}
   else
 return scm_exp (scm_product (scm_log (x), y));
 }
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 3c3e14f..637449f 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -2892,7 +2892,20 @@
   (pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
   (pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
   (pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
-  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
+  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
+  ;; tests for non zero values of base and exponent.
+  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1))
+(eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
+  (pass-if (eqv-loosely? 4.0 (expt -2.0 2.0))
+   (eqv-loosely? 4.0 (expt -2.0 2.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2.0 -3.0))
+   (eqv-loosely? -0.125 (expt -2.0 -3.0)))
+  (pass-if (eqv-loosely? -0.125 (expt -2 -3.0))
+   (eqv-loosely? -0.125 (expt -2 -3.0)))
+  (pass-if (eqv-loosely? 0.25 (expt 2.0 -2.0))
+   (eqv-loosely? 0.25 (expt 2.0 -2.0)))
+  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3))
+(eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3
 
 ;;;
 ;;; asinh
-- 
1.7.2.3



fix for expt bug

2010-10-31 Thread Ramakrishnan Muthukrishnan
Hi,

As reported here:

https://savannah.gnu.org/bugs/index.php?31464

expt currently wrongly prints the results for any negative base
numbers. The attached patch (also attached with the bug tracker) has a
fix and also adds a test case.

This is my first patch to guile, so please correct me if I have done
something wrong. I will be happy to rework it. I am yet to recieve the
assignment papers from the FSF (but they have been despatched already
by the FSF), I will mail them back as soon as I get it.

thanks
-- 
  Ramakrishnan
From c23939a1c2b7bfe1b3cf20abb6a7b431699281a1 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan vu3...@gmail.com
Date: Sun, 31 Oct 2010 23:22:52 +0530
Subject: [PATCH] Fix for bug #31464. expt needs to treat negative bases specially.
 Also adding test-suite cases for expt.

* libguile/numbers.c: if base is negative, find the absolute value
  of the base, find log and then later reapply the negative sign.
  The bug was caused by the fact that log of a negative number is
  undefined.

* test-suite/tests/numbers.test: Two new test cases for expt. For
  cases where the base is negative and the power to be raised is
  not an integer, the result should be a complex number.
---
 libguile/numbers.c|   11 +++
 test-suite/tests/numbers.test |7 ++-
 2 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/libguile/numbers.c b/libguile/numbers.c
index fbc6cc8..07ae95d 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -5451,6 +5451,17 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
 {
   return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
 }
+  else if (scm_is_real (x) 
+   scm_is_real (y) 
+   (scm_to_double (x)  0) 
+   !SCM_FRACTIONP (y))
+{
+  SCM x_abs;
+
+  x_abs = scm_abs (x);
+  return scm_product(scm_from_double (-1.0),
+ scm_exp (scm_product (scm_log (x_abs), y)));
+}
   else
 return scm_exp (scm_product (scm_log (x), y));
 }
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index 3c3e14f..3d53bbe 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -2892,7 +2892,12 @@
   (pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
   (pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
   (pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
-  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
+  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
+  ;; tests for non zero values of base and exponent.
+  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)
+   (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
+  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3)
+   (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 1/3
 
 ;;;
 ;;; asinh
-- 
1.7.2.3



Re: fix for expt bug

2010-10-31 Thread Mark H Weaver
Ramakrishnan,

Your fix is incorrect.  You have assumed that (-a)^b = -(a^b),
but this is true only if b is an odd integer.  A correct relation
is (-a)^b = (-1)^b * a^b.

As reported by Ludovic:

scheme@(guile-user) (expt -2742638075.5 2)
$8 = 7.52206361318235e18-1842.31337891184i
scheme@(guile-user) (* -2742638075.5 -2742638075.5)
$9 = 7.52206361318235e18

The reported bug is simply due to roundoff error.  You must know
something about complex numbers and specifically complex exponentials to
understand what's happening here.  The spurious imaginary part is
actually quite miniscule compared with the real part.  If one looks at
these results in polar form, the complex argument (angle) should ideally
be an exact zero, but is instead an inexact number very close to 0
(about 2.45e-16 radians in this case).

The most straightforward solution to this bug is to support a few
special cases, such as:

  (-a)^b = -(a^b)   (where a is positive real and b is an odd integer)
  (-a)^b =   a^b(where a is positive real and b is an even integer)

A more elaborate solution would involve supporting a polar
representation of complex numbers where the angle can be an exact
rational times pi, but this is almost certainly not worth it.

Best,
 Mark


Ramakrishnan Muthukrishnan vu3...@gmail.com wrote:
 https://savannah.gnu.org/bugs/index.php?31464

 expt currently wrongly prints the results for any negative base
 numbers. The attached patch (also attached with the bug tracker) has a
 fix and also adds a test case.

 This is my first patch to guile, so please correct me if I have done
 something wrong. I will be happy to rework it. I am yet to recieve the
 assignment papers from the FSF (but they have been despatched already
 by the FSF), I will mail them back as soon as I get it.

 thanks
 -- 
   Ramakrishnan

 From c23939a1c2b7bfe1b3cf20abb6a7b431699281a1 Mon Sep 17 00:00:00 2001
 From: Ramakrishnan Muthukrishnan vu3...@gmail.com
 Date: Sun, 31 Oct 2010 23:22:52 +0530
 Subject: [PATCH] Fix for bug #31464. expt needs to treat negative bases 
 specially.
  Also adding test-suite cases for expt.

 * libguile/numbers.c: if base is negative, find the absolute value
   of the base, find log and then later reapply the negative sign.
   The bug was caused by the fact that log of a negative number is
   undefined.

 * test-suite/tests/numbers.test: Two new test cases for expt. For
   cases where the base is negative and the power to be raised is
   not an integer, the result should be a complex number.
 ---
  libguile/numbers.c|   11 +++
  test-suite/tests/numbers.test |7 ++-
  2 files changed, 17 insertions(+), 1 deletions(-)

 diff --git a/libguile/numbers.c b/libguile/numbers.c
 index fbc6cc8..07ae95d 100644
 --- a/libguile/numbers.c
 +++ b/libguile/numbers.c
 @@ -5451,6 +5451,17 @@ SCM_DEFINE (scm_expt, expt, 2, 0, 0,
  {
return scm_from_double (pow (scm_to_double (x), scm_to_double (y)));
  }
 +  else if (scm_is_real (x) 
 +   scm_is_real (y) 
 +   (scm_to_double (x)  0) 
 +   !SCM_FRACTIONP (y))
 +{
 +  SCM x_abs;
 +
 +  x_abs = scm_abs (x);
 +  return scm_product(scm_from_double (-1.0),
 + scm_exp (scm_product (scm_log (x_abs), y)));
 +}
else
  return scm_exp (scm_product (scm_log (x), y));
  }
 diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
 index 3c3e14f..3d53bbe 100644
 --- a/test-suite/tests/numbers.test
 +++ b/test-suite/tests/numbers.test
 @@ -2892,7 +2892,12 @@
(pass-if (= 1 (expt 0 0)) (= 1 (expt 0 0)))
(pass-if (= 1 (expt 0 0.0)) (= 1 (expt 0 0.0)))
(pass-if (= 1 (expt 0.0 0)) (= 1 (expt 0.0 0)))
 -  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0
 +  (pass-if (= 1 (expt 0.0 0.0)) (= 1 (expt 0.0 0.0)))
 +  ;; tests for non zero values of base and exponent.
 +  (pass-if (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)
 +   (eqv-loosely? -2742638075.5 (expt -2742638075.5 1)))
 +  (pass-if (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 
 1/3)
 +   (eqv-loosely? 1.0002+1.7320508075688772i (expt -8 
 1/3
  
  ;;;
  ;;; asinh



Re: fix for expt bug

2010-10-31 Thread Ramakrishnan Muthukrishnan
On Mon, Nov 1, 2010 at 5:33 AM, Mark H Weaver m...@netris.org wrote:
 Ramakrishnan,

 Your fix is incorrect.  You have assumed that (-a)^b = -(a^b),

Mark,

Yes, you are right. Not sure what I was thinking when I made the patch. :-(

 The reported bug is simply due to roundoff error.  You must know
 something about complex numbers and specifically complex exponentials to
 understand what's happening here.  The spurious imaginary part is
 actually quite miniscule compared with the real part.  If one looks at
 these results in polar form, the complex argument (angle) should ideally
 be an exact zero, but is instead an inexact number very close to 0
 (about 2.45e-16 radians in this case).

 The most straightforward solution to this bug is to support a few
 special cases, such as:

  (-a)^b = -(a^b)   (where a is positive real and b is an odd integer)
  (-a)^b =   a^b    (where a is positive real and b is an even integer)

Thanks. I will take a dig at doing this solution.

-- 
  Ramakrishnan