Trim trailing zeros in Fortran print/write - io

How can I print without trailing zeros? For example if there was a function nice:
real*8 ff
ff = -3.5d0
print*, "there are ", nice(ff), " horses"
or a formatter t
print'(a,t,a)', "there are ", ff, " horses"
should give:
there are -3.5 horses

This solution works by limiting the precision (there may be some round off errors after ca 16 decimals) and then checking from the end where the last non-0 character is
function nice(ff) result(out)
character(:), allocatable :: out
character(20) :: str
real*8, intent(in) :: ff
integer ii
write(str,'(f20.8)') ff
str = trim(adjustl(str))
do ii = len_trim(str),1,-1
if (str(ii:ii)/="0") exit
enddo
out = str(1:ii)
end
Note that interval indexing like (ii:ii) is required for strings.

An alternative and easier approach which will work (so long as the total length is smaller than the character array 'CDUMMY') is shown below:
PROGRAM MAIN
IMPLICIT NONE
REAL*8 FF
FF = 3.5
! ***** WRITE FF TO A CHARACTER ARRAY. ONCE IN THIS FORM YOU CAN REMOVE TRAILING SPACES
CHARACTER CDUMMY*12
WRITE(CDUMMY,'(F12.1)') FF
WRITE(*,'(3A)') 'There are ',TRIM(ADJUSTL(CDUMMY)),' horses'
END
If you are not too concerned about spaces (as opposed to trailing zeros), then you could simply write using the format specifier Fx.y. For example, to write a floating point number to one decimal place,set y to 1. x is the total size of the number to be outputted including decimal place. So F6.1 would be okay so long as there are less than '9999.9' horses (I feel sorry for the 10,000th horse). In context, it would like so:
WRITE(*,'(A,F6.1,A)') 'There are ',FF,' horses'
Which would yield the following (the underscores represent spaces):
There are ___3.5 horses

Related

why is this trim text trailing not working?

IDENTIFICATION DIVISION.
PROGRAM-ID. KATA.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-INPUT PIC A(200).
01 WS-OUT PIC A(200).
01 I PIC 9(08).
01 J PIC 9(08).
01 INP-LEN PIC 9(08).
PROCEDURE DIVISION.
DISPLAY "INPUT YOUR STRING"
ACCEPT WS-INPUT
DISPLAY "REVERSING ......."
MOVE FUNCTION LENGTH(FUNCTION TRIM(WS-INPUT TRAILING)) TO INP-LEN
DISPLAY "Just for reference : Your string is "INP-LEN " long"
MOVE 1 to I.
PERFORM VARYING J from INP-LEN by -1 UNTIL J =0
MOVE WS-INPUT(I:1) to WS-OUT(J:1)
MOVE FUNCTION TRIM(WS-OUT TRAILING) TO WS-OUT
ADD 1 to I
END-PERFORM
MOVE FUNCTION TRIM(WS-OUT TRAILING) TO WS-OUT.
DISPLAY WS-OUT
DISPLAY FUNCTION LENGTH(WS-OUT)
STOP RUN.
Run the program for input ctrl test
If you run the program you will see that the length of WS-INPUT is :
Just for reference : Your string is 00000009 long
But if you do that for output it will say length of string is 200
Also the reversed string I get is :
tset lrtc
Which is 200 and not what I set.
Can someone explain where I went wrong and what can I do to fix it ?
(Note : I initially tried with function REVERSE so a simple
MOVE FUNCTION REVERSE(WS-INPUT) TO WS-OUTPUT
same problem was there as well
)
FUNCTION LENGTH (source) takes the length from source, in your case that's WS-OUT, which is PIC A(200) - so the answer 200 is correct.
FUNCTION TRIM (source TRAILING) creates as every function a temporary/internal item - in this case removing trailing SPACES from source.
Because of your MOVE of this temporary item with length 9 to one field which is of length 200 it gets right-padded by spaces.
Only DYNAMIC LENGTH items get a dynamic size by MOVE, all other items always stay with their size. [keeping "ODO" out for simplicity...]
You possibly want a nested function call: TRIM + REVERSE / LENGTH:
DISPLAY FUNCTION LENGTH ( FUNCTION TRIM (WS-OUT) )
DISPLAY "-" FUNCTION REVERSE ( FUNCTION TRIM (WS-IN TRAILING) ) "-"

