Skip to content

LAPACK slaln2.f: more accuracy hurts if not consistent #598

Description

@langou

This is a bug report from David Hough

Subject: LAPACK slaln2.f: more accuracy hurts if not consistent
Date: Wed, 29 Oct 2014 15:29:20 -0700 (PDT)

Another example turned up by enabling fused FMA operations to replace
multiply/add pairs at the compiler's discretion.

slaln2.f solves 1x1 or 2x2 systems of equations. Couldn't be simpler, right?

http://www.netlib.org/lapack/explore-html/da/d2d/slaln2_8f.html

But its invocation from the TESTING programs schkee.f/schkec.f/sget31.f
and the test input data file sec.in
gets into trouble with too-high residuals computed in sget31.f. Since slaln2.f uses total pivoting, how can it possibly have problems
with matrices of dimension <= 2?

After all, slaln2.f computes the answers with code like:

298 * Real 1x1 system.
299 *
300 * C = ca A - w D
301 *
302 csr = caa( 1, 1 ) - wrd1
...
323 x( 1, 1 ) = ( b( 1, 1 )*scale ) / csr

and

327 * Complex 1x1 system (w is complex)
328 *
329 * C = ca A - w D
330 *
331 csr = caa( 1, 1 ) - wrd1
332 csi = -wid1
...
354 CALL sladiv( scale
b( 1, 1 ), scale*b( 1, 2 ), csr, csi,
355 $ x( 1, 1 ), x( 1, 2 ) )

and sget31 checks them with code like:

221 res = abs( ( caa( 1, 1 )-wrd1 )*
222 $ x( 1, 1 )-scale*b( 1, 1 ) )

279 res = abs( ( caa( 1, 1 )-wrd1 )*
280 $ x( 1, 1 )+( wid1 )x( 1, 2 )-
281 $ scale
b( 1, 1 ) )
282 res = res + abs( ( -wi
d1 )x( 1, 1 )+
283 $ ( ca
a( 1, 1 )-wr*d1 )x( 1, 2 )-
284 $ scale
b( 1, 2 ) )

A very straighforward residual computation: to check x = bs / c compute
c
x - b*s

The problems arise when higher precision is used capriciously, as when
only one of sget31 or slaln2 replaces the ca-wd with an FMA, because they
are separately compiled, perhaps with different compiler options.

Then the computed residual is nowhere near where it should be if ca-wd
mostly cancels in single precision. And cchkec.f has this to say about
that:

Error in SLALN2: RMAX = 0.357E+07
LMAX = 60625 NINFO= 0 71553 KNT= 230400

My working solution - again not canonical LAPACK because it uses higher
precision - is to promote the candidates for fusing to higher precision:
In slaln2:

< CSR = CAA( 1, 1 ) - WRD1

CSR = dble(CA)*dble(A( 1, 1 )) - dble(WR)*dble(D1)

< CSR = CAA( 1, 1 ) - WRD1

CSR = dble(CA)*dble(A( 1, 1 )) - dble(WR)*dble(D1)

In sget31:

< RES = ABS( ( CAA( 1, 1 )-WRD1 )*
< $ X( 1, 1 )-SCALE*B( 1, 1 ) )

RES = ABS( ( dble(CA)dble(A( 1, 1 ))-dble(WR)dble(D1 ))
$ (X( 1, 1 ))-(SCALE)
(B( 1, 1 )) )

< RES = ABS( ( CAA( 1, 1 )-WRD1 )*
< $ X( 1, 1 )+( WID1 )X( 1, 2 )-
< $ SCALE
B( 1, 1 ) )
< RES = RES + ABS( ( -WI
D1 )X( 1, 1 )+
< $ ( CA
A( 1, 1 )-WR*D1 )X( 1, 2 )-
< $ SCALE
B( 1, 2 ) )

RES = ABS( x ( dble(CA)dble(A( 1, 1 ))-dble(WR)dble(D1) ) X( 1, 1 )+
x ( (WI)
(D1) )(X( 1, 2 ))- SCALEB( 1, 1 ) x )
RES = RES + ABS( $ ( dble(CA)dble(A( 1, 1 ))-dble(WR)dble(D1) )X( 1, 2 )+
x (-(WI)
(D1) )
(X( 1, 1 ))- SCALE
B( 1, 2 ) x )

That seems to do the trick. Interestingly, in my test environment,
corresponding bugs did not come up in the [cdz] versions of the same
functions.

It's not a question of whether higher precision is used. It's a question
of whether higher precision is used consistently. In a world where fusing multiple-add is mostly advantageous, or at least harmless, and is
either on or off globally, sensitive code needs to be protected.

The right solution is to have ways of indicating locally within the program text
where higher precision or other value-changing optimizations should be
avoided. Those places are relatively few, but hard to find after the
fact. However the right solution awaits a more cooperative attitude
from language designers and implementers.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions