What does C(C) do in BASIC? - syntax

I'm currently trying to understand this BASIC program. I especially have issues with this part:
DIM C(52),D(52)
FOR D=D TO 1 STEP -1
C=C-1
C(C)=D(D)
NEXT D
I guess that it is a for-loop which starts at D where the last executed iteration is D=1 (hence inclusive?)
What does C(C) do? C is an array with 52 elements and I assumed C(X) is an access to the X-th element of the array C. But what does it do when the parameter is C itself?

In the original BASIC program, there is a GOTO 1500 on line 90, which comes before lines 16-19, that you’ve reproduced here. Line 1500 is the start of the program’s main loop. This particular programmer uses the (not uncommon) pattern of placing subroutines at the beginning of their BASIC program, using a GOTO to jump to the main code.
The code you’ve reproduced from the Creative Computing program you’ve linked is a subroutine to “get a card”, as indicated by the comment above that section of code:
100 REM--SUBROUTINE TO GET A CARD. RESULT IS PUT IN X.
REM is a BASIC statement; it stands for “remark”. In modern parlance, it’s a comment.
In BASIC, arrays, strings, and numbers are in separate namespaces. This means that you can (and commonly do) have the same variable name for arrays as for the integer that you use to access the array. The following variables would all be separate in BASIC and not overwrite each other:
C = 12
C(5) = 33
C$ = "Jack of Spades"
C$(5) = "Five of Hearts"
Line 1 is a numeric variable called C.
Line 2 is a numeric array called C.
Line 3 is a string called C.
Line 4 is a string array called C.
A single program could contain all four of those variables without conflict. This is not unknown in modern programming languages; Perl, for example, has very similar behavior. A Perl script can have a number, a string, an array, and a hash all with the same name without conflicting.
If you look at line 1500 of the program you linked and follow through, you’ll see that the variable C is initialized to 53. This means that the first time this subroutine is called, C starts at 53, and gets immediately decremented to 52, which is the number of cards. After the program has run a bit, the value of C will vary.
Basically, this bit of code copies to the array C some values in the array D. It chooses which values of D() to copy to C() using the (most likely integer) numeric variables C and D. As the code steps through D from D’s initial value down to 1, C is also decremented by 1.
If D begins with value 3, and C begins with value 10, this happens:
C(9) = D(3)
C(8) = D(2)
C(7) = D(1)
Note that this example is purely hypothetical; I have not examined the code closely enough to verify that this combination of values is one that can occur in a program run.
A couple of caveats. There are many variations of BASIC, and few absolutes among them. For example, some BASIC dialects will use what looks like a string array as a means of accessing substrings and sometimes even modifying substrings within a string. In these dialects, C$(2) will be the second (or third, if zero-based) character in the string C$. The BASIC program you’ve linked does not appear to be one of those variants, since it uses LEFT$ and MID$ to access substrings.
Second, many BASIC dialects include a DEFSTR command, which defines a variable as a string variable without having to use the “$” marker. If a variable were defined in this manner as a string, it is no longer available as a number. This will often be true of both the scalar and the array forms. For example, consider this transcript using TRS-80 Model III BASIC:
READY
>10 DEFSTR C
>20 C = "HELLO, WORLD"
>30 PRINT C
>40 C(3) = 5
>RUN
HELLO, WORLD
?TM Error IN 40
READY
>
The program successfully accepts a string into the variable C, and prints it; it displays a “Type Mismatch Error” on attempting to assign a number to element 3 of the array C. That’s because DEFSTR C defines both C and C() as strings, and it becomes an error to attempt to assign a number to either of them.
The program you’ve linked likely (but not definitely) runs on a BASIC that supports DEFSTR. However, the program does not make use of it.
Finally, many variants will have a third type of variable for integers, which will not conflict with the others; often, this variable is identified by a “%” in the same way that a string is identified by a “$”:
C = 3.5
C% = 4
C$ = "FOUR"
In such variants, all three of these are separate variables and do not conflict with each other. You’ll often see a DEFINT C at the top of code that uses integers, to define that variable (and the array with the same name) as an integer, to save memory and to make the program run more quickly. BASICs of the era often performed integer calculations significantly faster than floating point/real calculations.

Related

How to do several enumerations type in Fortran?

