The following code converts from lower to upper case:
subroutine upcase(string)
character*(*) string
c
do i = 1, len(string)
ic = ichar(string(i:i))
if ( ic.ge.97 .and. ic.le.122 ) then
string(i:i) = char(ic-32)
endif
enddo
return
end
Does anyone know of a better (ie faster) way to do this?
Thanks in advance,
Richard Link
You could do the conversion by indexing into a table rather
than with an IF statement, e.g.
character*1 table(0:127)
do i = 0, ichar('a')-1
table(i) = char(i)
enddo
do i = ichar('a'),ichar('z')
table(i) = char(i + ichar('A') - ichar('a'))
enddo
do i = ichar('z')+1,127
table(i) = char(i)
enddo
{...}
string(i:i) = table(ichar(string(i:i)))
Of course, this makes huge assumptions about the character set (i.e. 0:127),
and gratuitously uses the horribly nonstandard do/enddo to boot :-), but
should work on ASCII machines as a rule. If your machine isn't
byte-addressable (e.g. a cray of some sort), then you may need to experiment
to find the fastest approach; your original version may very well be faster.
CHARACTER*1 C
CHARACTER*26 LOWER, UPPER
DATA LOWER/'abcdefghijklmnopqrstuvwxyz'/
DATA UPPER/'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
I = INDEX(LOWER,C)
C = UPPER(I:I)
Neldon
n...@inel.gov
---
The views and opinions expressed herein are personal and are not necessarily
those of the United States Government or any of its agencies or contractors.
The trouble with this is that it's ASCII dependent.
May I suggest (a la Software Tools):
subroutine low(line)
c Converts all uppercase characters to lowercase.
c Written by Liam Healy, Feb. 28, 1985.
c
character*(*) line
character*26 lower,upper
integer i,loc
data lower/'abcdefghijklmnopqrstuvwxyz'/
data upper/'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
do 100 i=1,len(line)
loc=index(upper,line(i:i))
if (loc.gt.0) line(i:i)=lower(loc:loc)
100 continue
return
end
This goes from upper to lower, but you get the idea.
Liam Healy
<>Hi,
<>
<>The following code converts from lower to upper case:
<>
<> subroutine upcase(string)
<> character*(*) string
<>c
<> do i = 1, len(string)
<> ic = ichar(string(i:i))
<> if ( ic.ge.97 .and. ic.le.122 ) then
<> string(i:i) = char(ic-32)
<> endif
<> enddo
<> return
<> end
<>
<>Does anyone know of a better (ie faster) way to do this?
<>
<>Thanks in advance,
<>Richard Link
<
<You could do the conversion by indexing into a table rather
<than with an IF statement, e.g.
<
< character*1 table(0:127)
< do i = 0, ichar('a')-1
< table(i) = char(i)
< enddo
< do i = ichar('a'),ichar('z')
< table(i) = char(i + ichar('A') - ichar('a'))
< enddo
< do i = ichar('z')+1,127
< table(i) = char(i)
< enddo
<{...}
< string(i:i) = table(ichar(string(i:i)))
<
<Of course, this makes huge assumptions about the character set (i.e. 0:127),
<and gratuitously uses the horribly nonstandard do/enddo to boot :-), but
<should work on ASCII machines as a rule. If your machine isn't
<byte-addressable (e.g. a cray of some sort), then you may need to experiment
<to find the fastest approach; your original version may very well be faster.
Hi from Finland!
... or You can use it as function rather than as subroutine. E.g. like this:
CHARACTER*80 A,B,UPPERC*1200
A = 'abcd'
C
C VECTOR B TO UPPERCASE BUT VECTOR A KEEPS ITS ORIGINAL STATE
C
B = UPPERC(A)
PRINT *,A(1:4)
PRINT *,B(1:4)
C
IF('BINGO'.EQ.UPPERC('bingo')) PRINT *,'BINGO!!!!'
STOP
END
CHARACTER*(*) FUNCTION UPPERC (A)
CHARACTER*(*) A,B*1200
CHARACTER*30 UPP,LITL
DATA UPP /'ABCDEFGHIJKLMNOPQRSTUVWXY^Z][\'/
DATA LITL /'abcdefghijklmnopqrstuvwxy~z}{|'/
L = LEN(A)
B = A
DO 100 I = 1,L
J = INDEX(LITL,B(I:I))
IF(J.GT.0) THEN
B(I:I) = UPP(J:J)
ENDIF
100 CONTINUE
UPPERC = B
RETURN
END
Excuse my 'english'! / Kari Riikonen
>The trouble with this is that it's ASCII dependent.
>Liam Healey (and others) write:
>May I suggest (a la Software Tools):
> subroutine low(line)
>c Converts all uppercase characters to lowercase.
>c Written by Liam Healy, Feb. 28, 1985.
>c
> character*(*) line
> character*26 lower,upper
> integer i,loc
> data lower/'abcdefghijklmnopqrstuvwxyz'/
> data upper/'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
>
> do 100 i=1,len(line)
> loc=index(upper,line(i:i))
> if (loc.gt.0) line(i:i)=lower(loc:loc)
> 100 continue
> return
> end
Thanks for all the replies. Several sent this algorith, which
I've decided is the best way to go.
...Rick
If my memory serves me right, initialising character variables in a DATA
statement is nonstandard. Somebody correct me, if I am wrong. The
solution would be to replace the two DATA statements with simple
assignments:
lower='abcdefghijklmnopqrstuvwxyz'
upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
As a related question, has anyone out there written a similar routine for
ISO-8859 character set(s), especially those characters above ASCII 127,
which clearly are written characters used in some languages?
Tero Siili
Tero....@fmi.fi
No, the use of a character constant in a data statement does not violate the
Fortran standard. The standard stipulates a constant, but does not say
anything about the kind of constant. A character constant works fine.
Neldon
Michael
--
Michael Lemke
Astronomy, UT Austin, Texas
(mic...@io.as.utexas.edu or UTSPAN::UTADNX::IO::MICHAEL [SPAN])
> If my memory serves me right, initialising character variables in a DATA
> statement is nonstandard. Somebody correct me, if I am wrong.
Well, my copy of the standard is at home, so I can't quote chapter and
verse, but my understanding is that it is perfectly standard to initialize
a character variable with a DATA statement. I certainly have done it a
lot and have never encountered a problem with any compiler (though I'll
admit that this doesn't prove it's standard).
By the way, I tested both methods of uppercasing, and on my hardware the
method using CHAR and ICHAR, which is limited to the ASCII collating
sequence, ran five times faster than the method using INDEX, which has
the advantage of working with any collating sequence.
dt> By the way, I tested both methods of uppercasing, and on my hardware the
method using CHAR and ICHAR, which is limited to the ASCII collating
sequence, ran five times faster than the method using INDEX, which has
the advantage of working with any collating sequence.
I got approximately the same results (on my Sun IPX running SunOS 4.1.3 &
f77 2.0.1) which is unfortunate. Being standard (or more general) should
not carry such a performance penalty. Ah well.
--
Gary Strand Opinions stated herein are mine alone and are
stra...@ncar.ucar.edu not representative of NCAR, UCAR, or the NSF
If you want the speed of CHAR/ICHAR and ASCII/EBCDIC portability, not
everything is lost, as this wonderful (:-) !!!) example shows:
SUBROUTINE UPPER(STRING)
* IN-PLACE TRANSLATION OF 'STRING' TO UPPERCASE.
CHARACTER*(*) STRING
INTEGER II(3,2)
DATA II/128,169,64,96,122,-32/
IF (ICHAR('A').EQ.65) THEN
K=2 !ASCII
ELSE
K=1 !EBCDIC
ENDIF
DO 10 I=1,LEN(STRING)
KODE = ICHAR(STRING(I:I))
IF ((KODE.GT.II(1,K).AND.(KODE.LE.II(2,K)))
$ STRING(I:I) = CHAR(KODE+II(3,K))
10 CONTINUE
RETURN
END
If your collating sequence is neither ASCII or EBCDIC, I feel
sorry for you!!!
--
furio ercolessi <fu...@uiuc.edu>* <fu...@sissa.it>+
* materials research lab, uni illinois at urbana-champaign
+ intl school for advanced studies, trieste, italy
Here's an ugly little subroutine that's just a tad slower than the
ASCII only one on a Sun4:
------------------------------------------------------------------------------
c.....Converts all uppercase characters in LINE:INOUT to lowercase.
c.....Assumes 8 bits maximum for each character.
subroutine low3(line)
character*(*) line
character*1 lowvec(256)
character*26 lower, upper
integer i, loc, ich, upmax, upmin
logical init
save lowvec, upmax, upmin, init
data upper /'ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
data lower /'abcdefghijklmnopqrstuvwxyz'/
data init /.false./
if (.not. init) then
upmax = 0
upmin = 257
do 100 i = 1, 256
loc = index(upper, char(i))
if (loc .gt. 0) then
upmax = max(upmax,i)
upmin = min(upmin,i)
lowvec(i) = lower(loc:loc)
else
lowvec(i) = char(i)
endif
100 continue
init = .true.
endif
do 200 i = 1, len(line)
ich = ichar(line(i:i))
if (ich .ge. upmin .and. ich .le. upmax)
& line(i:i) = lowvec(ich)
200 continue
end
------------------------------------------------------------------------------
Results for downcasing one line 10,000 times (user + system time, in sec):
ASCII only: 1.59
The general algorithm that was posted by Liam Healy: 13.42
low3, above: 1.90
This subroutine does assume 8 bit (at most) characters, but is otherwise
general.
--Radey Shouman
--
Radey Shouman rsho...@chpc.utexas.edu
I got some replies via mail stating that DATA initialisation is
standard-conforming. I may have confused this issue with COMMONs and
character variables, was there not some rule, that character variables
either can not be transferred via COMMON or they must not be mixed with
other types of data in a named COMMON?
Tero Siili
--
Bernard Tiffany Bitnet: USERW062@UMICHUM
Internet: Bernard...@umich.edu CompuServe: 75046.2667
Windows is no longer a trademark of Microsoft Corporation.
Some compilers do not accept character variables being mixed with other
types of data in COMMON blocks. This could be an evidence that the standard
does not contain any indication about it.
On the other hand, I do not know of any compiler refusing to pass character
variables in a COMMON block.
Concerning DATA statements, variables (of any type) contained in a COMMON
block can only initialized through DATA statements in BLOCK DATA sections,
although some compilers are more permissive (breaking the standard).
Mario
+---------------------------------------------------------------------+
| Mario Guanziroli - CERN,Geneva,Switzerland & CRS4,Cagliari,Italy |
+---------------------------------------------------------------------+
| Bitnet: PALACE@LEPICS |
| Intnet: pal...@lepics.cern.ch,mgua...@csf.cern.ch,guan...@crs4.it |
+---------------------------------------------------------------------+
| .. e infine uscimmo a riveder le stelle. (Dante Alighieri, Inferno) |
+---------------------------------------------------------------------+
Yes, you are right. The Fortran standard does not permit mixing character
variables with other type variables in the same common block.
One thing that surprised me when working through this excercise was
that apparently it is illegal to take a substring of a character
constant declared in a parameter statement, which would seem the
natural way of initializing strings like 'abcd...z' which are
guaranteed not to change. For example:
character*26 lower
parameter (lower = 'abcdefghijklmnopqrstuvwxyz')
.
.
.
something = lower(i:i)
Is illegal on every platform on which I've tried it, so I assume this
is per the f77 standard. Is this so? And, if so, what was the rationale
for this restriction?
Radey> One thing that surprised me when working through this excercise was
Radey> that apparently it is illegal to take a substring of a character
Radey> constant declared in a parameter statement, which would seem the
Radey> natural way of initializing strings like 'abcd...z' which are
Radey> guaranteed not to change. For example:
Radey> character*26 lower
Radey> parameter (lower = 'abcdefghijklmnopqrstuvwxyz')
Radey> .
Radey> .
Radey> .
Radey> something = lower(i:i)
Radey> Is illegal on every platform on which I've tried it, so I assume this
Radey> is per the f77 standard. Is this so?
Yes
Radey> And, if so, what was the rationale for this restriction?
I don't know. It comes from the fact that substrings are defined
to operate on variables and parameters aren't variables. I could
speculate that this might have just been an oversight, but I don't
really know.
In any case, this changed in f90. The above is legal f90. There are
several "small" improvements like this in f90 that don't tend to
get discussed because they are dwarfed by the major changes. This
is one of the small improvements that I've run into and been glad for.
--
--
Richard Maine
ma...@altair.dfrf.nasa.gov
Yes, the above routine is a bit enthusiastic and converts some extra
stuff along the way :-)
I have really no intention to defend it, the 'ABC...'/'abc...' approach
is certainly better and someone posted a solution (the one creating the
table the first time it's called) that seems to have all the advantages
and no disadvantage.
Fortran 77 allows substrings only on character variable names and
subscripted character array names.
Fortran 90 extends this feature to structure character names and character
string constants.
So, in Fortran 90, you can simply write:
something = 'abcdefghijklmnopqrstuvwxyz' (I:I)
which isn't possible in Fortran 77.
I was wondering if anyone knew of a book/site/FAQ that will give
me reasonable IMSL subroutine equivalents. A new postdoc in our
lab wants to run a program that has the following subroutines:
DNEQNF (some sort of non-linear equation solver)
DQDAG (some sort of numerical integration routine)
This must be a FAQ! I've given this guy 'Numerical Recipes' to
see if what he needs is there, but for future use, I'd like to
know if there are any IMSL-equivalents floating around.
I don't think he's really shooting for too much accuracy; in
the program, I see he has defined:
pi=22.0/7.0
:-)
Thanks, Netland.
-Andrew
--
-----------------------------------------------------------------------------
Andrew Anselmo / Department of Mechanical Engineering / SUNY Stony Brook
ans...@thermsa.eng.sunysb.edu
>>As a related question, has anyone out there written a similar routine for
>>ISO-8859 character set(s), especially those characters above ASCII 127,
>>which clearly are written characters used in some languages?
>>
>What's the problem with ISO-8859? Just add ae's and oe's to the data
>statement and make the variables lower/upper longer. I would do here
>but Convex' EDT emulation forces me to enter the characters numerically
>instead of with my compose key and I really don't feel like looking up
>the ASCII table. Otherwise, the program above will work as is.
The problem is that it won't work in both directions. You can easily
convert a-umlaut, o-umlaut and u-umlaut into ae, oe and ue, but
you can't convert them back, as there are words such as the
german "bauer" (farmer) where the u and the e are pronounced
distincively.
So, what are the standard german-to-ASCII translations of umlaut
characters?
-- Danny Schwendener E-mail: mac...@bernina.ethz.ch
ezInfo Information Services, Swiss Fed. Institute of Technology (ETHZ)
The discussion you quote above was about case-conversion in general,
and about converting, for example, lower-case a-umlaut to upper-case
a-umlaut in particular. In this respect, Michael's comment was exactly
on the spot. You bring up an entirely new topic, namely converting
an umlaut to a two-letter sequence. This hasn't been discussed in this
thread so far. In addition to the problem you mention (about reversing
the convertion) it has further pecularities, for example it doesn't keep
constant the length of the string.
>
> -- Danny Schwendener E-mail: mac...@bernina.ethz.ch
> ezInfo Information Services, Swiss Fed. Institute of Technology (ETHZ)
Dirk Husfeld
Institute of Astronomy and Astrophysics Tel.:(FRG) 89 92 20 94 40
Scheinerstrasse 1 Fax :(FRG) 89 92 20 94 27
8000 Munich 80, FRG
Email: hus...@astronomie.physik.uni-muenchen.dbp.de (X.400)
or hus...@usm.uni-muenchen.de (Internet)
Tero Siili
That was definately not the question here, as Dirk Husfeld has pointed
out too.
>>
>I posed the original related question regarding characters above ASCII
>127. I am not certain, what Michael means by adding ae's and oe's and
>working from that.
You just extend that data statement in the example code, which is now
gone:
data /lower/ 'abcdefghijklmnopqrstuvwxyzäöü'
data /upper/ 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ'
Add more characters to complete it (my editor still doesn't take
composed characters).
>My question was, whether anyone has written a routine
>to convert e.g. lowcase umlaut characters to upcase umlaut characters - a
>fairly trivial exercise, I admit. As for umlauts, they are only a single
>special case - how about Spanish or French special characters such as
>c-cedi?
>As far as I know, ISO-8859 does contain most of those special characters
>in upcase and lowcase, so the conversion should be fairly straightforward.
Yes, see above.
>As for plain ASCII, that we should get rid of, it is too limited and
>anglocentric IMHO.
>
Agreed.
|> lab wants to run a program that has the following subroutines:
|>
|> DNEQNF (some sort of non-linear equation solver)
|>
|> DQDAG (some sort of numerical integration routine)
You may try some subroutines from netlib:
HYBRD - Powell's hybrid method for nonlinear equations from MINPACK
QDAG(S) - Quadrature method from QUADPACK
To get more information mail the following text, e.g., to net...@research.att.com
send index from minpack
send index from quadpack
|>
|> This must be a FAQ! I've given this guy 'Numerical Recipes' to
|> see if what he needs is there, but for future use, I'd like to
|> know if there are any IMSL-equivalents floating around.
|>
Regards,
--
+-----------------------------------------------------------------------------+
| Oskar von Stryk st...@mathematik.tu-muenchen.de |
| Mathematisches Institut |
| Technische Universitaet FORTWIHR - The Bavarian Consortium on |
| P.O.Box 20 24 20 High Performance Scientific Computing |
| D-W-8000 Muenchen 2, Germany |
+-----------------------------------------------------------------------------+