How to do several enumerations type in Fortran? - enums

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.

Related

What does C(C) do in BASIC?

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.

Ada random Integer in range of array length

It's a simple question, yet I can't find anything that could help me...
I want to create some random connection between graph nodes. To do this I want do two random indexes and then connect the nodes.
declare
type randRange is range 0..100000;
n1: randRange;
n2: randRange;
package Rand_Int is new ada.numerics.discrete_random(randRange);
use Rand_Int;
gen : Generator;
begin
n1 := random(gen) mod n; -- first node
n2 := random(gen) mod n;
I wanted to define the range with length of my array but I got errors. Still, it doesn't compile.
Also I can't perform modulo as n is natural.
75:15: "Generator" is not visible
75:15: multiple use clauses cause hiding
75:15: hidden declaration at a-nudira.ads:50, instance at line 73
75:15: hidden declaration at a-nuflra.ads:47
And I have no idea what these errors mean - obviously, something is wrong with my generator.
I would appreciate if someone showed me a proper way to do this simple thing.
As others have answered, the invisibility of Generator is due to you having several "use" clauses for packages all of which have a Generator. So you must specify "Rand_Int.Generator" to show that you want the Generator from the Rand_Int package.
The problem with the "non-static expression" happens because you try to define a new type randRange, and that means the compiler has to decide how many bits it needs to use for each value of the type, and for that the type must have compile-time, i.e. static, bounds. You can instead define it as a subtype:
subtype randRange is Natural range 0 .. n-1;
and then the compiler knows that it can use the same number of bits as it uses for the Natural type. (I assume here that "n" is an Integer, or Natural or Positive; otherwise, use whatever type "n" is.)
Using a subtype should also resolve the problem with the "expected type".
You don't show us the whole code neccessary to reproduce the errors, but the error messages suggest you have another use clause somewhere, a use Ada.Numerics.Float_Random;. Either remove that, or specify which generator you want, ie. gen : Rand_Int.Generator;.
As for mod, you should specify the exact range you want when instantiating Discrete_Random instead:
type randRange is 0..n-1; -- but why start at 0? A list of nodes is better decribed with 1..n
package Rand_Int is new ada.numerics.discrete_random(randRange);
Now, there's no need for mod
The error messages you mention have to do with concept of visibility in Ada, which differs from most other languages. Understanding visibility is key to understanding Ada. I recommend that beginners avoid use <package> in order to avoid the visibility issues involved with such use clauses. As you gain experience with the language you can experiment with using common pkgs such as Ada.Text_IO.
As you seem to come from a language in which arrays have to have integer indices starting from zero, I recommend Ada Distilled, which does an excellent job of describing visibility in Ada. It is ISO/IEC 8652:2007, but you should have no difficulty picking up Ada-12 from that basis.
If you're interested in the issues involved in obtaining a random integer value in a subrange of an RNG's result range, or from a floating-point random value, you can look at PragmARC.Randomness.Real_Ranges and PragmARC.Randomness.U32_Ranges in the PragmAda Reusable Components.

Overflow in a random number generator and 4-byte vs. 8-byte integers

The famous linear congruential random number generator also known as minimal standard use formula
x(i+1)=16807*x(i) mod (2^31-1)
I want to implement this using Fortran.
However, as pointed out by "Numerical Recipes", directly implement the formula with default Integer type (32bit) will cause 16807*x(i) to overflow.
So the book recommend Schrage’s algorithm is based on an approximate factorization of m. This method can still implemented with default integer type.
However, I am wondering fortran actually has Integer(8) type whose range is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 which is much bigger than 16807*x(i) could be.
but the book even said the following sentence
It is not possible to implement equations (7.1.2) and (7.1.3) directly
in a high-level language, since the product of a and m − 1 exceeds the
maximum value for a 32-bit integer.
So why can't we just use Integer(8) type to implement the formula directly?
Whether or not you can have 8-byte integers depends on your compiler and your system. What's worse is that the actual value to pass to kind to get a specific precision is not standardized. While most Fortran compilers I know use the number of bytes (so 8 would be 64 bit), this is not guaranteed.
You can use the selected_int_kindmethod to get a kind of int that has a certain range. This code compiles on my 64 bit computer and works fine:
program ran
implicit none
integer, parameter :: i8 = selected_int_kind(R=18)
integer(kind=i8) :: x
integer :: i
x = 100
do i = 1, 100
x = my_rand(x)
write(*, *) x
end do
contains
function my_rand(x)
implicit none
integer(kind=i8), intent(in) :: x
integer(kind=i8) :: my_rand
my_rand = mod(16807_i8 * x, 2_i8**31 - 1)
end function my_rand
end program ran
Update and explanation of #VladimirF's comment below
Modern Fortran delivers an intrinsic module called iso_fortran_env that supplies constants that reference the standard variable types. In your case, one would use this:
program ran
use, intrinsic :: iso_fortran_env, only: int64
implicit none
integer(kind=int64) :: x
and then as above. This code is easier to read than the old selected_int_kind. (Why did R have to be 18 again?)
Yes. The simplest thing is to append _8 to the integer constants to make them 8 bytes. I know it is "old style" Fortran but is is portable and unambiguous.
By the way, when you write:
16807*x mod (2^31-1)
this is equivalent to take the result of 16807*x and use an and with a 32-bit mask where all the bits are set to one except the sign bit.
The efficient way to write it by avoiding the expensive mod functions is:
iand(16807_8*x, Z'7FFFFFFF')
Update after comment :
or
iand(16807_8*x, 2147483647_8)
if your super modern compiler does not have backwards compatibility.