Enumerating string constants with iota

The following example defines a series of port numbers starting at 3333 using iota.
package main
import (
"fmt"
)
const (
FirstPort = iota+3333
SecondPort
ThirdPort
)
func main() {
hostAndPort := "localhost:"+fmt.Sprint(SecondPort)
fmt.Printf("%s", hostAndPort )
// Output:
// localhost:3334
}
When combining hostname and ports, I'd like to avoid having to wrap the port constant in fmt.Sprint and simply write, for example, "localhost:"+SecondPort. Is there a way to use iota to define the port numbers as string constants, e.g "3334"?
The following doesn't work:
FirstPort = string(iota + 3333)
Neither does
FirstPort = fmt.Sprintf("%d", iota + 3333)
Quoting from Spec: Iota:
Within a constant declaration, the predeclared identifier iota represents successive untyped integer constants.
So iota provides you integer constants. If we want string constants, we need to find a way to convert an integer to its base-10 string representation. This way must be a constant expression, else we can't use it in a constant declaration.
Unfortunately for us, a simple type conversion from integer to string will not yield the base-10 representation of the numerical value, but:
Converting a signed or unsigned integer value to a string type yields a string containing the UTF-8 representation of the integer.
So the result will be a string holding a single rune, whose value (the Unicode codepoint) is the source number.
Also calling "converter" functions such as strconv.Itoa() or fmt.Sprint() is out of the question, as calling those functions cannot be part of a constant expression, so the result could only be used in a variable declaration (not to mention we couldn't use iota, it's only allowed in constant declarations).
But there is still a solution.
I don't think it is worth the hassle and the loss of readability, but actually you can define string constants holding increasing decimal numbers using iota.
The solution builds the "complete" numbers from digits. We can obtain the base-10 string representation by concatenating the digits (as string values) of the number.
Last question to solve for this is how to "list" the digits of a number. This is simple arithmetic:
The last digit (in base 10) of a number is i % 10.
The preceding digit is i / 10 % 10.
The one before that is i / 100 % 10.
And so on...
And to obtain the rune for a digit (which is in the range of 0..9), we can simply add '0' to it, and convert it to string. And that's all.
This is how we can code this for a 1-digit string number:
n0 = string('0'+iota%10)
For a 2-digit number:
n00 = string('0'+iota/10%10) + string('0'+iota/1%10)
For a 3-digit number:
n000 = string('0'+iota/100%10) + string('0'+iota/10%10) + string('0'+iota/1%10)
Let's see it in action:
const (
P00 = string('0'+iota/10%10) + string('0'+iota/1%10)
P01
P02
P03
P04
P05
P06
P07
P08
P09
P10
P11
P12
P13
P14
P15
P16
P17
P18
P19
P20
)
Printing the results:
fmt.Printf("%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n%v\n",
P00, P01, P02, P03, P04, P05, P06, P07, P08, P09,
P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20)
Output (try it on the Go Playground):
00
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
So far so good, but how do we make it start at 3333?
Also not a problem, can be achieved easily. We can shift the iota, simply by adding an "initial" number to it. And that's all it takes.
Let's see an example where the first number will be 3339:
const (
P3339 = string('0'+(iota+3339)/1000%10) +
string('0'+(iota+3339)/100%10) +
string('0'+(iota+3339)/10%10) +
string('0'+(iota+3339)/1%10)
P3340
P3341
)
func main() {
fmt.Println(P3339)
fmt.Println(P3340)
fmt.Println(P3341)
}
Output of the above is the expected (try it on the Go Playground):
3339
3340
3341
You're creating untyped numeric constants. When in doubt, check the spec. To create a string with host and port number, you can simply use fmt.Sprintf like so:
package main
const (
FirstPort = iota+3333
SecondPort
ThirdPort
)
func main() {
hostPort := fmt.Sprintf("localhost:%d", FirstPort)
fmt.Println(hostPort)
}
That's all there's too it: Demo

