程序运行后效果:
3.1415926 (F9.7) 3.14159260000000 3.1415926 34.12e+11 (2PE9.2) 3412000000000.00 34.1E+11 |
蓝色为输入的数据,红色为输出的该数据格式。其后转换为real*8类型,再转回字符型(以便检查是否正确)
001 | PROGRAM www_fcode_cn |
002 | CHARACTER ( LEN = 64 ) :: ztxt |
003 | CHARACTER ( LEN = 64 ) :: zfmt |
004 | Real ( Kind = Kind ( 0.0D0 ) ) :: d |
005 | Do |
006 | READ ( * , "(A)" , end = 1000 ) ztxt |
007 | CALL obtfmt ( ztxt , zfmt ) !// 从 ztxt 获得格式 zfmt |
008 | WRITE ( * , * ) zfmt !// 输出格式 |
009 | k = isnum ( ztxt ) |
010 | IF ( k == 1 ) THEN |
011 | READ ( ztxt , zfmt ) i |
012 | WRITE ( * , * ) i |
013 | WRITE ( * , zfmt ) i |
014 | END IF |
015 | IF ( k > 1 ) THEN |
016 | READ ( ztxt , zfmt ) d |
017 | WRITE ( * , * ) d |
018 | WRITE ( * , zfmt ) d |
019 | END IF |
020 | End Do |
021 | 1000 STOP |
022 | END PROGRAM www_fcode_cn |
023 |
024 | MODULE CODNUM |
025 | ! Definition of codes for the numerical types |
026 | ! _________________________________________________________________ |
027 | INTEGER , PARAMETER :: KINT = 1 ! integer |
028 | INTEGER , PARAMETER :: KFIX = 2 ! fixed point real |
029 | INTEGER , PARAMETER :: KEXP = 3 ! exponent type real |
030 | INTEGER , PARAMETER :: KDBL = 4 ! exponent type double |
031 | END MODULE CODNUM |
032 | INTEGER FUNCTION isnum ( ZVAL ) |
033 | ! Verify that a character string represents a numerical value |
034 | USE CODNUM |
035 | CHARACTER ( Len = * ) , INTENT ( IN ) :: ZVAL |
036 | ! __________________________________________________ |
037 | ! return : 0 = non-numeric string |
038 | ! else = code as defined in module codnum |
039 | ! __________________________________________________ |
040 | ! |
041 | ! initialise |
042 | ! |
043 | NUM = 0 |
044 | NMTS = 0 |
045 | NEXP = 0 |
046 | KMTS = 0 |
047 | IFEXP = 0 |
048 | ! |
049 | ! loop over characters |
050 | ! |
051 | ICHR = 0 |
052 | DO |
053 | IF ( ICHR >= LEN ( ZVAL ) ) THEN |
054 | ! |
055 | ! last check |
056 | ! |
057 | IF ( NMTS == 0 ) EXIT |
058 | IF ( NUM >= KEXP .AND. NEXP == 0 ) EXIT |
059 | isnum = NUM |
060 | RETURN |
061 | END IF |
062 | ICHR = ICHR + 1 |
063 | SELECT CASE ( ZVAL ( ICHR : ICHR ) ) |
064 | ! |
065 | ! process blanks |
066 | ! |
067 | CASE ( ' ' ) |
068 | CONTINUE |
069 | ! |
070 | ! process digits |
071 | ! |
072 | CASE ( '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ) |
073 | IF ( NUM == 0 ) NUM = KINT |
074 | IF ( NUM < KEXP ) THEN |
075 | NMTS = NMTS + 1 |
076 | ELSE |
077 | NEXP = NEXP + 1 |
078 | END IF |
079 | ! |
080 | ! process signs |
081 | ! |
082 | CASE ( '+' , '-' ) |
083 | IF ( NUM == 0 ) THEN |
084 | IF ( KMTS > 0 ) EXIT |
085 | KMTS = 1 |
086 | NUM = KINT |
087 | ELSE |
088 | IF ( NUM < KEXP ) EXIT |
089 | IF ( IFEXP > 0 ) EXIT |
090 | IFEXP = 1 |
091 | END IF |
092 | ! |
093 | ! process decimal point |
094 | ! |
095 | CASE ( '.' ) |
096 | IF ( NUM /= KINT .AND. ICHR /= 1 ) EXIT |
097 | NUM = KFIX |
098 | ! |
099 | ! process exponent |
100 | ! |
101 | CASE ( 'e' , 'E' ) |
102 | IF ( NUM >= KEXP ) EXIT |
103 | IF ( NMTS == 0 ) EXIT |
104 | NUM = KEXP |
105 | ! |
106 | CASE ( 'd' , 'D' ) |
107 | IF ( NUM >= KEXP ) EXIT |
108 | IF ( NMTS == 0 ) EXIT |
109 | NUM = KDBL |
110 | ! |
111 | ! any other character means the string is non-numeric |
112 | ! |
113 | CASE DEFAULT |
114 | EXIT |
115 | ! |
116 | END SELECT |
117 | END DO |
118 | ! |
119 | ! if this point is reached, the string is non-numeric |
120 | ! |
121 | isnum = 0 |
122 | RETURN |
123 | END FUNCTION isnum |
124 | SUBROUTINE obtfmt ( ZVAL , zfmt ) |
125 | USE CODNUM |
126 | ! Find out what Fortran format was used to write a numerical value |
127 | CHARACTER ( Len = * ) , INTENT ( IN ) :: ZVAL ! the string |
128 | CHARACTER ( Len = * ) , INTENT ( OUT ) :: zfmt ! the format |
129 | ! ____________________________________________________ |
130 | CHARACTER ( Len = 1 ) :: ZNUM 0 , ZNUM 1 , ZNUM 2 ! to write the numbers |
131 | ! of digits of the integers |
132 | ! used in the format |
133 | CHARACTER ( Len = 27 ) :: ZFMTW ! The format to write the format ... |
134 | INTERFACE |
135 | INTEGER FUNCTION isnum ( ZVAL ) |
136 | ! Verify that a string is numeric |
137 | CHARACTER ( Len = * ) , INTENT ( IN ) :: ZVAL ! the string |
138 | END FUNCTION isnum |
139 | ! |
140 | INTEGER FUNCTION NBRCHF ( JVAL ) |
141 | ! Number of characters (digits and minus sign) to display JVAL |
142 | INTEGER , INTENT ( IN ) :: JVAL ! the value |
143 | END FUNCTION NBRCHF |
144 | END INTERFACE |
145 | ! |
146 | ! initialise |
147 | ! |
148 | LVAL = LEN ( ZVAL ) |
149 | LFMT = LEN ( zfmt ) |
150 | ! |
151 | ! Big switching place |
152 | ! |
153 | KASE = isnum ( ZVAL ) |
154 | SELECT CASE ( KASE ) |
155 | ! |
156 | ! non numeric (A Format) |
157 | ! ____________________________________________________ |
158 | ! |
159 | CASE ( 0 ) |
160 | NCHR = LVAL |
161 | NCHR 1 = NBRCHF ( NCHR ) |
162 | ! |
163 | ! The format is (Axxx), we will write it with ('(A',Iw,')') |
164 | ! Lets create the latter format, ZFMTW, with w = NCHR1 |
165 | ! |
166 | IF ( NCHR 1 +3 > LFMT ) THEN |
167 | WRITE ( * , * ) "Argument string ZFMT too short" |
168 | ELSE |
169 | IF ( NCHR 1 > 0 .AND. NCHR 1 < 10 ) THEN |
170 | WRITE ( ZNUM 1 , "(I1)" ) NCHR 1 |
171 | ZFMTW = "('(A',I" / / ZNUM 1 / / ",')')" |
172 | WRITE ( zfmt , ZFMTW ) NCHR |
173 | ELSE |
174 | WRITE ( * , * ) "Doesn't a string length of" , & |
175 | & NCHR , " seem strange ?" |
176 | END IF |
177 | END IF |
178 | ! |
179 | ! integer |
180 | ! ____________________________________________________ |
181 | ! |
182 | CASE ( KINT ) |
183 | NCHF = LEN_TRIM ( ZVAL ) |
184 | ! |
185 | ! If it looks too long, remove leading blanks |
186 | ! |
187 | IF ( NCHF > 20 ) THEN |
188 | NCHF = LEN_TRIM ( ADJUSTL ( ZVAL ) ) |
189 | END IF |
190 | ! |
191 | NCHR 1 = NBRCHF ( NCHF ) |
192 | ! |
193 | ! The format is (Ixxx), we will write it with ('(I',Iw,')') |
194 | ! Lets create the latter format, ZFMTW, with w = NCHR1 |
195 | ! |
196 | IF ( NCHR 1 +3 > LFMT ) THEN |
197 | WRITE ( * , * ) "Argument string ZFMT too short" |
198 | ELSE |
199 | IF ( NCHR 1 > 0 .AND. NCHR 1 < 10 ) THEN |
200 | WRITE ( ZNUM 1 , "(I1)" ) NCHR 1 |
201 | ZFMTW = "('(I',I" / / ZNUM 1 / / ",')')" |
202 | WRITE ( zfmt , ZFMTW ) NCHF |
203 | ELSE |
204 | WRITE ( * , * ) "isn't an integer of " , NCHF , " & |
205 | & digits a strange idea ?" |
206 | END IF |
207 | END IF |
208 | ! |
209 | ! real, fixed point form |
210 | ! ____________________________________________________ |
211 | ! |
212 | CASE ( KFIX ) |
213 | NCHF = LEN_TRIM ( ZVAL ) |
214 | NCHFF = NCHF - INDEX ( ZVAL , '.' ) |
215 | ! |
216 | ! If it looks too long, remove leading blanks |
217 | ! |
218 | IF ( NCHF > 25 ) THEN |
219 | NCHF = LEN_TRIM ( ADJUSTL ( ZVAL ) ) |
220 | END IF |
221 | ! |
222 | NCHR 1 = NBRCHF ( NCHF ) |
223 | NCHR 2 = NBRCHF ( NCHFF ) |
224 | ! |
225 | ! The format is (Fxx.yy), we will write it with ('(F',Iw,'.',Id,')') |
226 | ! Lets create the latter format, ZFMTW, with w = NCHR1 |
227 | ! and d = NCHR2, obtained from the position of the decimal point |
228 | ! |
229 | IF ( NCHR 1 + NCHR 2 +4 > LFMT ) THEN |
230 | WRITE ( * , * ) "Argument string ZFMT too short" |
231 | ELSE |
232 | IF ( NCHR 1 > 0 .AND. NCHR 1 < 10 ) THEN |
233 | WRITE ( ZNUM 1 , "(I1)" ) NCHR 1 |
234 | WRITE ( ZNUM 2 , "(I1)" ) NCHR 2 |
235 | ZFMTW = "('(F',I" / / ZNUM 1 / / ",'.',I" / / ZNUM 2 / / & |
236 | & ",')')" |
237 | WRITE ( zfmt , ZFMTW ) NCHF , NCHFF |
238 | ELSE |
239 | WRITE ( * , * ) "isn't a real of " , NCHF , " & |
240 | & digits a strange idea ?" |
241 | END IF |
242 | END IF |
243 | ! |
244 | ! real, exponent form |
245 | ! ____________________________________________________ |
246 | ! |
247 | CASE ( KEXP , KDBL ) |
248 | NCHF = LEN_TRIM ( ZVAL ) |
249 | IF ( KASE == 3 ) THEN |
250 | NCHFF = Max ( INDEX ( ZVAL , 'E' ) , INDEX ( ZVAL , 'e' ) ) - 1 - & |
251 | & INDEX ( ZVAL , '.' ) |
252 | ELSE |
253 | NCHFF = Max ( INDEX ( ZVAL , 'D' ) , INDEX ( ZVAL , 'd' ) ) - 1 - & |
254 | & INDEX ( ZVAL , '.' ) |
255 | END IF |
256 | IPNT = INDEX ( ZVAL , '.' ) |
257 | IF ( IPNT > 0 ) THEN |
258 | NCHFP = IPNT - VERIFY ( ZVAL , " +-" ) |
259 | ELSE |
260 | NCHFP = NCHFF |
261 | NCHFF = 0 |
262 | END IF |
263 | ! |
264 | ! If it looks too long, remove leading blanks |
265 | ! |
266 | IF ( NCHF > 30 ) THEN |
267 | NCHF = LEN_TRIM ( ADJUSTL ( ZVAL ) ) |
268 | END IF |
269 | ! |
270 | NCHR 0 = NBRCHF ( NCHFP ) |
271 | NCHR 1 = NBRCHF ( NCHF ) |
272 | NCHR 2 = NBRCHF ( NCHFF ) |
273 | ! |
274 | ! The chosen format is (zPExx.yy), we will write it with |
275 | ! ('(',Ik,'PE',Iw,'.',Id,')') |
276 | ! Lets create the latter format, ZFMTW, with |
277 | ! k= NCHR0, w = NCHR1, d = NCHR2 |
278 | ! |
279 | IF ( NCHF +5 > LFMT ) THEN |
280 | WRITE ( * , * ) "Argument string ZFMT too short" |
281 | ELSE |
282 | IF ( NCHR 1 > 0 .AND. NCHR 1 < 10 ) THEN |
283 | WRITE ( ZNUM 0 , "(I1)" ) NCHR 0 |
284 | WRITE ( ZNUM 1 , "(I1)" ) NCHR 1 |
285 | WRITE ( ZNUM 2 , "(I1)" ) NCHR 2 |
286 | IF ( KASE == 3 ) THEN |
287 | ZFMTW = "('(',I" / / ZNUM 0 / / ",'PE',I" / / ZNUM 1 / / & |
288 | & ",'.',I" / / ZNUM 2 / / ",')')" |
289 | ELSE |
290 | ZFMTW = "('(',I" / / ZNUM 0 / / ",'PD',I" / / ZNUM 1 / / & |
291 | & ",'.',I" / / ZNUM 2 / / ",')')" |
292 | END IF |
293 | WRITE ( zfmt , ZFMTW ) NCHFP , NCHF , NCHFF |
294 | ELSE |
295 | WRITE ( * , * ) "isn't a real of " , NCHF , " & |
296 | & digits a strange idea ?" |
297 | END IF |
298 | END IF |
299 | ! |
300 | ! |
301 | CASE DEFAULT |
302 | WRITE ( * , * ) "Type " , KASE , " not known" |
303 | ! |
304 | END SELECT |
305 | RETURN |
306 | END SUBROUTINE obtfmt |
307 | INTEGER FUNCTION NBRCHF ( JVAL ) |
308 | ! Number of characters (digits and minus sign) to display JVAL |
309 | INTEGER , INTENT ( IN ) :: JVAL ! the value |
310 | ! ____________________________________________________ |
311 | ! |
312 | ! Compute with integers to avoid precision problems |
313 | ! with logarithms |
314 | ! |
315 | ! Start with 1, [+1 when negative] |
316 | ! ____________________________________________________ |
317 | ! |
318 | IF ( JVAL < 0 ) THEN |
319 | NCHF = 2 |
320 | JVALA = - JVAL |
321 | ELSE |
322 | NCHF = 1 |
323 | JVALA = JVAL |
324 | END IF |
325 | ! |
326 | ! + 1 per overpassing of power of 10 |
327 | ! |
328 | DO |
329 | IF ( JVALA < 10 ) EXIT |
330 | JVALA = JVALA / 10 |
331 | NCHF = NCHF + 1 |
332 | END DO |
333 | NBRCHF = NCHF |
334 | RETURN |
335 | END FUNCTION NBRCHF |