I tried to declare several enumeration types in Fortran.
This funny simple example illustrates well my problem :
program Main
enum, bind(c)
enumerator :: Colors = 0
enumerator :: Blue = 1
enumerator :: Red = 2
enumerator :: Green = 3
end enum
enum, bind(c)
enumerator :: Size = 0
enumerator :: Small = 1
enumerator :: Medium = 2
enumerator :: Large = 3
end enum
integer(kind(Colors)) :: myColor
myColor = Green
if (myColor == Large) then
write(*,*) 'MyColor is Large'
end if
end program Main
I also tried to enclose this enumeration in a type and many others things but none works.
Here I can compare Colors with Size. In C, for example, when I declare color and a size typedef enum, I have no such problem, because the two types are different.
Does it exist a simple solution to have several enumerated type in Fortran?
Otherwise, I imagine to declare several types with one integer member that holds the value and, after, to create interface to overload the operators I need (comparison, affectation and so on). I am not sure that solution is possible and also, I can do it.
Fortran does not have enumerated types in the sense that you wish to use.1
An enumeration in Fortran is a set of enumerators. The program of the question has two of them.
Enumerators themselves are named (integer) constants of a kind interoperable with C's corresponding enumeration type. They exist for the purposes of C interoperability and not to provide a similar functionality within Fortran.
The enumerators Green and Large in the question are two named integer constants with value 3 (of some, possibly different kind). Green==Large is a true expression whatever the kind parameters of the constants.
There is no mechanism in Fortran to restrict a variable to values of an enumeration. The constants could equivalently be declared as
integer(kind=enum_kind1) :: Green = 3_enum_kind1
integer(kind=enum_kind2) :: Large = 3_enum_kind2
for the appropriate kind values (which are quite likely in this case to be the same: C_INT) and the Fortran program would know no difference.
If you wish to use enumerated types in the sense that they exist in C and similar languages, you will have to use a non-intrinsic approach (as intimated in the question).
1 This is the case for the current, 2018, revision of the language. At this time, there is a proposal for the next revision (provisionally 2023) to include enumerated types closer to what is desired here. This specification is given in 7.6.2 of one particular working draft.

selecting matrices based on a variable

