User talk:Zmi007: Difference between revisions

Content added Content deleted
(short comments)
Line 33: Line 33:
::I have no objection to the various operators for messing with strings, though I have been startled by the implementation of some, at least as applied to CHARACTER variables as used in the F95 compiler I mess with. For instance, the latter-day library function LEN_TRIM(text) finds the last non-blank, but, the actual code first copies ''text'' to a work area then scans that work area!
::I have no objection to the various operators for messing with strings, though I have been startled by the implementation of some, at least as applied to CHARACTER variables as used in the F95 compiler I mess with. For instance, the latter-day library function LEN_TRIM(text) finds the last non-blank, but, the actual code first copies ''text'' to a work area then scans that work area!
::: Do not understand me wrong but I believe that fidelity to old compiler is not always honesty ) [[User:Zmi007|Zmi007]] ([[User talk:Zmi007|talk]]) 13:43, 9 December 2015 (UTC)
::: Do not understand me wrong but I believe that fidelity to old compiler is not always honesty ) [[User:Zmi007|Zmi007]] ([[User talk:Zmi007|talk]]) 13:43, 9 December 2015 (UTC)
===Writing an integer===
I don't have access to a F2003 compiler, and don't want to spend ''my'' money to gain access, especially when the prices I've seen are around US$3,000. The system I use dual starts to Linux or wunduhs, so there is a possibility there, but also a lot of time and patience needed to find a compatible compiler. I do have a wunduhs F95 compiler (alas, its microflaccid "visual" interface won't work on 64 bit or later than wunduhs XP) ... And here is a collection of IFMT(n) functions...
<lang Fortran>
CHARACTER*2 FUNCTION I2FMT4(N) !These are all the same.
INTEGER*4 N !But, the compiler doesn't offer generalisations.
IF (N.LT.0) THEN !Negative numbers cop a sign.
IF (N.LT.-9) THEN !But there's not much room left.
I2FMT4 = "-!" !So this means 'overflow'.
ELSE !Otherwise, room for one negative digit.
I2FMT4 = "-"//CHAR(ICHAR("0") - N) !Thus. Presume adjacent character codes, etc.
END IF !So much for negative numbers.
ELSE IF (N.LT.10) THEN !Single digit positive?
I2FMT4 = " " //CHAR(ICHAR("0") + N) !Yes. This.
ELSE IF (N.LT.100) THEN !Two digit positive?
I2FMT4 = CHAR(N/10 + ICHAR("0")) !Yes.
1 //CHAR(MOD(N,10) + ICHAR("0")) !These.
ELSE !Otherwise,
I2FMT4 = "+!" !Positive overflow.
END IF !So much for that.
END FUNCTION I2FMT4 !No WRITE and FORMAT unlimbering.

CHARACTER*8 FUNCTION I8FMT4(N) !Oh for proper strings.
INTEGER*4 N
CHARACTER*8 HIC
WRITE (HIC,1) N
1 FORMAT (I8)
I8FMT4 = HIC
END FUNCTION I8FMT4
Combinations and permutations lead to ...
INTERFACE I10FMT !Alright, reduce some vexations.
MODULE PROCEDURE I10FMT4,I10FMT2,I10FMT1
END INTERFACE
INTERFACE I8FMT !Sigh.
MODULE PROCEDURE I8FMT4,I8FMT2,I8FMT1
END INTERFACE
INTERFACE I2FMT !Proper strings would enable IFMT alone.
MODULE PROCEDURE I2FMT4,I2FMT2,I2FMT1
END INTERFACE !Perhaps a "string" module could be devised...

