@@ -121,7 +121,8 @@ SUBROUTINE HEADER
121
121
SUBROUTINE CHECK1 (SFAC )
122
122
* .. Parameters ..
123
123
INTEGER NOUT
124
- PARAMETER (NOUT= 6 )
124
+ REAL THRESH
125
+ PARAMETER (NOUT= 6 , THRESH= 10.0E0 )
125
126
* .. Scalar Arguments ..
126
127
REAL SFAC
127
128
* .. Scalars in Common ..
@@ -141,7 +142,7 @@ SUBROUTINE CHECK1(SFAC)
141
142
INTEGER ICAMAX
142
143
EXTERNAL SCASUM, SCNRM2, ICAMAX
143
144
* .. External Subroutines ..
144
- EXTERNAL CSCAL, CSSCAL, CTEST, ITEST1, STEST1
145
+ EXTERNAL CB1NRM2, CSCAL, CSSCAL, CTEST, ITEST1, STEST1
145
146
* .. Intrinsic Functions ..
146
147
INTRINSIC MAX
147
148
* .. Common blocks ..
@@ -256,6 +257,9 @@ SUBROUTINE CHECK1(SFAC)
256
257
20 CONTINUE
257
258
IF (ICASE.EQ. 6 ) THEN
258
259
* .. SCNRM2 ..
260
+ * Test scaling when some entries are tiny or huge
261
+ CALL CB1NRM2(N,INCX,THRESH)
262
+ CALL CB1NRM2(N,- INCX,THRESH)
259
263
CALL STEST1(SCNRM2(N,CX,INCX),STRUE2(NP1),STRUE2(NP1),
260
264
+ SFAC)
261
265
ELSE IF (ICASE.EQ. 7 ) THEN
@@ -782,3 +786,225 @@ SUBROUTINE ITEST1(ICOMP,ITRUE)
782
786
* End of ITEST1
783
787
*
784
788
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