Is there a way I can use a command that selects a matrix to use based on a variable?
Need in this /
:If (way to select a matrix based on what variable L equals) (E,F)=1:Output E,F,"O
I don't want to make a specific go-to for every single matrix I need.
This is for creating maps with the matrix in case anyone has a better way.
If i understand correctly you want to get the value from a certain matrix, chosen dynamically depending on the value of a variable. You can kinda do this by putting the names of the matrices into a string, then grab a substring of the string, using sub(, at a dynamic offset, based on L, and then feeding that string into expr( to get a reference to the matrix, ie
:"[A][B][C]"->Str1, sub(Str1,2,1) yields "[B]", expr("[B]") yields Matrix B...so 2 maps to [B]. TI considers the symbol [A] (and all the other matrix vars) to be a single character, so "[A][B][C]" is a 3 character string.
Note that all of the matrix vars need to be input from the MATRIX menu (including inside the string). Typing in the individual [ A ] chracters will not work.
Also note you can't grab indexes off of a matrix returned with expr (ie expr("[A]")(1,2) so you need an extra matrix (I used [J]) to store the result.
For example
:"MAKE SOME MATRICES"
:[[1,2][3,4]]->[A]
:[[5,6][7,8]]->[B]
:[[9,10],[11,12]]->[C]
:"SAMPLE L VALUE"
:2->L
:"STORE REFERENCES TO THE"
:"MATRICES IN A STRING"
:"[A][B][C]"->Str1
:expr(sub(Str1, L, 1))->[J]
:"SHOWS 6"
:[J](1,2)
so then proceed normally with [J]
:If [J](E,F)
: "DO WHATEVER
Tested on an 84 SE, I assume it would work the same for anything in that family, except IIRC some older models only have matrices A-F

Lua: What is typical approach for using calculated values in a for loop?

What is the typical approach in LUA (before the introduction of integers in 5.3) for dealing with calculated range values in for loops? Mathematical calculations on the start and end values in a numerical for loop put the code at risk of bugs, possibly nasty latent ones as this will only occur on certain values and/or with changes to calculation ordering. Here's a concocted example of a loop not producing the desire output:
a={"a","b","c","d","e"}
maybethree = 3
maybethree = maybethree / 94
maybethree = maybethree * 94
for i = 1,maybethree do print(a[i]) end
This produces the unforuntate output of two items rather than the desired three (tested on 5.1.4 on 64bit x86):
a
b
Programmers unfamiliar with this territory might be further confused by print() output as that prints 3!
The application of a rounding function to the nearest whole number could work here. I understand the approximatation with FP and why this fails, I'm interested in what the typical style/solution is for this in LUA.
Related questions:
Lua for loop does not do all iterations
Lua: converting from float to int
The solution is to avoid this reliance on floating-point math where floating-point precision may become an issue. Or, more realistically, just be aware of when you are using FP and be mindul of the precision issue. This isn’t a Lua problem that requires a Lua-specific solution.
maybethree is a misnomer: it is never three. Your code above is deterministic. It will always print just a and b. Since the maybethree variable is less than three, of course the for loop would not execute 3 times.
The print function is also behaving as defined/expected. Use string.format to show thr FP number in all its glory:
print(string.format("%1.16f", maybethree)) -- 2.9999999999999996
Still need to use calculated values to control your for loop? Then you already mentioned the answer: implement a rounding function.

Why does Pascal forbid modification of the counter inside the for block?

Is it because Pascal was designed to be so, or are there any tradeoffs?
Or what are the pros and cons to forbid or not forbid modification of the counter inside a for-block? IMHO, there is little use to modify the counter inside a for-block.
EDIT:
Could you provide one example where we need to modify the counter inside the for-block?
It is hard to choose between wallyk's answer and cartoonfox's answer,since both answer are so nice.Cartoonfox analysis the problem from language aspect,while wallyk analysis the problem from the history and the real-world aspect.Anyway,thanks for all of your answers and I'd like to give my special thanks to wallyk.
In programming language theory (and in computability theory) WHILE and FOR loops have different theoretical properties:
a WHILE loop may never terminate (the expression could just be TRUE)
the finite number of times a FOR loop is to execute is supposed to be known before it starts executing. You're supposed to know that FOR loops always terminate.
The FOR loop present in C doesn't technically count as a FOR loop because you don't necessarily know how many times the loop will iterate before executing it. (i.e. you can hack the loop counter to run forever)
The class of problems you can solve with WHILE loops is strictly more powerful than those you could have solved with the strict FOR loop found in Pascal.
Pascal is designed this way so that students have two different loop constructs with different computational properties. (If you implemented FOR the C-way, the FOR loop would just be an alternative syntax for while...)
In strictly theoretical terms, you shouldn't ever need to modify the counter within a for loop. If you could get away with it, you'd just have an alternative syntax for a WHILE loop.
You can find out more about "while loop computability" and "for loop computability" in these CS lecture notes: http://www-compsci.swan.ac.uk/~csjvt/JVTTeaching/TPL.html
Another such property btw is that the loopvariable is undefined after the for loop. This also makes optimization easier
Pascal was first implemented for the CDC Cyber—a 1960s and 1970s mainframe—which like many CPUs today, had excellent sequential instruction execution performance, but also a significant performance penalty for branches. This and other characteristics of the Cyber architecture probably heavily influenced Pascal's design of for loops.
The Short Answer is that allowing assignment of a loop variable would require extra guard code and messed up optimization for loop variables which could ordinarily be handled well in 18-bit index registers. In those days, software performance was highly valued due to the expense of the hardware and inability to speed it up any other way.
Long Answer
The Control Data Corporation 6600 family, which includes the Cyber, is a RISC architecture using 60-bit central memory words referenced by 18-bit addresses. Some models had an (expensive, therefore uncommon) option, the Compare-Move Unit (CMU), for directly addressing 6-bit character fields, but otherwise there was no support for "bytes" of any sort. Since the CMU could not be counted on in general, most Cyber code was generated for its absence. Ten characters per word was the usual data format until support for lowercase characters gave way to a tentative 12-bit character representation.
Instructions are 15 bits or 30 bits long, except for the CMU instructions being effectively 60 bits long. So up to 4 instructions packed into each word, or two 30 bit, or a pair of 15 bit and one 30 bit. 30 bit instructions cannot span words. Since branch destinations may only reference words, jump targets are word-aligned.
The architecture has no stack. In fact, the procedure call instruction RJ is intrinsically non-re-entrant. RJ modifies the first word of the called procedure by writing a jump to the next instruction after where the RJ instruction is. Called procedures return to the caller by jumping to their beginning, which is reserved for return linkage. Procedures begin at the second word. To implement recursion, most compilers made use of a helper function.
The register file has eight instances each of three kinds of register, A0..A7 for address manipulation, B0..B7 for indexing, and X0..X7 for general arithmetic. A and B registers are 18 bits; X registers are 60 bits. Setting A1 through A5 has the side effect of loading the corresponding X1 through X5 register with the contents of the loaded address. Setting A6 or A7 writes the corresponding X6 or X7 contents to the address loaded into the A register. A0 and X0 are not connected. The B registers can be used in virtually every instruction as a value to add or subtract from any other A, B, or X register. Hence they are great for small counters.
For efficient code, a B register is used for loop variables since direct comparison instructions can be used on them (B2 < 100, etc.); comparisons with X registers are limited to relations to zero, so comparing an X register to 100, say, requires subtracting 100 and testing the result for less than zero, etc. If an assignment to the loop variable were allowed, a 60-bit value would have to be range-checked before assignment to the B register. This is a real hassle. Herr Wirth probably figured that both the hassle and the inefficiency wasn't worth the utility--the programmer can always use a while or repeat...until loop in that situation.
Additional weirdness
Several unique-to-Pascal language features relate directly to aspects of the Cyber:
the pack keyword: either a single "character" consumes a 60-bit word, or it is packed ten characters per word.
the (unusual) alfa type: packed array [1..10] of char
intrinsic procedures pack() and unpack() to deal with packed characters. These perform no transformation on modern architectures, only type conversion.
the weirdness of text files vs. file of char
no explicit newline character. Record management was explicitly invoked with writeln
While set of char was very useful on CDCs, it was unsupported on many subsequent 8 bit machines due to its excess memory use (32-byte variables/constants for 8-bit ASCII). In contrast, a single Cyber word could manage the native 62-character set by omitting newline and something else.
full expression evaluation (versus shortcuts). These were implemented not by jumping and setting one or zero (as most code generators do today), but by using CPU instructions implementing Boolean arithmetic.
Pascal was originally designed as a teaching language to encourage block-structured programming. Kernighan (the K of K&R) wrote an (understandably biased) essay on Pascal's limitations, Why Pascal is Not My Favorite Programming Language.
The prohibition on modifying what Pascal calls the control variable of a for loop, combined with the lack of a break statement means that it is possible to know how many times the loop body is executed without studying its contents.
Without a break statement, and not being able to use the control variable after the loop terminates is more of a restriction than not being able to modify the control variable inside the loop as it prevents some string and array processing algorithms from being written in the "obvious" way.
These and other difference between Pascal and C reflect the different philosophies with which they were first designed: Pascal to enforce a concept of "correct" design, C to permit more or less anything, no matter how dangerous.
(Note: Delphi does have a Break statement however, as well as Continue, and Exit which is like return in C.)
Clearly we never need to be able to modify the control variable in a for loop, because we can always rewrite using a while loop. An example in C where such behaviour is used can be found in K&R section 7.3, where a simple version of printf() is introduced. The code that handles '%' sequences within a format string fmt is:
for (p = fmt; *p; p++) {
if (*p != '%') {
putchar(*p);
continue;
}
switch (*++p) {
case 'd':
/* handle integers */
break;
case 'f':
/* handle floats */
break;
case 's':
/* handle strings */
break;
default:
putchar(*p);
break;
}
}
Although this uses a pointer as the loop variable, it could equally have been written with an integer index into the string:
for (i = 0; i < strlen(fmt); i++) {
if (fmt[i] != '%') {
putchar(fmt[i]);
continue;
}
switch (fmt[++i]) {
case 'd':
/* handle integers */
break;
case 'f':
/* handle floats */
break;
case 's':
/* handle strings */
break;
default:
putchar(fmt[i]);
break;
}
}
It can make some optimizations (loop unrolling for instance) easier: no need for complicated static analysis to determine if the loop behavior is predictable or not.
From For loop
In some languages (not C or C++) the
loop variable is immutable within the
scope of the loop body, with any
attempt to modify its value being
regarded as a semantic error. Such
modifications are sometimes a
consequence of a programmer error,
which can be very difficult to
identify once made. However only overt
changes are likely to be detected by
the compiler. Situations where the
address of the loop variable is passed
as an argument to a subroutine make it
very difficult to check, because the
routine's behaviour is in general
unknowable to the compiler.
So this seems to be to help you not burn your hand later on.
Disclaimer: It has been decades since I last did PASCAL, so my syntax may not be exactly correct.
You have to remember that PASCAL is Nicklaus Wirth's child, and Wirth cared very strongly about reliability and understandability when he designed PASCAL (and all of its successors).
Consider the following code fragment:
FOR I := 1 TO 42 (* THE UNIVERSAL ANSWER *) DO FOO(I);
Without looking at procedure FOO, answer these questions: Does this loop ever end? How do you know? How many times is procedure FOO called in the loop? How do you know?
PASCAL forbids modifying the index variable in the loop body so that it is POSSIBLE to know the answers to those questions, and know that the answers won't change when and if procedure FOO changes.
It's probably safe to conclude that Pascal was designed to prevent modification of a for loop index inside the loop. It's worth noting that Pascal is by no means the only language which prevents programmers doing this, Fortran is another example.
There are two compelling reasons for designing a language that way:
Programs, specifically the for loops in them, are easier to understand and therefore easier to write and to modify and to verify.
Loops are easier to optimise if the compiler knows that the trip count through a loop is established before entry to the loop and invariant thereafter.
For many algorithms this behaviour is the required behaviour; updating all the elements in an array for example. If memory serves Pascal also provides do-while loops and repeat-until loops. Most, I guess, algorithms which are implemented in C-style languages with modifications to the loop index variable or breaks out of the loop could just as easily be implemented with these alternative forms of loop.
I've scratched my head and failed to find a compelling reason for allowing the modification of a loop index variable inside the loop, but then I've always regarded doing so as bad design, and the selection of the right loop construct as an element of good design.
Regards
Mark

Generating random number in a given range in Fortran 77

I am a beginner trying to do some engineering experiments using fortran 77. I am using Force 2.0 compiler and editor. I have the following queries:
How can I generate a random number between a specified range, e.g. if I need to generate a single random number between 3.0 and 10.0, how can I do that?
How can I use the data from a text file to be called in calculations in my program. e.g I have temperature, pressure and humidity values (hourly values for a day, so total 24 values in each text file).
Do I also need to define in the program how many values are there in the text file?
Knuth has released into the public domain sources in both C and FORTRAN for the pseudo-random number generator described in section 3.6 of The Art of Computer Programming.
2nd question:
If your file, for example, looks like:
hour temperature pressure humidity
00 15 101325 60
01 15 101325 60
... 24 of them, for each hour one
this simple program will read it:
implicit none
integer hour, temp, hum
real p
character(80) junkline
open(unit=1, file='name_of_file.dat', status='old')
rewind(1)
read(1,*)junkline
do 10 i=1,24
read(1,*)hour,temp,p,hum
C do something here ...
10 end
close(1)
end
(the indent is a little screwed up, but I don't know how to set it right in this weird environment)
My advice: read up on data types (INTEGER, REAL, CHARACTER), arrays (DIMENSION), input/output (READ, WRITE, OPEN, CLOSE, REWIND), and loops (DO, FOR), and you'll be doing useful stuff in no time.
I never did anything with random numbers, so I cannot help you there, but I think there are some intrinsic functions in fortran for that. I'll check it out, and report tomorrow. As for the 3rd question, I'm not sure what you ment (you don't know how many lines of data you'll be having in a file ? or ?)
You'll want to check your compiler manual for the specific random number generator function, but chances are it generates random numbers between 0 and 1. This is easy to handle - you just scale the interval to be the proper width, then shift it to match the proper starting point: i.e. to map r in [0, 1] to s in [a, b], use s = r*(b-a) + a, where r is the value you got from your random number generator and s is a random value in the range you want.
Idigas's answer covers your second question well - read in data using formatted input, then use them as you would any other variable.
For your third question, you will need to define how many lines there are in the text file only if you want to do something with all of them - if you're looking at reading the line, processing it, then moving on, you can get by without knowing the number of lines ahead of time. However, if you are looking to store all the values in the file (e.g. having arrays of temperature, humidity, and pressure so you can compute vapor pressure statistics), you'll need to set up storage somehow. Typically in FORTRAN 77, this is done by pre-allocating an array of a size larger than you think you'll need, but this can quickly become problematic. Is there any chance of switching to Fortran 90? The updated version has much better facilities for dealing with standardized dynamic memory allocation, not to mention many other advantages. I would strongly recommend using F90 if at all possible - you will make your life much easier.
Another option, depending on the type of processing you're doing, would be to investigate algorithms that use only single passes through data, so you won't need to store everything to compute things like means and standard deviations, for example.
This subroutine generate a random number in fortran 77 between 0 and ifin
where i is the seed; some great number such as 746397923
subroutine rnd001(xi,i,ifin)
integer*4 i,ifin
real*8 xi
i=i*54891
xi=i*2.328306e-10+0.5D00
xi=xi*ifin
return
end
You may modifies in order to take a certain range.

Resources