Fortran77 User Input Validation - validation

I need the user to enter only real numbers when prompted. An error message should be displayed and program should stop in case the user enters a character or any other symbol. How can i do this in fortran 77.

I assumed, you probably want to have more tries, because what you have in your question does the compiler does automatically.
You can use the IOSTAT= or ERR= specifiers.
INTEGER IE
DO I = 1, MAX
READ(*,*,IOSTAT=IE) X
IF (IE.eq.0) GOTO 10
PRINT *,"Wrong input, try again."
END DO
10 CONTINUE
or
GOTO 10
20 PRINT *,"Wrong input, try again."
10 READ(*,*,ERR=20) X

improving the user interface a little, i like to read a string, then do the error check on an internal read:
character insting*80
ie=1
do while(ie.ne.0)
read(*,'(a)')instring
if(instring(1:1).eq.'q')stop
read(instring,*,iostat=ie)x
if(ie.ne.0)then
write(*,*)'invalid input ',trim(instring),' is not a real number'
endif
enddo
(note trim is not f77 btw, but its easy enough to replicate if needed)
Note, with some effort you can handle the pathalogic cases. A leading '/' or ',' throws no error but leaves the value of x unchanged (likely system/compiler dependent however!), so you can do something like this:
x=-999999.
read(instring,*,iostat=ie)x
if(ie.eq.0.and.x.eq.-999999.)then
.. code to handle error..
endif
You could alternately use index to look for the bad characters. On my system a decimal . by itself is taken as zero. That gets a bit cumbersome to handle, but it can be done by parsing instring

Related

Trying to display what position the matrix editor is at

I have a TI-84 Plus CE (although I kind of want it to be backwards compatible, and compatible with the nSPIRE and TI-84 Plus)
I am trying to output onto the screen what position the matrix editor is at, and I am getting an ERROR:syntax, although (to the best of my knowledge about this language) the statement is valid.
my code is:
:Input "NUM OF ROWS?",A
:Input "NUM OF COLUMNS?",B
:{A,B}->dim([A])
:For(R,1,A)
:For(C,1,B)
:Disp "LOCATION: ("R","C")"
:Input "VALUE?",E
:E->[A](C,D)
:End
:End
:ChiSquared-Test([A],[B])
side note: i'm also getting a "divide by zero error" on the chi-squared test, for an unknown reason.
Fixed The Problem!
FIX:
Disp "Matrix Location:",{R,C}
The Reason the error happened was because in TI Basic, the option to have variables displayed outside the text is not available, so you have to do a 2 line display with the description in the first line, and the matrix location in the next line.
(R,C) when in a Disp statement throw an error, so you need to use the curly brackets instead like so: {R,C}.

Creating a variable to measure string length

So I'm curious as to what I'm missing here. I have a program for school and part of the program requires that I measure the length of the input string. I have it laid out as "if String==6" which you can see in my code below. My professor would rather it be stored in a variable and that I use the .length method to measure it. His exact words are as follows, "To see if the ticket number is greater than six characters, you need to store it in a variable. Then, on line 19, you can check it by using ticket.length == 6."
I tried using his method and I put "ticket_number.length==6." but that returns an error. Im not sure why, isnt "ticket_number" the variable that needs measured? Or do I need to create another variable just for ticket length? I'm sure there is an easy answer, I just cant seem to find it. Thanks in advance for any and all help!
begin
print "Please enter your six-digit ticket number."
ticket_number=gets.chomp.to_i
ones_digit=ticket_number%10
truncated_number=ticket_number/10.floor
remainder=truncated_number%7
if String=6 and ones_digit==remainder and ticket_number>0
print "Your ticket number is valid."
else
print "Your ticket number is invalid."
end
end while ticket_number>0
There's a couple of problems here but the biggest one is that converting to an integer means you've forfeited your opportunity to test vs. length:
ticket_number = gets.chomp
if (ticket_number.length != 6)
puts "Your ticket number must be six digits"
next
end
You can convert after the fact:
ticket_number = ticket_number.to_i
Then do your math.
Ideally you'd wrap this up in a function that, given a ticket number, will return true or false depending on validity. This de-couples it from your display and looping logic, simplifying things.

