Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default KINDs for constants and intrinsics #78

Open
FortranFan opened this issue Nov 11, 2019 · 21 comments
Open

Default KINDs for constants and intrinsics #78

FortranFan opened this issue Nov 11, 2019 · 21 comments
Labels
Clause 7 Standard Clause 7: Types

Comments

@FortranFan
Copy link
Member

FortranFan commented Nov 11, 2019

A proposal from UK national body from year 2013: https://wg5-fortran.org/N1951-N2000/N1975.txt

--------------------------------------------------------------------------
Number: UK-01
Title: Default KINDs for constants and intrinsics
Status: For Consideration
Basic Functionality:
Program-specified default KIND for constants etc.
Rationale:
(a) In the 64-bit world default integer generally being 32-bit is
    increasingly leading to incorrect programs.
(b) In the floating-point world default real generally being 32-bit
    not infrequently leads to incorrect programs.
(c) It is tedious and error-prone to have to attach kind_param's to
    individual literal constants.
(d) It is tedious and error-prone to have to specify a KIND= argument as
    required for each individual reference to an intrinsic function.
(e) Program specification of the default type parameters is possible for
    derived types but not intrinsic types.

Specification (requirements):
1. Provide a mechanism for specifying the default kind parameter for the
   intrinsic types REAL and INTEGER.
2. Decouple the concepts of "default kind" from those of "single precision"
   and "basic integer"; "default kind" to be used for literal constants,
   implicit typing, etc., while "single precision" et al to be used for the
   old storage association contexts.

Discussion:

Specifications (detailed):
--------------------------
a. There will be a new statement, that can appear only between the USE
   statements and IMPLICIT statements, to specify the default kind for a
   particular intrinsic type.
b. The effect of this statement is to change the default kind for the
   remainder of the scoping unit.  To avoid circular dependencies, it does
   not affect the default kind of literals appearing in or before the
   statement itself, nor does it affect the type implied by a PARAMETER
   statement that appears before the statement.
   Rationale: circular dependencies bad, named constants good.
c. The default kind setting in a scoping unit is initially that of its
   host scoping unit; note that as nested scoping units appear necessarily
   after any IMPLICIT statements, this will inherit the user setting.
d. In the case of REAL, the default kind for COMPLEX is also affected.
   It does not affect double precision kind, which remains as twice single
   precision in storage.
e. Terminology:
     "default kind" = user-specifiable default kind
     "single precision kind" = old default real kind
     "basic integer kind" = old default integer kind
f. OPTIONAL: There is a reasonable argument to be made that permitting the
   user to specify the kind for "double precision" constants and variables
   would also be valuable.
g. Table of places where "default kind" is used, and what that should
   correspond to in the new scheme, follows.

    Context                                         Should be
    ---------------------------------------------------------
(1) integer literal with no <kind-param>            default kind
(2) "kindly" intrinsics with absent KIND=           default kind * Note T0
(3) intrinsics with no KIND argument                default kind * Note T1
(4) <type-spec> with no KIND parameter, e.g. REAL   default kind * Note T2
(5) arguments to generic intrinsics                 accept both * Note T3
(6) args/result for specific intrinsics, e.g. AMIN1 basic kind * Note T4
(7) constants in ISO_FORTRAN_ENV                    basic kind * Note T5
(8) having the size of one numeric storage unit     basic kind
(9) EQUIVALENCE/COMMON real/integer matching        basic kind

Note T0.
  This includes LBOUND, LCOBOUND, SIZE, SHAPE ... i.e. all the ones that
  have a KIND= argument and return a REAL/INTEGER/COMPLEX result of the
  specified kind when present, and default kind when not.

Note T1.
  Actually these don't really matter much, as the value always fits into
  basic kind.  However, it would be more convenient when passing as an
  actual argument, and more consistent, for these to be the new
  user-specifiable default kind too.  Here is a representative list of
  the intrinsics concerned: DIGITS, PRECISION, RANGE, EXPONENT,
  MAX_EXPONENT, and THIS_IMAGE.

Note T2.
  Wherever the <type-spec> is, viz a type declaration statement, component
  definition statement, array constructor, etc.

Note T3.
  The affected intrinsics:arguments are DATE_AND_TIME: VALUE,
  EXECUTE_COMMAND_LINE:EXITSTAT,CMDSTAT, GET_COMMAND:LENGTH,STATUS, and
  similar.  Not a big deal (values always representable in the basic kind)
  but why not relax the requirement to permit larger kinds always anyway?