Number to string with leading (left padded) zeros in Julialang

It seems as an easy question, but I cannot find the answer anywhere. If I have an integer variable, how can I transform it to a string with leading zeros?
I want something as the code below:
n = 4
string_size = 3
println(fleading(n, string_size))
# result should be "004"
Where fleading would be something like the function to transform the number to string with leading zeros. The analogous way in python is str(4).zfill(3) which gives 004 as result.
You're looking for the lpad() (for left pad) function:
julia> lpad(4,3,"0")
"004"
Note the last argument must be a string.
From the documentation:
lpad(string, n, "p")
Make a string at least n columns wide when printed, by padding on the left
with copies of p.
For Julia 1.0 the syntax is:
lpad(s, n::Integer, p::Union{AbstractChar,AbstractString}=' ')
The example is therefore:
julia> lpad(4, 3, '0')
004
There is also #printf("%03i",4) using Printf.#printf

How can I write a to_upper() or to_lower() function in F90?

How does one write a (Intel) F90 function that converts a string into lowercase (or, alternatively, uppercase)? I want to pass a character array to the function and have it return a character array, e.g.
program main
implicit none
character*32 :: origStr = "Hello, World!"
character*32 :: newStr
newStr = to_lower(origStr)
write (*,*) newStr
end program main
such that this program outputs hello, world!.
I've been starting with the to_lower() subroutine found at RosettaCode, but I can't figure out how to write it as a function.
Thanks in advance!
PS -- Bonus points if you can do it with a string of unfixed length!
Wow -- even though I'd searched for over an hour, immediately after posting this, I found an answer here (under "Miscellaneous Fortran Hints and Tips").
The code I used is as follows (for to_upper):
function to_upper(strIn) result(strOut)
! Adapted from http://www.star.le.ac.uk/~cgp/fortran.html (25 May 2012)
! Original author: Clive Page
implicit none
character(len=*), intent(in) :: strIn
character(len=len(strIn)) :: strOut
integer :: i,j
do i = 1, len(strIn)
j = iachar(strIn(i:i))
if (j>= iachar("a") .and. j<=iachar("z") ) then
strOut(i:i) = achar(iachar(strIn(i:i))-32)
else
strOut(i:i) = strIn(i:i)
end if
end do
end function to_upper
Hope this helps somebody!
Here's one that doesn't rely on the ASCII representation
Pure Function to_upper (str) Result (string)
! ==============================
! Changes a string to upper case
! ==============================
Implicit None
Character(*), Intent(In) :: str
Character(LEN(str)) :: string
Integer :: ic, i
Character(26), Parameter :: cap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Character(26), Parameter :: low = 'abcdefghijklmnopqrstuvwxyz'
! Capitalize each letter if it is lowecase
string = str
do i = 1, LEN_TRIM(str)
ic = INDEX(low, str(i:i))
if (ic > 0) string(i:i) = cap(ic:ic)
end do
End Function to_upper
You can easily change this to to_lower by switching the low and cap strings in the loop.
As the original author of this code, I'm pleased that it's of some help. I used to wonder why these functions were not built in to Fortran. My guess is that they only work for a rather restricted set of letters, i.e. the ones used in English. If you have text in almost any other European language you will have characters with accents, and then converting them to upper or lower case is much harder. For example e-grave in French turned into upper case is usually shown as just plain E (the grave accent gets lost), but in e-acute it does not. The designers of Fortran have always tried to provide facilities which suit a wide range of languages, and doing upper/lower case conversion in a multi-language way is not at all easy. At least that's my guess as to why you have to do it yourself.

