🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: sci.math.num-analysis
4 messages
4 total messages Started by Ivo Welch Wed, 05 Aug 1992 17:48
Bug in SVDCMP of "Numerical Recipees in C"
#191
Author: Ivo Welch
Date: Wed, 05 Aug 1992 17:48
64 lines
2396 bytes
I  have  the 1989 version  of   Numerical Recipees  in  C, both   in book  and
electronic form. I believe I have found a bug---or at least  a nuisance.  When
a matrix  contains some  extreme values,  it   is  possible  to get  an access
violation.

(Does anyone have a bug list of NRinC?)

Note: The code below is copyrighted, but since it is only a small  fragment, I
presume it is ok to post it to better explain the bug.

----------------

Description: On Chapter 2, page 70, the code looks like

  for (k=n;k>=1;k--) {
    for (its=1;its<=30;its++) {
      flag=1;
      for (l=k;l>=1;l--) {
        nm=l-1;
        if (fabs(rv1[l])+anorm == anorm) {
          flag=0;
          break;
        }
        if (fabs(w[nm])+anorm == anorm) break;
      }

# note that l ends with a value of 0 if the loop exits. Typically,
# rv1[l]=0, so the loop is exited early---no problem then. However,
# if the matrix is poorly setup (and I have had such a case), rv1[1]
# can become NaN (0/0), and the loop completes rather than breaks.
# I believe rv1[1] turned into NaN, since my matrix contained an IEEE
# -Inf.

# I presume this problem can be fixed if the condition reads l>=2,
# and nm=l-1 is moved into both the start and iteration.

      if (flag) {
        c=0.0;
        s=1.0;
        for (i=l;i<=k;i++) {

# note that i starts with a value of l. If l can be 0
# this means that the subsequent indices refer to 0, not 1.
# Since NRinC allocates all matrices/vectors from 1, not 0,
# this results in an access violation error---if you are lucky.

          f=s*rv1[i];
          if (fabs(f)+anorm != anorm) {
            g=w[i];
            h=PYTHAG(f,g);
            w[i]=h;
            h=1.0/h;
            c=g*h;
            s=(-f*h);
            for (j=1;j<=m;j++) {
              y=a[j][nm];
              z=a[j][i];
              a[j][nm]=y*c+z*s;
              a[j][i]=z*c-y*s;
            }
          }
        }
      }
Re: Bug in SVDCMP of "Numerical Recipees in C"
#195
Author: Darrell Roy Hougen
Date: Thu, 06 Aug 1992 02:45
39 lines
2324 bytes
iwelch@agsm.ucla.edu (Ivo Welch) writes:


*I  have  the 1989 version  of   Numerical Recipees  in  C, both   in book  and
*electronic form. I believe I have found a bug---or at least  a nuisance.  When
*a matrix  contains some  extreme values,  it   is  possible  to get  an access
*violation.

[ Code deleted. ]

*# note that l ends with a value of 0 if the loop exits. Typically,
*# rv1[l]=0, so the loop is exited early---no problem then. However,
*# if the matrix is poorly setup (and I have had such a case), rv1[1]
*# can become NaN (0/0), and the loop completes rather than breaks.
*# I believe rv1[1] turned into NaN, since my matrix contained an IEEE
*# -Inf.

I have had the same problem, but *only* when my input matrix contained
an Inf or NaN as appears to be the case in your example.  So, unless
you intend to work with infinities, it would appear that the code
works.  However, the fact that the program produces a segmentation
violation and core dumps as the result of a data error *is* annoying.

*# I presume this problem can be fixed if the condition reads l>=2,
*# and nm=l-1 is moved into both the start and iteration.

Perhaps you should just check for l == 0 at the end of the loop and
exit gracefully with an error message.  If you disallow l = 1 in the
body of the loop, the code may not work properly.  I think there is a
comment in the book (if not in the code) that rv1[1] is always zero so
that the loop will always exit before l = 0.  If rv1[1] is not zero,
there must be something wrong with the data.  Therefore, you could
check the value of rv1[1] to see if it is correct at various points in
the code.

Darrell

P.S. I would also be interested in seeing a bug list for Numerical
Recipes in C is anyone has it on line.
Re: Bug in SVDCMP of "Numerical Recipees in C"
#202
Author: Ivo Welch
Date: Thu, 06 Aug 1992 15:53
77 lines
3071 bytes
I have just found (perhaps) a more serious error in the same code. Look at nm:
it is  l-1 when the first  loop exits. So, the  loop exits with  l=1 and nm=0.
Look at the next use of nm. It is an index into the a[] array. ARGGGH!

Furthermore, perhaps someone can enlighten me as to what the statement

        if (fabs(rv1[l])+anorm == anorm)

tests. anorm is the max of abs(w[]) + abs(rv1[]). What ugly code.

/ivo

In article <1992Aug5.104832.27184@mic.ucla.edu> iwelch@agsm.ucla.edu (Ivo Welch) writes:
>
>I  have  the 1989 version  of   Numerical Recipees  in  C, both   in book  and
>electronic form. I believe I have found a bug---or at least  a nuisance.  When
>a matrix  contains some  extreme values,  it   is  possible  to get  an access
>violation.
>
>(Does anyone have a bug list of NRinC?)
>
>Note: The code below is copyrighted, but since it is only a small  fragment, I
>presume it is ok to post it to better explain the bug.
>
>----------------
>
>Description: On Chapter 2, page 70, the code looks like
>
>  for (k=n;k>=1;k--) {
>    for (its=1;its<=30;its++) {
>      flag=1;
>      for (l=k;l>=1;l--) {
>        nm=l-1;
>        if (fabs(rv1[l])+anorm == anorm) {
>          flag=0;
>          break;
>        }
>        if (fabs(w[nm])+anorm == anorm) break;
>      }
>
># note that l ends with a value of 0 if the loop exits. Typically,
># rv1[l]=0, so the loop is exited early---no problem then. However,
># if the matrix is poorly setup (and I have had such a case), rv1[1]
># can become NaN (0/0), and the loop completes rather than breaks.
># I believe rv1[1] turned into NaN, since my matrix contained an IEEE
># -Inf.
>
># I presume this problem can be fixed if the condition reads l>=2,
># and nm=l-1 is moved into both the start and iteration.
>
>      if (flag) {
>        c=0.0;
>        s=1.0;
>        for (i=l;i<=k;i++) {
>
># note that i starts with a value of l. If l can be 0
># this means that the subsequent indices refer to 0, not 1.
># Since NRinC allocates all matrices/vectors from 1, not 0,
># this results in an access violation error---if you are lucky.
>
>          f=s*rv1[i];
>          if (fabs(f)+anorm != anorm) {
>            g=w[i];
>            h=PYTHAG(f,g);
>            w[i]=h;
>            h=1.0/h;
>            c=g*h;
>            s=(-f*h);
>            for (j=1;j<=m;j++) {
>              y=a[j][nm];
>              z=a[j][i];
>              a[j][nm]=y*c+z*s;
>              a[j][i]=z*c-y*s;
>            }
>          }
>        }
>      }
testing for "smallness" (was: Re: Bug in SVDCMP of "Numerical Recipees in C")
#214
Author: Jonathan Thornburg
Date: Fri, 07 Aug 1992 20:37
75 lines
3840 bytes
In article <1992Aug6.085315.10239@mic.ucla.edu> iwelch@agsm.ucla.edu
(Ivo Welch) writes:
> [ referring to the "Numerical Recipes in C" SVDCMP function ]
>Furthermore, perhaps someone can enlighten me as to what the statement
>
>        if (fabs(rv1[l])+anorm == anorm)
>
>tests. anorm is the max of abs(w[]) + abs(rv1[]).

This is actually a nice way of testing whether or not  rv1[l]  is
"negligably small" relative to  w[] .  That is, in general the test

	if (x == (x + e))

(the  fabs()  actually isn't needed) tests whether or not  e  is
negligably small relative to  x .  More precisely, to within at
most a factor of two (which doesn't matter here) it tests for
 |e/x| < eps  where  eps  is the "machine epsilon", i.e. the
smallest positive floating point number such that  1.0+eps != 1.0
in floating point.  (eps = 5.97e-8 for IEEE single, 1.12e-16 for
IEEE double precision.)  This can be useful in testing whether or
not some iteration which updates  x  by adding  e  to it, has
converged.

This is a *nice* way of testing this because it *automatically*
adapts to the floating point format used.  That is, code written
using this style of test should work unchanged with any reasonable
floating point system (even Cray) *without* requiring changes to
"machine constants".

The same trick can also be used to test for things being "almost
negligable":

	if (x == (x + 0.01*e))

tests for  x + e  and  x  differing by at most 100 "units in the
last place" (100 times the value of the least significant bit in
 x ), i.e. for  |e/x| < 100*eps .  Here again the error tolerance
*automatically* adapts to the floating point precision.

(The one caveat in this is that the usual floating point precision
must be used for the computation/storage of  (x + e) , or at least
this quantity must be stored in a usual-precision register or memory
location.  If this computation is done/stored in (say) an extended-
precision register, all bets are off.  The usual hack to force
 (x + e)  to be computed in the "usual precision" is (using Fortran)

		double precision x, e
		double precision temp(2)
		common /extemp/ temp
		...
	c
	c	is  e  negligably small compared to  x ?
		temp(1) = x
		temp(2) = temp(1) + e
		if (temp(1) .eq. temp(2)) then
			... e  is negligably small compared to  x
		else
			... it isn't
		end if

(In C the array would be declared with "extern" storage class, i.e.
it would be declared at "top level", not inside a function, and would
*not* be declared "static".)

Here the use of an array, and its placement in a common block, are
intended to force the compiler to actually compute and store  x + e
in memory, hopefully rounding it to the "usual precision".  This is
rather ugly, but is safe against most optimizing compilers and
extended-precision-registers hardware.

- Jonathan Thornburg
  <jonathan@einstein.ph.utexas.edu> or <jonathan@hermes.chpc.utexas.edu>
  University of Texas at Austin / Physics Dept / Center for Relativity
  and (for a few more months) U of British Columbia / {Astronomy,Physics}
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads