@@ -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,225 @@ 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+ IF ((SNRM.NE. SNRM).OR. (ZNRM.NE. ZNRM)) THEN
964+ IF ((SNRM.NE. SNRM).NEQV. (ZNRM.NE. ZNRM)) THEN
965+ TRAT = ONE / ULP
966+ ELSE
967+ TRAT = ZERO
968+ END IF
969+ ELSE IF (ZNRM == ZERO) THEN
970+ TRAT = SNRM / ULP
971+ ELSE
972+ TRAT = (ABS (SNRM- ZNRM) / ZNRM) / (TWO* REAL (N)* ULP)
973+ END IF
974+ IF ((TRAT.NE. TRAT).OR. (TRAT.GE. THRESH)) THEN
975+ IF (FIRST) THEN
976+ FIRST = .FALSE.
977+ WRITE (NOUT,99999 )
978+ END IF
979+ WRITE (NOUT,98 ) " SCNRM2" , N, INCX, IV, IW, TRAT
980+ END IF
981+ END DO
982+ END DO
983+ 99999 FORMAT (' FAIL' )
984+ 99 FORMAT ( ' Not enough space to test ' , A6, ' : NMAX = ' ,I6,
985+ + ' , INCX = ' ,I6,/ ,' N = ' ,I6,' , must be at least ' ,I6 )
986+ 98 FORMAT ( 1X , A6, ' : N=' , I6,' , INCX=' , I4, ' , IV=' , I2, ' , IW=' ,
987+ + I2, ' , test=' , E15.8 )
988+ RETURN
989+ CONTAINS
990+ REAL FUNCTION SXVALS (XX ,K )
991+ * .. Scalar Arguments ..
992+ REAL XX
993+ INTEGER K
994+ * .. Local Scalars ..
995+ REAL X, Y, YY, Z
996+ * .. Intrinsic Functions ..
997+ INTRINSIC HUGE
998+ * .. Executable Statements ..
999+ Y = HUGE (XX)
1000+ Z = YY
1001+ IF (K.EQ. 1 ) THEN
1002+ X = - Z
1003+ ELSE IF (K.EQ. 2 ) THEN
1004+ X = Z
1005+ ELSE IF (K.EQ. 3 ) THEN
1006+ X = Z / Z
1007+ END IF
1008+ SXVALS = X
1009+ RETURN
1010+ END
1011+ END
0 commit comments