Skip to content

Commit ae9c818

Browse files
authored
Merge pull request #925 from angsch/master
Add Anderson's tests of NRM2
2 parents f568a60 + 26df4b3 commit ae9c818

File tree

4 files changed

+899
-8
lines changed

4 files changed

+899
-8
lines changed

BLAS/TESTING/cblat1.f

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

0 commit comments

Comments
 (0)