• Use of non-default-kind logical variables

    From Beliavsky@21:1/5 to All on Mon Mar 21 09:07:54 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to Beliavsky on Mon Mar 21 17:14:49 2022
    Beliavsky <beliavsky@aol.com> schrieb:
    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.

    This is a question of the meaing of the kind numbers. While it
    is customary to have kind=1 as single-byte logicals, this is by
    no means guaranteed.

    A better way might be to use c_bool, as in

    use iso_c_binding, only : c_bool
    logical (kind=c_bool) :: x

    which is likely to be the minimum size for a logical variable
    (typically one byte) and which is likely to have an efficient
    implemementation because the people who implemented the companion
    processor should know their jobs.

    [...]

    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

    and nagfor yields (with default options, they have
    an option which would accept the code above)

    NAG Fortran Compiler Release 7.1(Hanzomon) Build 7101
    Error: x.f90, line 7: KIND value (8) does not specify a valid representation method
    Errors in declarations, no further processing for TEST_LOGICAL
    [NAG Fortran Compiler error termination, 1 error]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Steve Lionel@21:1/5 to Beliavsky on Mon Mar 21 16:17:49 2022
    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.

    --
    Steve Lionel
    ISO/IEC JTC1/SC22/WG5 (Fortran) Convenor
    Retired Intel Fortran developer/support
    Email: firstname at firstnamelastname dot com
    Twitter: @DoctorFortran
    LinkedIn: https://www.linkedin.com/in/stevelionel
    Blog: https://stevelionel.com/drfortran
    WG5: https://wg5-fortran.org

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Beliavsky@21:1/5 to Steve Lionel on Mon Mar 21 14:02:35 2022
    On Monday, March 21, 2022 at 4:17:55 PM UTC-4, Steve Lionel wrote:
    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.


    Thanks -- I can find some tweets in that post. You recommended that the customer who wrote

    DO WHILE (K .LE. 2 .AND. FOUND .EQV. .FALSE.)

    write

    DO WHILE ((K .LE. 2) .AND. (FOUND .EQV. .FALSE.))

    but I think would be even better to write

    DO WHILE ((K .LE. 2) .AND. (.NOT. FOUND))

    Thanks to Thomas Koenig for his message. The new question could be if there are times where
    it is beneficial to use C_BOOL even when not interoperating with C.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to gah4@u.washington.edu on Mon Mar 21 21:50:48 2022
    gah4 <gah4@u.washington.edu> schrieb:
    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.

    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.

    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.

    Most ISAs have instructions for loading and storing individual
    bytes. Getting at an individual bit requires shifting and masking,
    which costs several instructions (and cycles). A byte is probably
    the smallest unit that can be addressed individually (Alpha was the
    latest major version which started out without byte adressability,
    and that was later added). There may be some DSPs which use only
    words, but programming Fortran on them is probably very rare.

    Using less memory can be quite beneficial to take off load
    from the cache, so using bytes (or _Bool, which almost always
    translates to a byte) gives you a good compromose. The higher
    effort of bitmaps will mean that they are probably slower, which
    may be offset in some cases by either a) the problem not fitting
    into memory, or b) the problem still fitting into one of the
    cache levels.

    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.

    And you don't know what KIND
    of logical array it generates.

    I can speak for gfortran: If a temporary is generated for a mask,
    it uses one-byte logical values.

    Actually, the library contains a trick that may be questionable C.
    To avoid different versions for different LOGICAL types (and thus
    at least one axis of combinatorical explosion), the code examines
    only the least significant byte of the values of the MASK,
    using different stides for the different LOGICAL kinds.

    This was one reason for the decision to only allow 0 and 1 as the
    binary repesentation of .false. and .true., respectively Under
    this scheme, 255 would have been .true., and 256 .false., clearly
    not a desirable state of affairs.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to Beliavsky on Mon Mar 21 14:16:52 2022
    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.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Mon Mar 21 15:02:33 2022
    On Monday, March 21, 2022 at 2:50:51 PM UTC-7, Thomas Koenig wrote:

    (snip, I wrote)

    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.

    Yes. I wrote "very large" without saying how large that was,
    but eventually you get large enough to be larger than the
    last cache level. Now that 4GB is considered small for RAM
    (though it is what is on the MacBook Air that I write this on),
    one might consider "very large" in the GB range.

    Not so many years ago, we worried about arrays so large
    that we start paging to virtual memory, when things really
    slow down! (And you can hear the difference!)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to All on Mon Mar 21 17:34:00 2022
    On Tuesday, March 22, 2022 at 8:16:54 AM UTC+11, gah4 wrote:
    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.

    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.

    The relevant logical operators are .EQV. AND .NEQV.
    (supplemented by .NOT., .AND., .OR.)

    And logical variables with as little as one but (but typically with one byte) have been available in PL/I since 1966.

    They were, though,
    often useful for character (before CHARACTER variables) data, when you didn't need to compare it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Beliavsky on Mon Mar 21 17:17:57 2022
    On Tuesday, March 22, 2022 at 3:07:59 AM UTC+11, 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)

    KIND=1 does not necessarily get anything.

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robin Vowels@21:1/5 to Steve Lionel on Mon Mar 21 17:20:23 2022
    On Tuesday, March 22, 2022 at 7:17:55 AM UTC+11, Steve Lionel wrote:
    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.

    Once again, PL/I has has logical variables of as little as one bit
    (but typically 8 bits or one byte) since 1966.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to All on Mon Mar 21 19:44:43 2022
    "Beliavsky" wrote in message news:6bf7b907-6a27-426f-a755-b5156b4b4f81n@googlegroups.com...

    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 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.

    In Fortran there is the LOGICAL_KINDS array from the ISO_FORTRAN_ENV
    module that can get you the logical kinds. You could figure out how big
    they are using the C_SIZEOF function but I think that may still unusable
    in constant expressions -- but maybe it is now. If not, you have to use
    tricks with TRANSFER and SIZE to get the BIT_SIZE of a LOGICAL variable.
    These tricks often lead to ICE :)

    C_BOOL is very problematic to the standard and is an issue that really
    pulls my chain, as all long time participants in this forum are aware.
    The definition of _Bool was intentionally left imprecise in the C
    standard and while imprecision is all well and good for users of that
    language, in Fortran we are normally expected to know what we are
    talking about. If C_BOOL >= 0 the compiler more or less has to
    implement a logical kind that matches the imprecisely defined
    behavior of _Bool. This leads to a completely broken behavior for
    logical variables in gfortran and to 2 different styles of logical
    variables in ifort which can lead to inconsistent results and which
    may or may not have been fixed (it's been years since I checked).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to All on Mon Mar 21 18:16:42 2022
    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.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to James Van Buskirk on Mon Mar 21 20:45:51 2022
    On Monday, March 21, 2022 at 6:45:17 PM UTC-7, James Van Buskirk wrote:

    (snip on KINDs of LOGICAL variables)

    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.

    Often that is done using a look-up table with some bit combinations.
    And often when they do, it works better at whole words than bytes.

    But also algorithms that use packed bitwise data for input, output,
    or both, pretty much have to be done that way. Compression
    algorithms often have to do much work bitwise.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to All on Mon Mar 21 22:07:51 2022
    "gah4" wrote in message news:9e67bb40-eff4-4729-81d8-618ad6735266n@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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to All on Tue Mar 22 01:00:59 2022
    "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

    D:\gfortran\james\sieves>gfortran -c sieve.f90
    sieve.f90:5:38:

    [(size(transfer(logical(.FALSE.,LOGICAL_KINDS(iLoop)),[0_INT8])), &
    1
    Error: Invalid kind for LOGICAL at (1)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to James Van Buskirk on Mon Mar 21 23:38:24 2022
    On Monday, March 21, 2022 at 9:08:26 PM UTC-7, James Van Buskirk wrote:
    "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.

    Some of the ones I have known don't put in all the bits.

    Start by declaring 2 prime, and then only use bits for odd numbers.

    It makes the rest of the algorithm slightly harder, but only half as many bits. Continuing on, don't use bits for multiples of 2 or 3, so only 1/3 as many bits.

    But it isn't that much harder to use all the bits.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to gah4@u.washington.edu on Tue Mar 22 06:44:44 2022
    gah4 <gah4@u.washington.edu> schrieb:
    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.

    Or FORALL, which did not work out too well.

    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))

    I agree.

    (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.)

    You're right. People could just interchange the returned values
    without the TRANSPOSE :-) and a run-time argument to BACK is also
    likely to end up in a library call.

    (For gfortran, you can look "under the hood" by specifying
    -fdump-tree-original and inspecting the generated dump file.
    It is a C-like representation of what is handed to the middle end.
    Not pretty to read, but sometimes instructive, and invaluable in
    finding compiler bugs.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to James Van Buskirk on Tue Mar 22 02:35:13 2022
    On Monday, March 21, 2022 at 9:08:26 PM UTC-7, James Van Buskirk wrote:
    "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.

    OK, it starts like this. The assignments were written by another Fortran program to compute all the hex constants. They could be computed
    within the program, and it would be much smaller, but then the loops
    don't have constants for ORing.

    integer, parameter :: n=1000
    integer bits(0:n+32)
    ! bits represent integers starting from 0.
    ! this program assumes 32 bit integers
    integer i, j, k, l
    ! clear all bits
    bits = 0
    ! mark 1
    bits(0) = int(z'40000000')
    ! 2 1
    print *,2
    do i=0,n-1
    bits(i+ 0)=ior(bits(i+ 0),int(z'AAAAAAAA'))
    enddo
    ! 3 3
    print *,3
    do i=0, n-1, 3
    bits(i+ 0)=ior(bits(i+ 0),int(z'92492492'))
    bits(i+ 1)=ior(bits(i+ 1),int(z'49249249'))
    bits(i+ 2)=ior(bits(i+ 2),int(z'24924924'))
    enddo
    ! 5 5
    print *,5
    do i=0, n-1, 5
    bits(i+ 0)=ior(bits(i+ 0),int(z'84210842'))
    bits(i+ 1)=ior(bits(i+ 1),int(z'10842108'))
    bits(i+ 2)=ior(bits(i+ 2),int(z'42108421'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 8421084'))
    bits(i+ 4)=ior(bits(i+ 4),int(z'21084210'))
    enddo
    ! 7 7
    print *,7
    do i=0, n-1, 7
    bits(i+ 0)=ior(bits(i+ 0),int(z'81020408'))
    bits(i+ 1)=ior(bits(i+ 1),int(z'10204081'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 2040810'))
    bits(i+ 3)=ior(bits(i+ 3),int(z'20408102'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 4081020'))
    bits(i+ 5)=ior(bits(i+ 5),int(z'40810204'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 8102040'))
    enddo
    ! 11 11
    print *, 11
    do i=0, n-1, 11
    bits(i+ 0)=ior(bits(i+ 0),int(z'80100200'))
    bits(i+ 1)=ior(bits(i+ 1),int(z'40080100'))
    bits(i+ 2)=ior(bits(i+ 2),int(z'20040080'))
    bits(i+ 3)=ior(bits(i+ 3),int(z'10020040'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 8010020'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 4008010'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 2004008'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 1002004'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 801002'))
    bits(i+ 9)=ior(bits(i+ 9),int(z' 400801'))
    bits(i+10)=ior(bits(i+10),int(z' 200400'))
    enddo
    ! 13 13
    print *, 13
    do i=0, n-1, 13
    bits(i+ 0)=ior(bits(i+ 0),int(z'80040020'))
    bits(i+ 1)=ior(bits(i+ 1),int(z' 1000800'))
    bits(i+ 2)=ior(bits(i+ 2),int(z'40020010'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 800400'))
    bits(i+ 4)=ior(bits(i+ 4),int(z'20010008'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 400200'))
    bits(i+ 6)=ior(bits(i+ 6),int(z'10008004'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 200100'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 8004002'))
    bits(i+ 9)=ior(bits(i+ 9),int(z' 100080'))
    bits(i+10)=ior(bits(i+10),int(z' 4002001'))
    bits(i+11)=ior(bits(i+11),int(z' 80040'))
    bits(i+12)=ior(bits(i+12),int(z' 2001000'))
    enddo
    ! 17 17
    print *, 17
    do i=0, n-1, 17
    bits(i+ 0)=ior(bits(i+ 0),int(z'80004000'))
    bits(i+ 1)=ior(bits(i+ 1),int(z'20001000'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 8000400'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 2000100'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 800040'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 200010'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 80004'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 20001'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 8000'))
    bits(i+ 9)=ior(bits(i+ 9),int(z'40002000'))
    bits(i+10)=ior(bits(i+10),int(z'10000800'))
    bits(i+11)=ior(bits(i+11),int(z' 4000200'))
    bits(i+12)=ior(bits(i+12),int(z' 1000080'))
    bits(i+13)=ior(bits(i+13),int(z' 400020'))
    bits(i+14)=ior(bits(i+14),int(z' 100008'))
    bits(i+15)=ior(bits(i+15),int(z' 40002'))
    bits(i+16)=ior(bits(i+16),int(z' 10000'))
    enddo
    ! 19 19
    print *, 19
    do i=0, n-1, 19
    bits(i+ 0)=ior(bits(i+ 0),int(z'80001000'))
    bits(i+ 1)=ior(bits(i+ 1),int(z' 2000040'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 80001'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 2000'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 4000080'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 100002'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 4000'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 8000100'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 200004'))
    bits(i+ 9)=ior(bits(i+ 9),int(z' 8000'))
    bits(i+10)=ior(bits(i+10),int(z'10000200'))
    bits(i+11)=ior(bits(i+11),int(z' 400008'))
    bits(i+12)=ior(bits(i+12),int(z' 10000'))
    bits(i+13)=ior(bits(i+13),int(z'20000400'))
    bits(i+14)=ior(bits(i+14),int(z' 800010'))
    bits(i+15)=ior(bits(i+15),int(z' 20000'))
    bits(i+16)=ior(bits(i+16),int(z'40000800'))
    bits(i+17)=ior(bits(i+17),int(z' 1000020'))
    bits(i+18)=ior(bits(i+18),int(z' 40000'))
    enddo
    ! 23 23
    print *, 23
    do i=0, n-1, 23
    bits(i+ 0)=ior(bits(i+ 0),int(z'80000100'))
    bits(i+ 1)=ior(bits(i+ 1),int(z' 20000'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 4000008'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 1000'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 200000'))
    bits(i+ 5)=ior(bits(i+ 5),int(z'40000080'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 10000'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 2000004'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 800'))
    bits(i+ 9)=ior(bits(i+ 9),int(z' 100000'))
    bits(i+10)=ior(bits(i+10),int(z'20000040'))
    bits(i+11)=ior(bits(i+11),int(z' 8000'))
    bits(i+12)=ior(bits(i+12),int(z' 1000002'))
    bits(i+13)=ior(bits(i+13),int(z' 400'))
    bits(i+14)=ior(bits(i+14),int(z' 80000'))
    bits(i+15)=ior(bits(i+15),int(z'10000020'))
    bits(i+16)=ior(bits(i+16),int(z' 4000'))
    bits(i+17)=ior(bits(i+17),int(z' 800001'))
    bits(i+18)=ior(bits(i+18),int(z' 200'))
    bits(i+19)=ior(bits(i+19),int(z' 40000'))
    bits(i+20)=ior(bits(i+20),int(z' 8000010'))
    bits(i+21)=ior(bits(i+21),int(z' 2000'))
    bits(i+22)=ior(bits(i+22),int(z' 400000'))
    enddo
    ! 29 29
    print *, 29
    do i=0, n-1, 29
    bits(i+ 0)=ior(bits(i+ 0),int(z'80000004'))
    bits(i+ 1)=ior(bits(i+ 1),int(z' 20'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 100'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 800'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 4000'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 20000'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 100000'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 800000'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 4000000'))
    bits(i+ 9)=ior(bits(i+ 9),int(z'20000001'))
    bits(i+10)=ior(bits(i+10),int(z' 8'))
    bits(i+11)=ior(bits(i+11),int(z' 40'))
    bits(i+12)=ior(bits(i+12),int(z' 200'))
    bits(i+13)=ior(bits(i+13),int(z' 1000'))
    bits(i+14)=ior(bits(i+14),int(z' 8000'))
    bits(i+15)=ior(bits(i+15),int(z' 40000'))
    bits(i+16)=ior(bits(i+16),int(z' 200000'))
    bits(i+17)=ior(bits(i+17),int(z' 1000000'))
    bits(i+18)=ior(bits(i+18),int(z' 8000000'))
    bits(i+19)=ior(bits(i+19),int(z'40000002'))
    bits(i+20)=ior(bits(i+20),int(z' 10'))
    bits(i+21)=ior(bits(i+21),int(z' 80'))
    bits(i+22)=ior(bits(i+22),int(z' 400'))
    bits(i+23)=ior(bits(i+23),int(z' 2000'))
    bits(i+24)=ior(bits(i+24),int(z' 10000'))
    bits(i+25)=ior(bits(i+25),int(z' 80000'))
    bits(i+26)=ior(bits(i+26),int(z' 400000'))
    bits(i+27)=ior(bits(i+27),int(z' 2000000'))
    bits(i+28)=ior(bits(i+28),int(z'10000000'))
    enddo
    ! 31 31
    print *, 31
    do i=0, n-1, 31
    bits(i+ 0)=ior(bits(i+ 0),int(z'80000001'))
    bits(i+ 1)=ior(bits(i+ 1),int(z' 2'))
    bits(i+ 2)=ior(bits(i+ 2),int(z' 4'))
    bits(i+ 3)=ior(bits(i+ 3),int(z' 8'))
    bits(i+ 4)=ior(bits(i+ 4),int(z' 10'))
    bits(i+ 5)=ior(bits(i+ 5),int(z' 20'))
    bits(i+ 6)=ior(bits(i+ 6),int(z' 40'))
    bits(i+ 7)=ior(bits(i+ 7),int(z' 80'))
    bits(i+ 8)=ior(bits(i+ 8),int(z' 100'))
    bits(i+ 9)=ior(bits(i+ 9),int(z' 200'))
    bits(i+10)=ior(bits(i+10),int(z' 400'))
    bits(i+11)=ior(bits(i+11),int(z' 800'))
    bits(i+12)=ior(bits(i+12),int(z' 1000'))
    bits(i+13)=ior(bits(i+13),int(z' 2000'))
    bits(i+14)=ior(bits(i+14),int(z' 4000'))
    bits(i+15)=ior(bits(i+15),int(z' 8000'))
    bits(i+16)=ior(bits(i+16),int(z' 10000'))
    bits(i+17)=ior(bits(i+17),int(z' 20000'))
    bits(i+18)=ior(bits(i+18),int(z' 40000'))
    bits(i+19)=ior(bits(i+19),int(z' 80000'))
    bits(i+20)=ior(bits(i+20),int(z' 100000'))
    bits(i+21)=ior(bits(i+21),int(z' 200000'))
    bits(i+22)=ior(bits(i+22),int(z' 400000'))
    bits(i+23)=ior(bits(i+23),int(z' 800000'))
    bits(i+24)=ior(bits(i+24),int(z' 1000000'))
    bits(i+25)=ior(bits(i+25),int(z' 2000000'))
    bits(i+26)=ior(bits(i+26),int(z' 4000000'))
    bits(i+27)=ior(bits(i+27),int(z' 8000000'))
    bits(i+28)=ior(bits(i+28),int(z'10000000'))
    bits(i+29)=ior(bits(i+29),int(z'20000000'))
    bits(i+30)=ior(bits(i+30),int(z'40000000'))
    enddo
    print '(1x, 6z9)', bits(0:n-1)
    end

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to Thomas Koenig on Tue Mar 22 12:05:34 2022
    "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 :(

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to James Van Buskirk on Tue Mar 22 17:55:03 2022
    James Van Buskirk <not_valid@comcast.net> schrieb:
    "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

    What is this supposed to do? Is this a Sieve of Erastosthenes?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From James Van Buskirk@21:1/5 to Thomas Koenig on Tue Mar 22 13:56:58 2022
    "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.

    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?

    As alluded to above, to provide context for what the various kinds
    are. Good on NAG for passing this deceptively difficult test.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to James Van Buskirk on Tue Mar 22 19:33:08 2022
    James Van Buskirk <not_valid@comcast.net> schrieb:
    "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.

    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?

    (Patches for gfortran welcome, by the way.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to James Van Buskirk on Tue Mar 22 20:20:41 2022
    James Van Buskirk <not_valid@comcast.net> schrieb:
    "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.

    c_sizeof works, as would a look at the compiler's documentation :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From steve kargl@21:1/5 to Thomas Koenig on Tue Mar 22 21:17:10 2022
    Thomas Koenig wrote:

    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.)

    Don't hold your breath. James has had decades to fix
    constant expression in gfortran. He choose to not be
    part of the solution.

    --
    steve

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)