Note T4.
  Not actually important.  These are wholly redundant anyway.

Note T5.
  As if it were a user-defined module with those constants.

Syntax (illustrative):
----------------------
   DEFAULT <intrinsic-type-name> ( [ KIND = ] <int-constant-expr> )
     where <intrinsic-type-name> is INTEGER or REAL.
   Cnnn (Ryyy) The kind number specified in a DEFAULT INTEGER statement
     shall specify a kind whose storage size is at least as great as that
     of basic integer kind.
   {Reason: To stop the user shooting his foot off with a short integer
            kind.}

   OPTIONAL: If we permit specification of double precision kind, add this
             additional syntax:
   DEFAULT DOUBLE PRECISION ( [ KIND = ] <int-constant-expr> )
   Cnnn The kind number specified in a DEFAULT DOUBLE PRECISION
     statement shall not specify a kind whose storage size is less than
     that of default real kind.
   {Reason: There might not be a bigger real kind than the user-specified
            default, but it would be counter-intuitive to permit
            specification of a double precision kind that is actually
            smaller than default real.}

Example:
--------
This is just to show how it works, it is too trivial to show much
advantage.

Program sum_tan_prefix
  Default Integer (Kind=Selected_Int_Kind(18))
  Default Real (Kind=Selected_Real_Kind(15))
  Real,Allocatable :: x(:)
  Print *,'Input vector length N'
  Read *, n
  If (n<2) Stop 'Don''t be silly.'
  Allocate(x(n))
  Print *,'Input vector with',Size(x),'values in degrees'
  Read *,x
  tmp = 0
  Print *,'SUM_TAN_PREFIX results'
  Do i=1,Size(x)
    tmp = tmp + Tan(x(i)*3.1415926535897932384/180)
    Print *,i,x
  End Do
End Program
@certik
Copy link
Member

certik commented Nov 11, 2019

@FortranFan, thanks for this idea. I think this is a long standing issue in Fortran and a source of a lot of errors, at least in the codes that I have seen. Do you mind editing the title of this issue to just "Default KINDs for constants and intrinsics", the "Brilliant" Proposal part does not add value.
In a similar spirit, if possible, please try to keep the discussion technical. Trust me, I think I fully understand your frustration, and we have to streamline how the committee works. But I want these discussions here on issues to be purely technical (if the issue is technical like this one), so that we can move the discussion forward on technical terms. You can open another issue to discuss how the committee can improve how it works.

@FortranFan FortranFan changed the title "Brilliant" Proposal: Default KINDs for constants and intrinsics Default KINDs for constants and intrinsics Nov 11, 2019
@FortranFan
Copy link
Member Author

@certik wrote:

..the "Brilliant" Proposal part does not add value.
In a similar spirit, if possible, please try to keep the discussion technical. Trust me, I think I fully understand your frustration, and we have to streamline how the committee works. But I want these discussions here on issues to be purely technical (if the issue is technical like this one), so that we can move the discussion forward on technical terms. You can open another issue to discuss how the committee can improve how it works.

@certik , as asked, the title and the body have been edited - please let me know if there's anything else objectionable.

@certik
Copy link
Member

certik commented Nov 11, 2019

@FortranFan thank you, I think it looks great!

@certik certik added Clause 16 Standard Clause 16: Intrinsic procedures and modules Clause 7 Standard Clause 7: Types and removed Clause 16 Standard Clause 16: Intrinsic procedures and modules labels Apr 23, 2022
@8bitmachine
Copy link

I have also made a request which is based on a similar concept that numbers declared with REAL(8) for example are exactly that. The issue is that if a number is not specified to be "doubnle precision" then at least one compilier will only assign 4-byte precision even though a number is declared 8 bytyes.
For example:
REAL(8) :: x=3.
PRINT*,'x=',x
may print out
3.00000001254321
or some such.
This is only fixable (in my compiler) if the statement
REAL(8) :: x=3.0d0 is used.
Not even REAL(8) :: x=3.0E0 worked.

So my request is that variables declared as REAL(8) (or other) are recognised as 8 byte precision and not left to a compiler preference.
Following on from this, the "D" designator is past its due date and should be obsoleted.
Furthermore, requring the decimal point to indicate a real number is also past due.
Unless this is already implemented, I would like to see
REAL(8) ::one=1
be sufficient to specify the variable one as 1.0000000000000 etc and not have to type the decimal pont - in otherwords, because the variable is declared real, it should implcitly understand that without a decimal point.