How do I remove the 'Done' message after my program has executed?

I made a program that is similar to clearing RAM. However, it always leaves a "Done" message followed by a dotted line after being executed. In addition, if you scroll up, you can see that the program was executed. Is there a way to remove both of these things? If you can't hide the fact that a program was executed, could you suppress the 'Done' message?
I have tried adding ClearHome" and " as the last line of my program, and neither stops the Done message from displaying.
Bonus points if your solution can be contained within the original program.
In a separate program, type the following line of code:
AsmPrgmFDCB00AEC9
Then at the end of the original program, type the following line of code:
Asm(prgmPROGRAMNAME
It is recommended that you test this out first with all programs archived, just running the above line of code alone, in case it fails. Hex codes like that one have been known to fail, and sometimes clears the RAM.
You can also try these other hex codes, but always keep in mind the warning above. My RAM has been cleared by this before, so use caution:
http://tibasicdev.wikidot.com/hexcodes
This works on TI 83 and 84, may be different with other calculator types.
EDIT:
I found a way to do this without an external program, and is much simpler.
Just add the following line of code to the end of your program:
Output(1,1," //no space, just a quote
You may or may not have to add ClrHome before that line of code.
This should prevent the Done message from appearing at the end.
Hope this helps!
Put an empty string at the end of your program, so your last line looks like this:
""
Or this
"
The empty string is stored to ans and will be displayed as a blank line rather than the Done message.
There is also an assembly hexcode to do this without leaving the blank line at the top:
FDCB00AEC9
When run at the end of the program using one of the various methods of running assembly, it will leave you with a blank, fully operational homescreen.
Outputting an empty string will prevent the Done message and also preserve Ans, in case a calling program is expecting to use it.
Output(Y,X,"")
See http://tibasicdev.wikidot.com/output for more details on Output(.
In your situation, run Clear Entries (found under Mem), then scroll up so that the Done message is selected and press Clear to get rid of it.

Format statement with unknown columns

I am attempting to use fortran to write out a comma-delimited file for import into another commercial package. The issue is that I have an unknown number of data columns. My output needs to look like this:
a_string,a_float,a_different_float,float_array_elem1,float_array_elem2,...,float_array_elemn
which would result in something that might look like this:
L1080,546876.23,4325678.21,300.2,150.125,...,0.125
L1090,563245.1,2356345.21,27.1245,...,0.00983
I have three issues. One, I would prefer the elements to be tightly grouped (variable column width), two, I do not know how to define a variable number of array elements in the format statement, and three, the array elements can span a large range--maybe 12 orders of magnitude. The following code conceptually does what I want, but the variable 'n' and the lack of column-width definition throws an error (of course):
WRITE(50,900) linenames(ii),loc(ii,1:2),recon(ii,1:n)
900 FORMAT(A,',',F,',',F,n(',',F))
(I should note that n is fixed at run-time.) The write statement does what I want it to when I do WRITE(50,*), except that it's width-delimited.
I think this thread almost answered my question, but I got quite confused: SO. Right now I have a shell script with awk fixing the issue, but that solution is...inelegant. I could do some manipulation to make the output a string, and then just write it, but I would rather like to avoid that option if at all possible.
I'm doing this in Fortran 90 but I like to try to keep my code as backwards-compatible as possible.
the format close to what you want is f0.3, this will give no spaces and a fixed number of decimal places. I think if you want to also lop off trailing zeros you'll need to do a good bit of work.
The 'n' in your write statement can be larger than the number of data values, so one (old school) approach is to put a big number there, eg 100000. Modern fortran does have some syntax to specify indefinite repeat, i'm sure someone will offer that up.
----edit
the unlimited repeat is as you might guess an asterisk..and is evideltly "brand new" in f2008
In order to make sure that no space occurs between the entries in your line, you can write them separately in character variables and then print them out using theadjustl() function in fortran:
program csv
implicit none
integer, parameter :: dp = kind(1.0d0)
integer, parameter :: nn = 3
real(dp), parameter :: floatarray(nn) = [ -1.0_dp, -2.0_dp, -3.0_dp ]
integer :: ii
character(30) :: buffer(nn+2), myformat
! Create format string with appropriate number of fields.
write(myformat, "(A,I0,A)") "(A,", nn + 2, "(',',A))"
! You should execute the following lines in a loop for every line you want to output
write(buffer(1), "(F20.2)") 1.0_dp ! a_float
write(buffer(2), "(F20.2)") 2.0_dp ! a_different_float
do ii = 1, nn
write(buffer(2+ii), "(F20.3)") floatarray(ii)
end do
write(*, myformat) "a_string", (trim(adjustl(buffer(ii))), ii = 1, nn + 2)
end program csv
The demonstration above is only for one output line, but you can easily write a loop around the appropriate block to execute it for all your output lines. Also, you can choose different numerical format for the different entries, if you wish.

Multi-line input problems when using STDIN.gets

Having looked at this question, I have the following code:
$/ = "\0"
answer = STDIN.gets
Now, I was hoping that this would allow the user to:
enter a multi-line input, terminating by pressing Ctrl-D.
enter a single line input, terminating by pressing Ctrl-D.
enter a "nothing" input, terminating by pressing Ctrl-D.
However, the behaviour I actually see is that:
The user can enter a multi-line input fine.
The user can not enter a single line input, unless they hit Ctrl-D twice.
The user can enter a "nothing" input if they hit Ctrl-D straight away.
So, why does the single line situation (i.e. if the user has entered some text but no newline and then hit Ctrl-D) require two presses of Ctrl-D? And why does it work then if the user enters nothing? (I have noted that if they enter nothing and hit Ctrl-D, I don't get an empty string but the nil class - I discovered this when trying to call .empty? on the result, since it suddenly failed horribly. If there is a way to get it to return an empty string as well, that would be nice. I prefer checking .empty? to ==, and don't particularly want to define .empty? for the nil class.)
EDIT: Since I really would like to know the "correct way" to do this in Ruby, I am offering a bounty of 200 rep. I will also accept answers that give another way of entering terminal multi-line input with a sensible "submit" procedure - I will be the judge of 'suitable'. For example, we're currently using two "\n"s, but that's not suitable, as it blocks paragraphs and is unintuitive.
The basic problem is the terminal itself. See many of the related links to the right of your post. To get around this you need to put the terminal in a raw state. The following worked for me on a Solaris machine:
#!/usr/bin/env ruby
# store the old stty settings
old_stty = `stty -g`
# Set up the terminal in non-canonical mode input processing
# This causes the terminal to process one character at a time
system "stty -icanon min 1 time 0 -isig"
answer = ""
while true
char = STDIN.getc
break if char == ?\C-d # break on Ctrl-d
answer += char.chr
end
system "stty #{old_stty}" # restore stty settings
answer
I'm not sure if the storing and restoring of the stty settings is necessary but I've seen other people do it.
When reading STDIN from a terminal device you are working in a slightly different mode to reading STDIN from a file or a pipe.
When reading from a tty Control-D (EOF) only really sends EOF if the input buffer is empty. If it is not empty it returns data to the read system call but does not send EOF.
The solution is to use some lower level IO and read a character at a time. The following code (or somethings similar) will do what you want
#!/usr/bin/env ruby
answer = ""
while true
begin
input = STDIN.sysread(1)
answer += input
rescue EOFError
break
end
end
puts "|#{answer.class}|#{answer}|"
The results of running this code with various inputs are as follows :-
INPUT This is a line<CR><Ctrl-D>
|String|This is a line
|
INPUT This is a line<Ctrl-D>
|String|This is a line|
INPUT<Ctrl-D>
|String||

Resources