@@ -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,10 @@ 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-2 )* 2 ,THRESH)
262
+ CALL CB1NRM2(N,INCX,THRESH)
263
+ * Test with hardcoded mid range entries
259
264
CALL STEST1(SCNRM2(N,CX,INCX),STRUE2(NP1),STRUE2(NP1),
260
265
+ SFAC)
261
266
ELSE IF (ICASE.EQ. 7 ) THEN
@@ -782,3 +787,228 @@ SUBROUTINE ITEST1(ICOMP,ITRUE)
782
787
* End of ITEST1
783
788
*
784
789
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