@certik
Copy link
Member

certik commented May 22, 2022

My understanding is that REAL(8) :: x=3 is declaring an integer 3 (exact) and then implicitly casting it to a kind=8 floating point number. So it should print exactly 3.0000000000000000 (or similar).

@8bitmachine
Copy link

You are right, but my concern is that something like
REAL(8)::x=4.1
does not default to 8 byte precision (at least not with the compiler I am using, but it can be forced by setting promote REAL(4) to REAL (8).
My point is that in order to drop the D descriptor Fortran should require all initialisations to implicitly set the target accuracy.
What happens currently is that REAL(8) :: x=4.1 assigns an 8 byte space but only specifies 4 bytes of precision, leaving the LSB's undefined (random numbers).

@certik
Copy link
Member

certik commented May 22, 2022

Yes, that is a common problem, and discussed in quite a few issues here and at Fortran discourse. If you read through the prior discussion, there are quite a few arguments why it might be difficult to fix this. So in order for any such proposal to succeed, you have to address the prior points.

@klausler
Copy link

You are right, but my concern is that something like REAL(8)::x=4.1 does not default to 8 byte precision (at least not with the compiler I am using, but it can be forced by setting promote REAL(4) to REAL (8). My point is that in order to drop the D descriptor Fortran should require all initialisations to implicitly set the target accuracy. What happens currently is that REAL(8) :: x=4.1 assigns an 8 byte space but only specifies 4 bytes of precision, leaving the LSB's undefined (random numbers).

All bits are completely well defined, just not to what you think they should be. Come on.

@8bitmachine
Copy link

@klausler - What was the point of your comment?
Fortran as a language has strict rules. But if users want to bring it up to date and elminate some of the more outdated quirks things like D descriptor then surely defining constants properly is mandatory? And making number implementation compatible with future capabilities at the same time. It won't be long before REAL(16) is needed if not already by some programmers.
Even a floating point chip designed decades ago did a better job (and that tended to work with 96 bit precision).
@certik - do you have a link to where the previous points have been raised?

@certik
Copy link
Member

certik commented May 23, 2022

I think Peter's point was that the current standard defines exactly what happens and it has its logic and motivation and it is (relatively) consistent. I agree.

But in my experience this is a point of confusion to almost every single new person to Fortran. I'll find the links to prior discussions later today.

@klausler
Copy link

My point is that claiming that the lower order bits of the result of a 32-bit to 64-bit floating-point conversion are undefined random garbage is complete nonsense.

If you don't like D numbers, use a modern suffix.

@8bitmachine
Copy link

@klausler - Well, filling in with zeros to extend the data is one approach, but do you agree that the bits ought to have been extended to ensure that the number is consistent with the specified one when converted back from binary to decimal?
I was somewhat glib, technically corrected. But the digits may as well have been random for the effect they have as to avoid this some additional work is needed (like using D, still).
I am not sure what the motivation was but no doubt Fortran developers will know.
I'm not that new to Fortran BTW, but I do have some wishes for future releases.

@wyphan
Copy link

wyphan commented May 23, 2022

@8bitmachine I think what @klausler meant is the representation of a number as sign, mantissa, and exponent bits in the floating-point representation as dictated by IEEE 754 standard. If you know the nuances of the mantissa bits, I think you should arrive at the conclusion that it is impossible to have a one-to-one mapping between binary and decimal for floating-point numbers. I suggest you grab a copy of the latest Fortran standard interpretation document J3/18-007r1 and look into the following:

  • section 7.4.3 on "Numeric intrinsic types"
  • section 16.9.160 on the definition of the "REAL()" intrinsic function
  • section 17 "Exceptions and IEEE Arithmetic".

@klausler
Copy link

@klausler - Well, filling in with zeros to extend the data is one approach, but do you agree that the bits ought to have been extended to ensure that the number is consistent with the specified one when converted back from binary to decimal?

Every binary number with a finite number of digits can be represented by a decimal number with a finite number of digits, but the converse is not true.

@8bitmachine
Copy link

I do know that decimal numbers and binary numbers do not have exact equvialents, of course.
My point is that, and I do not seem to be the only person, I would much prefer that when a compiler sees
real(8)::x=4.1, to continue with my earlier example, it translates and stores the number as
4010666666666666 rather than 4010666660000000 (both hexadecimal).
Rather than having to use a suffix, although that would appear to be the current BKM.

@8bitmachine
Copy link

I would also add that it seems to me that selected_real_kind has not actually helped.
Most computer systems these days implement the IEEE number formats in full. Therefore, unlike earlier times, 32, 64 and extended precisions are well established and should be the primary defaults. Fortran should in my view recognise that.
If particular programs need greater resolution than offered by real(8) or real(16) then perhaps the argument needs to be as to what the next resolution standard should be. selected_real_kind does not really assure of a particular resolution only a minimum which might be met.
Having to specify a real with a suffix seems to be as an imposition similar to requiring the D descriptor.
No doubt Fortran community will tell me "selected_real_kind" is a step forward. As a long time user of Fortran, I'm asking for a simpler option, not a more complicated one.

@wyphan
Copy link

wyphan commented May 24, 2022 via email

@klausler
Copy link

The problem here is that you're trying to change part of the language that is not context-sensitive into something that is. The type of a numeric literal (in Fortran and every other programming language that I know!) is self evident from the characters that constitute that literal. 3.14 is default REAL in Fortran in every context, and double in C/C++ in every context.

So you want to change that. Fine. What you need to do next is (1) figure out a way to not invalidate hundreds of millions of lines of existing code by changing the interpretation of their numeric literals and (2) figure out a way of defining, in a very precise and airtight way, how the context would affect the interpretation of numeric literals.

Last, you may not like SELECTED_REAL_KIND or the real kind parameters in the intrinsic modules, but you're going to have to use those kind names even if you somehow come up with useful semantics for the REAL(KIND=k) type-declaration-stmt. REAL(8) should be universally portable, but it isn't, thanks to one vendor.

@8bitmachine
Copy link

@wyphan
Indeed, that sort of adds to my point that while selected_real_kind appears to offer a great flexibility in practice almost all, at least all the programs I have seen in industrial use, have used real(8) which I assume is the same as real64 ISO_FORTRAN_ENV which I would use if my compiler had it. I've never needed greater than that either, so real(4) and real(8) should have been sufficient. It also means I question the development of selected-real_kind if it was not going to offer guaranteed formats, as many of the possible real/exponent combinations won't be available or used. Must have seemed a good idea at the time.
@klausler, yes it may be that REAL(8) and REAL(4) would indeed set the context. I'm sure that is not beyond the capabilities of Fortran programmers. It is difficult to see, though, how extending a real(4) to a real(8) by zeroing the additional bits was a better solution as the context has changed for those variables defined as real(8). Presumably, like myself, programmers wishing to use 8 byte precision were expecting the context to change.
I guess I'll define real(r8) as a selected real kind (15,307) and have done with it. Does not alter my wish for a simpler system.
Therefore, if programmers are using some form of selected_real_kind definition a new term would only apply to

@w6ws
Copy link

w6ws commented May 24, 2022 via email

@FortranFan
Copy link
Member Author

FortranFan commented May 25, 2022

What you need to do next is (1) figure out a way to not invalidate hundreds of millions of lines of existing code by changing the interpretation of their numeric literals and (2) figure out a way of defining, in a very precise and airtight way, how the context would affect the interpretation of numeric literals.

@8bitmachine , why not upvote the original post? It addresses the challenges thrown here by @klausler. Should there be any gaps or limitations or wrinkles with the proposal in the original post, the standard committee should and can step up to iron them out, if they can be influenced to again take up a solution to the situation. Note the proposal in the original post nearly had made its way into Fortran 2008 but was only deferred due to non-technical aspects.

Consider the following program:

   double precision :: x = 0.1
   print "(b0)", x
end

Most processors based on the current standard will yield the following output:

11111110111001100110011001100110100000000000000000000000000000

Per your posts here and as mentioned by @certik re: many Fortranners, the above output is a bit (pun intended) confusing and can even lead to errors with unsuspecting users.

With the proposal in the original post, the following modification will likely give many users the output they expect and also want with a possible conforming processor in the future:

   default real (kind=kind(1D0))   !<-- pseudo syntax
   double precision :: x = 0.1
   print "(b0)", x
end
11111110111001100110011001100110011001100110011001100110011010

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Clause 7 Standard Clause 7: Types
Projects
None yet
Development

No branches or pull requests

6 participants