Enums in computer memory

A quote from Wikipedia's article on enumerated types would be the best opening for this question:
In other words, an enumerated type has values that are different from each other, and that can be compared and assigned, but which are not specified by the programmer as having any particular concrete representation in the computer's memory; compilers and interpreters can represent them arbitrarily.
While I understand the definition and uses of enums, I can't yet grasp the interaction between enums and memory — when an enum type is declared without creating an instance of enum type variable, is the type definition stored in memory as a union or a structure? And what is the meaning behind the aforementioned Wiki excerpt?
The Wikipedia excerpt isn't talking specifically about C's enum types. The C standard has some specific requirements for how enums work.
An enumerated type is compatible with either char or some signed or unsigned integer type. The choice of representation is up to the compiler, which must document its choice (it's implementation-defined), but the type must be able to represent all the values of the enumeration.
The values of the enumeration constants start at 0 by default, and increment by 1 for each successive constant:
enum foo {
zero, // equal to 0
one, // equal to 1
two // equal to 2
};
The constants are always of type int, regardless of what the enum type itself is compatible with. (It would have made more sense for the constants to be of the enumerated type; they're of type int for historical reason.)
You can specify values for some or all of the constants -- which means that the values are not necessarily distinct:
enum bar {
two = 2,
deux = 2,
zwei = 2,
one = 1,
dos // implicitly equal to 2
};
Defining an enumerated type doesn't result in anything being stored in memory at run time. If you define an object of the enumerated type, that object's value will be stored in memory (unless it's optimized away), and will occupy sizeof (enum whatever) bytes. It's the same as for objects of any other type.
An enumeration constant is treated as a constant expression. The expression two is treated almost identically to a constant 2.
Note that C++ has some different rules for enum types. Your question is tagged C, so I won't go into details.
It means that the enum constants are not required to be located in memory. You cannot take the addresses of them.
This allows the compiler to replace all references to enum constants with their actual values. For example, the code:
enum { x = 123; }
int y = x;
may compile as if it were:
int y = 123;
When an enum type is declared without creating an instance of enum type variable, is the type definition stored in memory as a union or a structure?
In C, types are mostly compile-time constructs; once the program has been compiled to machine code, all the type information disappears*. Accessing a struct member is instead "access the memory n bytes past this pointer".
So if the compiler inlines all the enums as shown above, then enums do not exist at all in compiled code.
* Except optionally in the debugging info section, but that's usually only read by debuggers.

Untyped set operations in Isabelle

I have the following code in Isabelle:
typedecl type1
typedecl type2
consts
A::"type1 set"
B::"type2 set"
When I want to use union operation with A and B as bellow:
axiomatization where
c0: "A ∩ B = {}"
Since A and B are sets of different types, I get an error of clash of types which makes sense!
I am wondering if there are any counterparts for set operations that they implicitly consider their operands as pure sets (i.e., ignore their types), therefore something like A ∩' B become possible ( ∩' is ∩ operation counterpart in above sense).
PS:
Another workaround is type casting that I wrote this as a separate question here to better organize my questions.
Thanks
Sets in Isabelle/HOL are always typed, i.e., they contain only elements of one type. If you want to have untyped sets, you have to switch to another logic such as Isabelle/ZF.
Similarly, all values in HOL are annotated with their type, and this is fundamental to the logic. Equality, for example, can only be applied to two values of the same type. Hence, there is no notion of equality between values of different types. Consequently, there is no set operation that ignores the type of values, because such an operation would necessarily have to know how to identify values of different types.

Resources