Skip to content

Commit 91552a5

Browse files
committed
Improve testing of NRM2
Add tests covering arrays with extreme numbers provided in Anderson E. (2017) Algorithm 978: Safe Scaling in the Level 1 BLAS ACM Trans Math Softw 44:1--28 https://doi.org/10.1145/3061665 [D,S]NRM2 coverage improves lines 59.1% -> 100.0% branches 30.0% -> 90.0%. [DZ,SC]NRM2 coverage improves lines 67.0% -> 100.0% branches 41.7% -> 91.7% incx = 0 is not covered
1 parent 7a29cfe commit 91552a5

File tree

4 files changed

+883
-8
lines changed

4 files changed

+883
-8
lines changed

BLAS/TESTING/cblat1.f

Lines changed: 228 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ SUBROUTINE HEADER
121121
SUBROUTINE CHECK1(SFAC)
122122
* .. Parameters ..
123123
INTEGER NOUT
124-
PARAMETER (NOUT=6)
124+
REAL THRESH
125+
PARAMETER (NOUT=6, THRESH=10.0E0)
125126
* .. Scalar Arguments ..
126127
REAL SFAC
127128
* .. Scalars in Common ..
@@ -141,7 +142,7 @@ SUBROUTINE CHECK1(SFAC)
141142
INTEGER ICAMAX
142143
EXTERNAL SCASUM, SCNRM2, ICAMAX
143144
* .. External Subroutines ..
144-
EXTERNAL CSCAL, CSSCAL, CTEST, ITEST1, STEST1
145+
EXTERNAL CB1NRM2, CSCAL, CSSCAL, CTEST, ITEST1, STEST1
145146
* .. Intrinsic Functions ..
146147
INTRINSIC MAX
147148
* .. Common blocks ..
@@ -256,6 +257,9 @@ SUBROUTINE CHECK1(SFAC)
256257
20 CONTINUE
257258
IF (ICASE.EQ.6) THEN
258259
* .. SCNRM2 ..
260+
* Test scaling when some entries are tiny or huge
261+
CALL CB1NRM2(N,INCX,THRESH)
262+
CALL CB1NRM2(N,-INCX,THRESH)
259263
CALL STEST1(SCNRM2(N,CX,INCX),STRUE2(NP1),STRUE2(NP1),
260264
+ SFAC)
261265
ELSE IF (ICASE.EQ.7) THEN
@@ -782,3 +786,225 @@ SUBROUTINE ITEST1(ICOMP,ITRUE)
782786
* End of ITEST1
783787
*
784788
END
789+
SUBROUTINE CB1NRM2(N,INCX,THRESH)
790+
* Compare NRM2 with a reference computation using combinations
791+
* of the following values:
792+
*
793+
* 0, very small, small, ulp, 1, 1/ulp, big, very big, infinity, NaN
794+
*
795+
* one of these values is used to initialize x(1) and x(2:N) is
796+
* filled with random values from [-1,1] scaled by another of
797+
* these values.
798+
*
799+
* This routine is adapted from the test suite provided by
800+
* Anderson E. (2017)
801+
* Algorithm 978: Safe Scaling in the Level 1 BLAS
802+
* ACM Trans Math Softw 44:1--28
803+
* https://doi.org/10.1145/3061665
804+
*
805+
* .. Scalar Arguments ..
806+
INTEGER INCX, N
807+
REAL THRESH
808+
*
809+
* =====================================================================
810+
* .. Parameters ..
811+
INTEGER NMAX, NOUT, NV
812+
PARAMETER (NMAX=20, NOUT=6, NV=10)
813+
REAL HALF, ONE, THREE, TWO, ZERO
814+
PARAMETER (HALF=0.5E+0, ONE=1.0E+0, TWO= 2.0E+0,
815+
& THREE=3.0E+0, ZERO=0.0E+0)
816+
* .. External Functions ..
817+
REAL SCNRM2
818+
EXTERNAL SCNRM2
819+
* .. Intrinsic Functions ..
820+
INTRINSIC AIMAG, ABS, CMPLX, MAX, MIN, REAL, SQRT
821+
* .. Model parameters ..
822+
REAL BIGNUM, SAFMAX, SAFMIN, SMLNUM, ULP
823+
PARAMETER (BIGNUM=0.1014120480E+32,
824+
& SAFMAX=0.8507059173E+38,
825+
& SAFMIN=0.1175494351E-37,
826+
& SMLNUM=0.9860761315E-31,
827+
& ULP=0.1192092896E-06)
828+
* .. Local Scalars ..
829+
COMPLEX ROGUE
830+
REAL SNRM, TRAT, V0, V1, WORKSSQ, Y1, Y2,
831+
& YMAX, YMIN, YNRM, ZNRM
832+
INTEGER I, IV, IW, IX, KS
833+
LOGICAL FIRST
834+
* .. Local Arrays ..
835+
COMPLEX X(NMAX), Z(NMAX)
836+
REAL VALUES(NV), WORK(NMAX)
837+
* .. Executable Statements ..
838+
VALUES(1) = ZERO
839+
VALUES(2) = TWO*SAFMIN
840+
VALUES(3) = SMLNUM
841+
VALUES(4) = ULP
842+
VALUES(5) = ONE
843+
VALUES(6) = ONE / ULP
844+
VALUES(7) = BIGNUM
845+
VALUES(8) = SAFMAX
846+
VALUES(9) = SXVALS(V0,2)
847+
VALUES(10) = SXVALS(V0,3)
848+
ROGUE = CMPLX(1234.5678E+0,-1234.5678E+0)
849+
FIRST = .TRUE.
850+
*
851+
* Check that the arrays are large enough
852+
*
853+
IF (N*ABS(INCX).GT.NMAX) THEN
854+
WRITE (NOUT,99) "SCNRM2", NMAX, INCX, N, N*ABS(INCX)
855+
RETURN
856+
END IF
857+
*
858+
* Zero-sized inputs are tested in STEST1.
859+
IF (N.LE.0) THEN
860+
RETURN
861+
END IF
862+
*
863+
* Generate 2*(N-1) values in (-1,1).
864+
*
865+
KS = 2*(N-1)
866+
DO I = 1, KS
867+
CALL RANDOM_NUMBER(WORK(I))
868+
WORK(I) = ONE - TWO*WORK(I)
869+
END DO
870+
*
871+
* Compute the sum of squares of the random values
872+
* by an unscaled algorithm.
873+
*
874+
WORKSSQ = ZERO
875+
DO I = 1, KS
876+
WORKSSQ = WORKSSQ + WORK(I)*WORK(I)
877+
END DO
878+
*
879+
* Construct the test vector with one known value
880+
* and the rest from the random work array multiplied
881+
* by a scaling factor.
882+
*
883+
DO IV = 1, NV
884+
V0 = VALUES(IV)
885+
IF (ABS(V0).GT.ONE) THEN
886+
V0 = V0*HALF*HALF
887+
END IF
888+
Z(1) = CMPLX(V0,-THREE*V0)
889+
DO IW = 1, NV
890+
V1 = VALUES(IW)
891+
IF (ABS(V1).GT.ONE) THEN
892+
V1 = (V1*HALF) / SQRT(REAL(KS+1))
893+
END IF
894+
DO I = 1, N-1
895+
Z(I+1) = CMPLX(V1*WORK(2*I-1),V1*WORK(2*I))
896+
END DO
897+
*
898+
* Compute the expected value of the 2-norm
899+
*
900+
Y1 = ABS(V0) * SQRT(10.0E0)
901+
IF (N.GT.1) THEN
902+
Y2 = ABS(V1)*SQRT(WORKSSQ)
903+
ELSE
904+
Y2 = ZERO
905+
END IF
906+
YMIN = MIN(Y1, Y2)
907+
YMAX = MAX(Y1, Y2)
908+
*
909+
* Expected value is NaN if either is NaN. The test
910+
* for YMIN == YMAX avoids further computation if both
911+
* are infinity.
912+
*
913+
IF ((Y1.NE.Y1).OR.(Y2.NE.Y2)) THEN
914+
* add to propagate NaN
915+
YNRM = Y1 + Y2
916+
ELSE IF (YMIN == YMAX) THEN
917+
YNRM = SQRT(TWO)*YMAX
918+
ELSE IF (YMAX == ZERO) THEN
919+
YNRM = ZERO
920+
ELSE
921+
YNRM = YMAX*SQRT(ONE + (YMIN / YMAX)**2)
922+
END IF
923+
*
924+
* Fill the input array to SCNRM2 with steps of incx
925+
*
926+
DO I = 1, N
927+
X(I) = ROGUE
928+
END DO
929+
IX = 1
930+
IF (INCX.LT.0) IX = 1 - (N-1)*INCX
931+
DO I = 1, N
932+
X(IX) = Z(I)
933+
IX = IX + INCX
934+
END DO
935+
*
936+
* Call SCNRM2 to compute the 2-norm
937+
*
938+
SNRM = SCNRM2(N,X,INCX)
939+
*
940+
* Compare SNRM and ZNRM. Roundoff error grows like O(n)
941+
* in this implementation so we scale the test ratio accordingly.
942+
*
943+
IF (INCX.EQ.0) THEN
944+
Y1 = ABS(REAL(X(1)))
945+
Y2 = ABS(AIMAG(X(1)))
946+
YMIN = MIN(Y1, Y2)
947+
YMAX = MAX(Y1, Y2)
948+
IF ((Y1.NE.Y1).OR.(Y2.NE.Y2)) THEN
949+
* add to propagate NaN
950+
ZNRM = Y1 + Y2
951+
ELSE IF (YMIN == YMAX) THEN
952+
ZNRM = SQRT(TWO)*YMAX
953+
ELSE IF (YMAX == ZERO) THEN
954+
ZNRM = ZERO
955+
ELSE
956+
ZNRM = YMAX * SQRT(ONE + (YMIN / YMAX)**2)
957+
END IF
958+
ZNRM = SQRT(REAL(n)) * ZNRM
959+
ELSE
960+
ZNRM = YNRM
961+
END IF
962+
IF ((SNRM.NE.SNRM).OR.(ZNRM.NE.ZNRM)) THEN
963+
IF ((SNRM.NE.SNRM).NEQV.(ZNRM.NE.ZNRM)) THEN
964+
TRAT = ONE / ULP
965+
ELSE
966+
TRAT = ZERO
967+
END IF
968+
ELSE IF (ZNRM == ZERO) THEN
969+
TRAT = SNRM / ULP
970+
ELSE
971+
TRAT = (ABS(SNRM-ZNRM) / ZNRM) / (TWO*REAL(N)*ULP)
972+
END IF
973+
IF ((TRAT.NE.TRAT).OR.(TRAT.GE.THRESH)) THEN
974+
IF (FIRST) THEN
975+
FIRST = .FALSE.
976+
WRITE(NOUT,99999)
977+
END IF
978+
WRITE (NOUT,98) "SCNRM2", N, INCX, IV, IW, TRAT
979+
END IF
980+
END DO
981+
END DO
982+
99999 FORMAT (' FAIL')
983+
99 FORMAT ( ' Not enough space to test ', A6, ': NMAX = ',I6,
984+
+ ', INCX = ',I6,/,' N = ',I6,', must be at least ',I6 )
985+
98 FORMAT( 1X, A6, ': N=', I6,', INCX=', I4, ', IV=', I2, ', IW=',
986+
+ I2, ', test=', E15.8 )
987+
RETURN
988+
CONTAINS
989+
REAL FUNCTION SXVALS(XX,K)
990+
* .. Scalar Arguments ..
991+
REAL XX
992+
INTEGER K
993+
* .. Local Scalars ..
994+
REAL X, Y, YY, Z
995+
* .. Intrinsic Functions ..
996+
INTRINSIC HUGE
997+
* .. Executable Statements ..
998+
Y = HUGE(XX)
999+
Z = YY
1000+
IF (K.EQ.1) THEN
1001+
X = -Z
1002+
ELSE IF (K.EQ.2) THEN
1003+
X = Z
1004+
ELSE IF (K.EQ.3) THEN
1005+
X = Z / Z
1006+
END IF
1007+
SXVALS = X
1008+
RETURN
1009+
END
1010+
END

0 commit comments

Comments
 (0)