INTERFACE FFMT
MODULE PROCEDURE FFMT4,FFMT8
END INTERFACE FFMT
</lang>
On the face of it, the task is easy, but there are traps. Many Fortran compilers do not handle the case of a WRITE statement invoking a WRITE statement as via a function (e.g. <code>WRITE (OUT,"(3A)") "Yes, we have ",IFMT(N)," Bananas!"</code>), or, possibly allow this so long as one or the other, or perhaps both refrain from using a FORMAT in them, or the statements involved do not trigger some detail. Determining exactly what is possible on one compiler is not a good idea, because another compiler may well have different rules, and thereby, portability fades. Thus the I2FMT routines play with simple arithmetic rather than unlimber the FORMAT apparatus (which is also time-consuming: a fortnight back I modified a prog. that systematically used multiple WRITE statements of assorted texts (generating .kml text for Google Earth's system) into one that used compound WRITE statements of those texts and was startled by a fivefold increase in speed of execution), and there is the question of whether it is better to place the two characters one-at-a-time in two statements rather than use // - which is likely to mean that the expression's value is developed in a work area, then that is copied to the recipient. I couldn't face all this with I8FMT, though I did for function SLASHDATE, allowing four digits for the year number - this function gets heavy use in my major project. A second question is whether or not the function name can be used as a variable within the function, not merely as the destination for an assignment of the final result. In other words, function I8FMT's code could write to a variable I8FMT rather than to HIC then assign HIC's content to I8FMT. Similar usages are possible for arithmetic functions, but, some compilers I have encountered fail to do this properly and thereby, portability fades. If recursion is contemplated, then, a recursive function FACT(X) could refer to FACT within itself as a variable, but FACT(X - 1) would be a function invocation, and this protocol would work even for functions with no parameter as in F vs. F().
<lang Fortran>
CHARACTER*10 FUNCTION SLASHDATE(DAYNUM) !This is relatively innocent.
Caution! The Gregorian calendar did not exist prior to 15/10/1582!
Confine expected operation to four-digit years, since fixed-field sizes are in mind.
Can use this function in WRITE statements with FORMAT, since this function does not use them.
Compilers of lesser merit can concoct code that bungles such double usage otherwise.
INTEGER*4 DAYNUM !-32768 to 32767 is just not adequate.
TYPE(DATEBAG) D !Though these numbers are more restrained.
INTEGER N,L !Workers.
IF (DAYNUM.EQ.NOTADAYNUMBER) THEN !Perhaps some work can be dodged.
SLASHDATE = " Undated!!" !No proper day number has been placed.
RETURN !So give up, rather than show odd results.
END IF !So much for confusion.
D = MUNYAD(DAYNUM) !Get the pieces.
IF (D%DAY.GT.9) THEN !Here we go.
SLASHDATE(1:1) = CHAR(D%DAY/10 + ICHAR("0")) !Faster than a table look-up?
ELSE !Even if not,
SLASHDATE(1:1) = " " !This should be quick.
END IF !So much for the tens digit.
SLASHDATE(2:2) = CHAR(MOD(D%DAY,10) + ICHAR("0")) !The units digit.
SLASHDATE(3:3) = "/" !Enough of the day number. The separator.
IF (D%MONTH.GT.9) THEN !Now for the month.
SLASHDATE(4:4) = CHAR(D%MONTH/10 + ICHAR("0")) !The tens digit.
ELSE !Not so often used. A table beckons...
SLASHDATE(4:4) = " " !Some might desire leading zeroes here.
END IF !Enough of October, November and December.
SLASHDATE(5:5) = CHAR(MOD(D%MONTH,10) + ICHAR("0")) !The units digit.
SLASHDATE(6:6) = "/" !Enough of the month number. The separator.
L = 10 !The year value deserves a loop, it having four digits.
N = ABS(D%YEAR) !Should never be zero. 1BC is year -1 and 1AD is year = +1.
1 SLASHDATE(L:L) = CHAR(MOD(N,10) + ICHAR("0")) !But if it is, this will place a zero.
N = N /10 !Drop a power of ten.
L = L - 1 !Step back for the next digit.
IF (L.GT.6) GO TO 1 !Thus always four digits, even if they lead with zero.
IF (N.GT.0) SLASHDATE(7:7) = "?" !Y > 9999? Might as well do something.
IF (D%YEAR.LT.0) SLASHDATE(7:7) = "-" !Years BC? Rather than give no indication.
c WRITE (SLASHDATE,1) D%DAY,D%MONTH,D%YEAR !Some compilers will bungle this.
c 1 FORMAT (I2,"/",I2,"/",I4) !If so, a local variable must be used.
RETURN !Enough. !As when SLASHDATE is invoked in a WRITE statement.
END FUNCTION SLASHDATE !Simple enough.
</lang>
Naturally, I could do a proper job by repeatedly using MOD(N,10) and placing the appropriate digit and dividing N by ten but, aside from the annoyance of the digits coming out backwards (and you don't know how many there will be) there are traps here too. With two's complement, one cannot just determine the sign and then continue with ABS(N), because, in 16 bits, -32768 can't be represented as a positive integer. Very well, work always with negative integers, converting a positive N to negative. Then you discover (or should!) that the MOD function for negative numbers has two styles of behaviour and different computers (and their compilers) may well differ (Prof. Knuth remarks on this in the calculation for the date of Easter). Thus portability fades again. But in this case, because the number of digits resulting is unknown until the deed is done, a scratchpad is needed so that the desired digits only can be returned, with no leading spaces...

Which is pointless in F95, where CHARACTER functions always return a fixed number of characters - so I have routines such as SSPACE to single-space a line of text... Only with the latter day STRING style could this be done properly.