Array of Strings in Fortran 77

I've a question about Fortran 77 and I've not been able to find a solution.
I'm trying to store an array of strings defined as the following:
character matname(255)*255
Which is an array of 255 strings of length 255.
Later I read the list of names from a file and I set the content of the array like this:
matname(matcount) = mname
EDIT: Actually mname value is hardcoded as mname = 'AIR' of type character*255, it is a parameter of a function matadd() which executes the previous line. But this is only for testing, in the future it will be read from a file.
Later on I want to print it with:
write(*,*) matname(matidx)
But it seems to print all the 255 characters, it prints the string I assigned and a lot of garbage.
So that is my question, how can I know the length of the string stored?
Should I have another array with all the lengths?
And how can I know the length of the string read?
Thanks.
You can use this function to get the length (without blank tail)
integer function strlen(st)
integer i
character st*(*)
i = len(st)
do while (st(i:i) .eq. ' ')
i = i - 1
enddo
strlen = i
return
end
Got from here: http://www.ibiblio.org/pub/languages/fortran/ch2-13.html
PS: When you say: matname(matidx) it gets the whole string(256) chars... so that is your string plus blanks or garbage
The function Timotei posted will give you the length of the string as long as the part of the string you are interested in only contains spaces, which, if you are assigning the values in the program should be true as FORTRAN is supposed to initialize the variables to be empty and for characters that means a space.
However, if you are reading in from a file you might pick up other control characters at the end of the lines (particularly carriage return and/or line feed characters, \r and/or \n depending on your OS). You should also toss those out in the function to get the correct string length. Otherwise you could get some funny print statements as those characters are printed as well.
Here is my version of the function that checks for alternate white space characters at the end besides spaces.
function strlen(st)
integer i,strlen
character st*(*)
i = len(st)
do while ((st(i:i).eq.' ').or.(st(i:i).eq.'\r').or.
+ (st(i:i).eq.'\n').or.(st(i:i).eq.'\t'))
i = i - 1
enddo
strlen = i
return
end
If there are other characters in the "garbage" section this still won't work completely.
Assuming that it does work for your data, however, you can then change your write statement to look like this:
write(*,*) matname(matidx)(1:strlen(matname(matidx)))
and it will print out just the actual string.
As to whether or not you should use another array to hold the lengths of the string, that is up to you. the strlen() function is O(n) whereas looking up the length in a table is O(1). If you find yourself computing the lengths of these static strings often, it may improve performance to compute the length once when they are read in, store them in an array and look them up if you need them. However, if you don't notice the slowdown, I wouldn't worry about it.
Depending on the compiler that you are using, you may be able to use the trim() intrinsic function to remove any leading/trailing spaces from a string, then process it as you normally would, i.e.
character(len=25) :: my_string
my_string = 'AIR'
write (*,*) ':', trim(my_string), ':'
should print :AIR:.
Edit:
Better yet, it looks like there is a len_trim() function that returns the length of a string after it has been trimmed.
intel and Compaq Visual Fortran have the intrinsic function LEN_TRIM(STRING) which returns the length without trailing blanks or spaces.
If you want to suppress leading blanks or spaces, use "Adjust Left" i.e. ADJUSTF(STRING)
In these FORTRANs I also note a useful feature: If you pass a string in to a function or subroutine as an argument, and inside the subroutine it is declared as CHARACTER*(*), then
using the LEN(STRING) function in the subroutine retruns the actual string length passed in, and not the length of the string as declared in the calling program.
Example:
CHARACTER*1000 STRING
.
.
CALL SUBNAM(STRING(1:72)
SUBROUTINE SYBNAM(STRING)
CHARACTER*(*) STRING
LEN(STRING) will be 72, not 1000

Resources