I don't recall textbooks and tutorials recommending that the
KIND of logical variables be specified (they do so for reals),
and I have always used the default logical. Using (kind=1) logical
variables would save memory since default logical variables occupy
the same memory as default integers and reals.
A program illustrating logical kinds is below. It gives output
4 4 4
1 2 4 8
on gfortran, Intel Fortran, and flang.
program test_logical
implicit none
logical :: tf
logical(kind=1) :: tf1
logical(kind=2) :: tf2
logical(kind=4) :: tf4
logical(kind=8) :: tf8
print "(*(i3))",kind(0),kind(0.0),kind(tf)
print "(*(i3))",kind(tf1),kind(tf2),kind(tf4),kind(tf8)
end program test_logical
I don't recall textbooks and tutorials recommending that the KIND of logical variables be specified (they do so for reals), and I have always used the default logical.
On 3/21/2022 12:07 PM, Beliavsky wrote:
I don't recall textbooks and tutorials recommending that the KIND of logical variables be specified (they do so for reals), and I have always used the default logical.I discuss some of this in https://stevelionel.com/drfortran/2000/04/29/doctor-fortran-in-to-eqv-or-to-neqv-that-is-the-question-or-its-only-logical/
I'll also note that Fortran 202x will add a
SELECTED_LOGICAL_KIND(bits) function if you care about this. F2018 has a LOGICAL_KINDS named constant in intrinsic module ISO_FORTRAN_ENV.
On Monday, March 21, 2022 at 9:07:59 AM UTC-7, Beliavsky wrote:
I don't recall textbooks and tutorials recommending that the KIND
of logical variables be specified (they do so for reals), and I have
always used the default logical. Using (kind=1) logical variables
would save memory since default logical variables occupy the
same memory as default integers and reals.
Fortran requires that default INTEGER, REAL, and LOGICAL be the same
size. That is convenient when using EQUIVALENCE.
Smaller size means less memory, but on systems today memory size
is often not a big problem. And not so many programs use large arrays
of LOGICAL.
Has anyone written programs with (kind=1) logical variables and
compared their speed with programs using default logical variables?
It would depend on how they are used. There was a Stack Overflow
thread https://stackoverflow.com/questions/22125504/why-we-need-1-2-4-8-bytes-to-store-logical-variable-in-fortran.
Yes it depends on how they are used. Most machines now have a
cache, which makes speed very dependent on access patterns.
If you randomly access elements of a very large array, most references
will not be in cache, and the limit is the speed of main memory.
If you sequentially access elements of a 2D (or more) array, along
a dimension that is not sequential in memory, you also often miss
the cache on every access.
In the case of cache miss, it will pull the whole cache line from main
memory (or maybe from the next level cache), such that byte and word
access times are likely equal.
Otherwise, many problems that use large arrays of LOGICAL, should
instead be large arrays of bits. (Especially if you are doing bitmap graphics.). In that case, using bitwise logical functions allows for such access, though sometimes the program logic is different.
One more case to consider. Using an intrinsic function with a MASK=
argument, with a logical expression. Consider:
MAXLOC(A, MASK=A>0)
Logically, and possibly physically, the program generates a LOGICAL array
of A>0, and then uses this array for MAXLOC.
And you don't know what KIND
of logical array it generates.
I don't recall textbooks and tutorials recommending that the KIND
of logical variables be specified (they do so for reals), and I have
always used the default logical. Using (kind=1) logical variables
would save memory since default logical variables occupy the
same memory as default integers and reals.
Has anyone written programs with (kind=1) logical variables and
compared their speed with programs using default logical variables?
It would depend on how they are used. There was a Stack Overflow
thread https://stackoverflow.com/questions/22125504/why-we-need-1-2-4-8-bytes-to-store-logical-variable-in-fortran.
If you randomly access elements of a very large array, most references
will not be in cache, and the limit is the speed of main memory.
If you sequentially access elements of a 2D (or more) array, along
a dimension that is not sequential in memory, you also often miss
the cache on every access.
In the case of cache miss, it will pull the whole cache line from main memory (or maybe from the next level cache), such that byte and word
access times are likely equal.
It's actually a bit more complicated. Modern systems have several
level of caches, typically three. L1 cache is the fastest and
smallest, L2 intermediate and L3 biggest and slowest. And then
comes main memory, which is glacial in terms of cycles.
On Monday, March 21, 2022 at 9:07:59 AM UTC-7, Beliavsky wrote:
I don't recall textbooks and tutorials recommending that the KINDFortran requires that default INTEGER, REAL, and LOGICAL be the same
of logical variables be specified (they do so for reals), and I have
always used the default logical. Using (kind=1) logical variables
would save memory since default logical variables occupy the
same memory as default integers and reals.
size. That is convenient when using EQUIVALENCE.
Smaller size means less memory, but on systems today memory size
is often not a big problem. And not so many programs use large arrays
of LOGICAL.
Has anyone written programs with (kind=1) logical variables andYes it depends on how they are used. Most machines now have a
compared their speed with programs using default logical variables?
It would depend on how they are used. There was a Stack Overflow
thread https://stackoverflow.com/questions/22125504/why-we-need-1-2-4-8-bytes-to-store-logical-variable-in-fortran.
cache, which makes speed very dependent on access patterns.
If you randomly access elements of a very large array, most references
will not be in cache, and the limit is the speed of main memory.
If you sequentially access elements of a 2D (or more) array, along
a dimension that is not sequential in memory, you also often miss
the cache on every access.
In the case of cache miss, it will pull the whole cache line from main
memory (or maybe from the next level cache), such that byte and word
access times are likely equal.
Otherwise, many problems that use large arrays of LOGICAL, should
instead be large arrays of bits. (Especially if you are doing bitmap graphics.). In that case, using bitwise logical functions allows for such access, though sometimes the program logic is different.
One more case to consider. Using an intrinsic function with a MASK=
argument, with a logical expression. Consider:
MAXLOC(A, MASK=A>0)
Logically, and possibly physically, the program generates a LOGICAL array
of A>0, and then uses this array for MAXLOC. And you don't know what KIND
of logical array it generates.
Otherwise, many years ago we had the IBM OS/360 Fortran G and H compilers, with the only one byte type being LOGICAL*1. You can't use relational operators,
such as .EQ. with LOGICAL values, at least not in Fortran 66.
They were, though,
often useful for character (before CHARACTER variables) data, when you didn't need to compare it.
I don't recall textbooks and tutorials recommending that the KIND of logical variables be specified (they do so for reals), and I have always used the default logical. Using (kind=1)
logical variables would save memory since default logical variables occupy the same memory as default integers and reals. Has anyone written programs with (kind=1) logical variables and compared their speed with programs using default logical variables?It would depend on how they are used. There was a Stack Overflow thread https://stackoverflow.com/questions/22125504/why-we-need-1-2-4-8-bytes-to-store-logical-variable-in-fortran.
A program illustrating logical kinds is below. It gives output
4 4 4
1 2 4 8
on gfortran, Intel Fortran, and flang.
program test_logical
implicit none
logical :: tf
logical(kind=1) :: tf1
logical(kind=2) :: tf2
logical(kind=4) :: tf4
logical(kind=8) :: tf8
print "(*(i3))",kind(0),kind(0.0),kind(tf)
print "(*(i3))",kind(tf1),kind(tf2),kind(tf4),kind(tf8)
end program test_logical
On 3/21/2022 12:07 PM, Beliavsky wrote:
I don't recall textbooks and tutorials recommending that the KIND of logical variables be specified (they do so for reals), and I have always used the default logical.I discuss some of this in https://stevelionel.com/drfortran/2000/04/29/doctor-fortran-in-to-eqv-or-to-neqv-that-is-the-question-or-its-only-logical/
I'll also note that Fortran 202x will add a
SELECTED_LOGICAL_KIND(bits) function if you care about this. F2018 has a LOGICAL_KINDS named constant in intrinsic module ISO_FORTRAN_ENV.
I don't recall textbooks and tutorials recommending that the KIND of
logical variables be specified (they do so for reals), and I have always
used the default logical. Using (kind=1) logical variables would save
memory since default logical variables occupy the same memory as
default integers and reals. Has anyone written programs with (kind=1)
logical variables and compared their speed with programs using
default logical variables? It would depend on how they are used.
There was a Stack Overflow thread https://stackoverflow.com/questions/22125504/why-we-need-1-2-4-8-bytes-to-store-logical-variable-in-fortran.
One more case to consider. Using an intrinsic function with a MASK= argument, with a logical expression. Consider:
MAXLOC(A, MASK=A>0)
Logically, and possibly physically, the program generates a LOGICAL array of A>0, and then uses this array for MAXLOC.
For the simple case you outlined, I would expect a good compiler
to generate a loop. This is not always possible, for example for
MAXLOC(A, MASK=A>0, dim=n)
where n is a variable. In this case, I would expect the
compiler to generate a call to a library function.
If space matters, you need bit arrays. Also they can help in terms of parallelism in that AVX can perform 256 LOGICAL operations in
parallel in one instruction with throughput of 2 per clock cycle.
Try timing a sieve of Eratosthenes that is not cache-aware with the
various LOGICAL kinds and bit arrays and see how far each can get
in, say, 10 seconds. Actually the sieve is a difficult problem in that
you need several different techniques to get the best speed at each
problem size.
Many bitwise algorithms can be written for word-wide bitwise operators.
Not having written one, I suspect that the sieve of Eratosthenes is one.
On Monday, March 21, 2022 at 9:08:26 PM UTC-7, James Van Buskirk wrote:
Try writing something up and posting your code and results.
"gah4" wrote in message
news:9e67bb40-eff4-4729...@googlegroups.com...
Many bitwise algorithms can be written for word-wide bitwise operators.
Not having written one, I suspect that the sieve of Eratosthenes is one.
Try writing something up and posting your code and results.
On Monday, March 21, 2022 at 2:50:51 PM UTC-7, Thomas Koenig wrote:
(snip, I wrote)
One more case to consider. Using an intrinsic function with a MASK=
argument, with a logical expression. Consider:
MAXLOC(A, MASK=A>0)
Logically, and possibly physically, the program generates a LOGICAL array >> > of A>0, and then uses this array for MAXLOC.
For the simple case you outlined, I would expect a good compiler
to generate a loop. This is not always possible, for example for
MAXLOC(A, MASK=A>0, dim=n)
where n is a variable. In this case, I would expect the
compiler to generate a call to a library function.
About 20 years ago, some people would try to figure out the complicated combination of intrinsic functions to replace a DO loop.
But also at that
time, compilers were just starting to implement these functions, and likely did not use a loop. I suspect no compilers generate a loop for:
MAXLOC(TRANSPOSE(A),MASK=TRANSPOSE(A)>0,BACK=SIZE(A,1)>SIZE(A,2))
(Not that I know why anyone would do that, but I suspect there are some equally hard cases for compilers to figure out, and that people actually write.)
"gah4" wrote in message
news:9e67bb40-eff4-4729...@googlegroups.com...
Many bitwise algorithms can be written for word-wide bitwise operators.
Not having written one, I suspect that the sieve of Eratosthenes is one.
Try writing something up and posting your code and results.
James Van Buskirk <not_valid@comcast.net> schrieb:
D:\gfortran\james\sieves>type sieve.f90
module sieve_stuff
use ISO_FORTRAN_ENV
integer iLoop
integer, parameter :: logLens(*) = &
[(size(transfer(logical(.FALSE.,LOGICAL_KINDS(iLoop)),[0_INT8])),
&
iLoop = 1,size(LOGICAL_KINDS))]
end module sieve_stuff
What is this supposed to do? Is this a Sieve of Erastosthenes?
"gah4" wrote in message news:ba2fcfca-bda9-4d74-a34d-d69f70946f50n@googlegroups.com...
On Monday, March 21, 2022 at 9:08:26 PM UTC-7, James Van Buskirk wrote:
Try writing something up and posting your code and results.
[snip]
I can see why you are hesitant to try writing anything:
D:\gfortran\james\sieves>type sieve.f90
module sieve_stuff
use ISO_FORTRAN_ENV
integer iLoop
integer, parameter :: logLens(*) = &
[(size(transfer(logical(.FALSE.,LOGICAL_KINDS(iLoop)),[0_INT8])), &
iLoop = 1,size(LOGICAL_KINDS))]
end module sieve_stuff
James Van Buskirk <not_valid@comcast.net> schrieb:
The first thing to do is to find the BIT_SIZE of the various logical
kinds.
Why would do you want to know that for the sieve of Erastosthenes?
For a bit field, integers are better thant logicals (which
have so many restrictions that you are likely to run into
undefined behavior).
This is an example of how this syntax where an array-implied-do
variable is a constant expression makes compilers suffer :(
NAG Fortran will give you the values of 1,2,4,8 in your array.
What are you going to use them for?
"Thomas Koenig" wrote in message news:t1d2hn$o4v$2@newsreader4.netcologne.de...
James Van Buskirk <not_valid@comcast.net> schrieb:
D:\gfortran\james\sieves>type sieve.f90
module sieve_stuff
use ISO_FORTRAN_ENV
integer iLoop
integer, parameter :: logLens(*) = &
[(size(transfer(logical(.FALSE.,LOGICAL_KINDS(iLoop)),[0_INT8])),
&
iLoop = 1,size(LOGICAL_KINDS))]
end module sieve_stuff
What is this supposed to do? Is this a Sieve of Erastosthenes?
The first thing to do is to find the BIT_SIZE of the various logical kinds.
This is an example of how this syntax where an array-implied-do
variable is a constant expression makes compilers suffer :(
"Thomas Koenig" wrote in message news:t1d89k$uaq$1@newsreader4.netcologne.de...
James Van Buskirk <not_valid@comcast.net> schrieb:
The first thing to do is to find the BIT_SIZE of the various logical
kinds.
Why would do you want to know that for the sieve of Erastosthenes?
For a bit field, integers are better thant logicals (which
have so many restrictions that you are likely to run into
undefined behavior).
This branch of the discussion was about comparing the performance
of the various logical kinds and bitfields using the Sieve of Eratosthenes
as a test case. Thus it's worthwhile to know what the sizes are because
not all compilers map size in bytes directly to kind number.
James Van Buskirk <not_valid@comcast.net> schrieb:
This is an example of how this syntax where an array-implied-do
variable is a constant expression makes compilers suffer :(
NAG Fortran will give you the values of 1,2,4,8 in your array.
What are you going to use them for?
(Patches for gfortran welcome, by the way.)
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 159 |
Nodes: | 16 (0 / 16) |
Uptime: | 98:07:55 |
Calls: | 3,209 |
Files: | 10,563 |
Messages: | 3,009,574 |