• contradiction about the INFINITY macro

    From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Thu Sep 30 01:47:23 2021
    From Newsgroup: comp.std.c

    In ISO C99:TC3 to C17, 7.12p4:

    The macro INFINITY expands to a constant expression of type float
    representing positive or unsigned infinity, if available; else to a
    positive constant of type float that overflows at translation time.

    Consider the "else" case. It is said that INFINITY expands to a
    constant and that it overflows, so that it is not in the range of
    representable values of float.

    But in 6.4.4p2:

    Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type.

    which would imply that INFINITY expands to a value in the range of representable values of float, contradicted by 7.12p4.

    Same issue in the current C2x draft N2596 (7.12p7 and 6.4.4p2).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Wed Sep 29 19:05:38 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In ISO C99:TC3 to C17, 7.12p4:

    The macro INFINITY expands to a constant expression of type float
    representing positive or unsigned infinity, if available; else to a
    positive constant of type float that overflows at translation time.

    Consider the "else" case. It is said that INFINITY expands to a
    constant and that it overflows, so that it is not in the range of representable values of float.

    But in 6.4.4p2:

    Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type.

    which would imply that INFINITY expands to a value in the range of representable values of float, contradicted by 7.12p4.

    Same issue in the current C2x draft N2596 (7.12p7 and 6.4.4p2).

    6.4.4p2 is a constraint. It doesn't make it impossible to write code
    that violates that constraint.

    If I understand correctly, it means that if an infinite value is not
    available, then a program that refers to the INFINITY macro (in a
    context where it's treated as a floating-point expression) violates that constraint, resulting in a required diagnostic.

    In fact I wrote the previous paragraph before I read the footnote on the definition of INFINITY (N1570 7.12p4, footnote 229):

    In this case, using INFINITY will violate the constraint in 6.4.4
    and thus require a diagnostic.

    There is no contradiction.

    (I wonder if it would have been more useful to require that INFINITY not
    be defined unless it can be defined as an actual infinity, but I haven't
    given it a lot of thought.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Ben Bacarisse@ben.usenet@bsb.me.uk to comp.std.c on Thu Sep 30 03:20:23 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In ISO C99:TC3 to C17, 7.12p4:

    The macro INFINITY expands to a constant expression of type float
    representing positive or unsigned infinity, if available; else to a
    positive constant of type float that overflows at translation time.

    Consider the "else" case. It is said that INFINITY expands to a
    constant and that it overflows, so that it is not in the range of representable values of float.

    But in 6.4.4p2:

    Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type.

    which would imply that INFINITY expands to a value in the range of representable values of float, contradicted by 7.12p4.

    Right. But there is footnote that clarifies matters:

    "In this case, using INFINITY will violate the constraint in 6.4.4 and
    thus require a diagnostic."

    so any program using INFINITY has undefined behaviour because the intent
    is to violate 6.4.4. I agree that there should be a better way to
    specify it, but expanding to a constant that violates the constraints on
    such constants is clumsy but reasonably clear.
    --
    Ben.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Thu Sep 30 11:24:08 2021
    From Newsgroup: comp.std.c

    In article <87pmsqizrh.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In ISO C99:TC3 to C17, 7.12p4:

    The macro INFINITY expands to a constant expression of type float
    representing positive or unsigned infinity, if available; else to a
    positive constant of type float that overflows at translation time.

    Consider the "else" case. It is said that INFINITY expands to a
    constant and that it overflows, so that it is not in the range of representable values of float.

    But in 6.4.4p2:

    Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type.

    which would imply that INFINITY expands to a value in the range of representable values of float, contradicted by 7.12p4.

    Same issue in the current C2x draft N2596 (7.12p7 and 6.4.4p2).

    6.4.4p2 is a constraint. It doesn't make it impossible to write code
    that violates that constraint.

    Yes, but the issue here is that the standard mandates the implementation
    to violate a constraint, which is rather different from the case where a
    user writes buggy code.

    If I understand correctly, it means that if an infinite value is not available, then a program that refers to the INFINITY macro (in a
    context where it's treated as a floating-point expression) violates that constraint, resulting in a required diagnostic.

    I think the consequence is more than a diagnostic (which may yield a compilation failure in practice, BTW): AFAIK, the standard does not
    give a particular definition for "overflows at translation time",
    which would make it undefined behavior as usual for overflows.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Thu Sep 30 08:38:24 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <87pmsqizrh.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In ISO C99:TC3 to C17, 7.12p4:

    The macro INFINITY expands to a constant expression of type float
    representing positive or unsigned infinity, if available; else to a
    positive constant of type float that overflows at translation time.

    Consider the "else" case. It is said that INFINITY expands to a
    constant and that it overflows, so that it is not in the range of
    representable values of float.

    But in 6.4.4p2:

    Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type.

    which would imply that INFINITY expands to a value in the range of
    representable values of float, contradicted by 7.12p4.

    Same issue in the current C2x draft N2596 (7.12p7 and 6.4.4p2).

    6.4.4p2 is a constraint. It doesn't make it impossible to write code
    that violates that constraint.

    Yes, but the issue here is that the standard mandates the implementation
    to violate a constraint, which is rather different from the case where a
    user writes buggy code.

    No, it doesn't force the implementation to violate a constraint. It
    says that a *program* that uses the INFINITY macro violates a constraint
    (if the implementation doesn't support infinities).

    Constraints apply to programs, not to implementations.

    It means that if a program assumes that INFINITY is meaningful, and it's compiled for a target system where it isn't, a diagnostic is guaranteed.
    And again, it might have made more sense to say that INFINITY is not
    defined for such implementations (as is done for the NAN macro), but
    perhaps there was existing practice.

    Here's what the C99 Rationale says:

    What is INFINITY on machines that do not support infinity? It should
    be defined along the lines of: #define INFINITY 9e99999f, where
    there are enough 9s in the exponent so that the value is too large
    to represent as a float, hence, violates the constraint of 6.4.4
    Constants. In addition, the number classification macro FP_INFINITE
    should not be defined. That allows an application to test for the
    existance of FP_INFINITE as a safe way to determine if infinity is
    supported; this is the feature test macro for support for infinity.

    The problem with this is that the standard itself doesn't say that
    FP_INFINITE is defined conditionally.

    If I understand correctly, it means that if an infinite value is not
    available, then a program that refers to the INFINITY macro (in a
    context where it's treated as a floating-point expression) violates that
    constraint, resulting in a required diagnostic.

    I think the consequence is more than a diagnostic (which may yield a compilation failure in practice, BTW): AFAIK, the standard does not
    give a particular definition for "overflows at translation time",
    which would make it undefined behavior as usual for overflows.

    The meaning seems clear enough to me. It's a floating constant whose mathematical value is outside the range of float, such as 9e99999f.
    And yes, evaluating it (if the mandatory diagnostic does not cause
    compilation to fail) causes undefined behavior. I think the intent is
    that a portable program should check whether infinities are supported
    before trying to evaluate INFINITY, but that intent is not well
    reflected in the standard.

    I don't think I have access to an implementation that doesn't support infinities, so I don't know how this is handled in practice. Given the
    near universal adoption of IEEE floating-point, it's probably reasonably
    safe to assume that infinities are supported unless your program needs
    to be painfully portable.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Fri Oct 1 09:05:38 2021
    From Newsgroup: comp.std.c

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    No, it doesn't force the implementation to violate a constraint. It
    says that a *program* that uses the INFINITY macro violates a constraint
    (if the implementation doesn't support infinities).

    Then this means that the C standard defines something the user must
    not use (except when __STDC_IEC_559__ is defined, as in this case,
    INFINITY is guaranteed to expand to the true infinity).

    Constraints apply to programs, not to implementations.

    This is related, as programs will be transformed by an implementation.

    It means that if a program assumes that INFINITY is meaningful, and it's compiled for a target system where it isn't, a diagnostic is guaranteed.
    And again, it might have made more sense to say that INFINITY is not
    defined for such implementations (as is done for the NAN macro), but
    perhaps there was existing practice.

    Yes, currently there is no way of fallback (without things like
    autoconf tests).

    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)?
    This should not break existing programs.

    Here's what the C99 Rationale says:

    What is INFINITY on machines that do not support infinity? It should
    be defined along the lines of: #define INFINITY 9e99999f, where
    there are enough 9s in the exponent so that the value is too large
    to represent as a float, hence, violates the constraint of 6.4.4
    Constants. In addition, the number classification macro FP_INFINITE
    should not be defined. That allows an application to test for the
    existance of FP_INFINITE as a safe way to determine if infinity is
    supported; this is the feature test macro for support for infinity.

    The problem with this is that the standard itself doesn't say that FP_INFINITE is defined conditionally.

    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Fri Oct 1 12:20:06 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    [...]
    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)?
    This should not break existing programs.

    I agree. NAN is conditionally defined "if and only if the
    implementation supports quiet NaNs for the float type". I have no
    idea why the same wasn't done for INFINITY -- unless, as I mentioned
    upthread, there was existing practice. INFINITY was introduced
    in C99. Perhaps there were pre-C99 implementations that defined
    INFINITY as an extension in the way that's now specified in the
    standard. That's just speculation, and I still think making it
    conditional would have made more sense.

    [...]

    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I think the implication is that it assumes either all floating types have NaNs
    and/or infinities, or none do. That might be a valid assumption. (The
    Alpha supports both VAX and IEEE floating-point, and I don't think VAX
    FP supports infinities or NaNs, but I don't think an implementation
    would use, for example, VAX FP for float and IEEE for double.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Jakob Bohm@jb-usenet@wisemo.com.invalid to comp.std.c on Fri Oct 1 22:55:07 2021
    From Newsgroup: comp.std.c

    On 2021-10-01 11:05, Vincent Lefevre wrote:
    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    No, it doesn't force the implementation to violate a constraint. It
    says that a *program* that uses the INFINITY macro violates a constraint
    (if the implementation doesn't support infinities).

    Then this means that the C standard defines something the user must
    not use (except when __STDC_IEC_559__ is defined, as in this case,
    INFINITY is guaranteed to expand to the true infinity).

    Constraints apply to programs, not to implementations.

    This is related, as programs will be transformed by an implementation.

    It means that if a program assumes that INFINITY is meaningful, and it's
    compiled for a target system where it isn't, a diagnostic is guaranteed.
    And again, it might have made more sense to say that INFINITY is not
    defined for such implementations (as is done for the NAN macro), but
    perhaps there was existing practice.

    Yes, currently there is no way of fallback (without things like
    autoconf tests).

    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)?
    This should not break existing programs.

    The fallback is to test for defined(FP_INFINITE), see below.


    Here's what the C99 Rationale says:

    What is INFINITY on machines that do not support infinity? It should
    be defined along the lines of: #define INFINITY 9e99999f, where
    there are enough 9s in the exponent so that the value is too large
    to represent as a float, hence, violates the constraint of 6.4.4
    Constants. In addition, the number classification macro FP_INFINITE
    should not be defined. That allows an application to test for the
    existance of FP_INFINITE as a safe way to determine if infinity is
    supported; this is the feature test macro for support for infinity.

    The problem with this is that the standard itself doesn't say that
    FP_INFINITE is defined conditionally.

    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.


    I don't know if there is a set of similar macros for double and long
    double types buried somewhere in the standard.


    Enjoy

    Jakob
    --
    Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
    Transformervej 29, 2860 S|+borg, Denmark. Direct +45 31 13 16 10
    This public discussion message is non-binding and may contain errors.
    WiseMo - Remote Service Management for PCs, Phones and Embedded
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Fri Oct 1 14:26:09 2021
    From Newsgroup: comp.std.c

    Jakob Bohm <jb-usenet@wisemo.com.invalid> writes:
    On 2021-10-01 11:05, Vincent Lefevre wrote:
    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    No, it doesn't force the implementation to violate a constraint. It
    says that a *program* that uses the INFINITY macro violates a constraint >>> (if the implementation doesn't support infinities).
    Then this means that the C standard defines something the user must
    not use (except when __STDC_IEC_559__ is defined, as in this case,
    INFINITY is guaranteed to expand to the true infinity).

    Constraints apply to programs, not to implementations.
    This is related, as programs will be transformed by an
    implementation.

    It means that if a program assumes that INFINITY is meaningful, and it's >>> compiled for a target system where it isn't, a diagnostic is guaranteed. >>> And again, it might have made more sense to say that INFINITY is not
    defined for such implementations (as is done for the NAN macro), but
    perhaps there was existing practice.
    Yes, currently there is no way of fallback (without things like
    autoconf tests).
    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)?
    This should not break existing programs.

    The fallback is to test for defined(FP_INFINITE), see below.


    Here's what the C99 Rationale says:

    What is INFINITY on machines that do not support infinity? It should >>> be defined along the lines of: #define INFINITY 9e99999f, where
    there are enough 9s in the exponent so that the value is too large
    to represent as a float, hence, violates the constraint of 6.4.4
    Constants. In addition, the number classification macro FP_INFINITE >>> should not be defined. That allows an application to test for the
    existance of FP_INFINITE as a safe way to determine if infinity is
    supported; this is the feature test macro for support for infinity.

    The problem with this is that the standard itself doesn't say that
    FP_INFINITE is defined conditionally.
    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.


    I don't know if there is a set of similar macros for double and long
    double types buried somewhere in the standard.

    The INFINITY and NAN macros are defined only for float. I think the
    assumption is that either all floating-point types support infinities,
    or none do, and likewise for NaNs. On the other hand, fpclassify() is a
    macro that can be applied to an expression of any floating-point type.

    The problem, as I said, is that the standard doesn't say that
    FP_INFINITE is conditionally defined. Since they're specified in the
    same section that explicitly says that NAN is conditionally defined, I
    think the only reasonable reading of the standard's wording is that
    FP_INFINITE is defined whether infinities are supported or not.
    If they're not, it just means that fpclassify() will never return
    FP_INFINITE and isinf() always returns 0.

    The author(s) of the Rationale obviously *thought* that FP_INFINITE is conditionally defined. They were mistaken. The Rationale itself makes
    it clear that the Standard, not the Rationale, is what defines the
    language.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Mon Oct 4 09:26:19 2021
    From Newsgroup: comp.std.c

    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I think the implication is that it assumes either all floating types have NaNs
    and/or infinities, or none do. That might be a valid assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Mon Oct 4 10:34:18 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would not
    imply that INFINITY is usable, since for instance, long double may
    have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I think the
    implication is that it assumes either all floating types have NaNs
    and/or infinities, or none do. That might be a valid assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    IMHO it would have been better if the assumption that all floating
    types behave similarly had been stated explicitly, and perhaps if there
    were three NAN macros for the three floating-point types.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Geoff Clare@geoff@clare.See-My-Signature.invalid to comp.std.c on Tue Oct 5 13:53:06 2021
    From Newsgroup: comp.std.c

    Keith Thompson wrote:

    Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    IMHO it would have been better if the assumption that all floating
    types behave similarly had been stated explicitly, and perhaps if there
    were three NAN macros for the three floating-point types.

    NaN support for each floating type can be queried, and a NaN
    obtained if supported, by calling nanf(), nan(), and nanl().
    --
    Geoff Clare <netnews@gclare.org.uk>
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Wed Oct 6 00:12:38 2021
    From Newsgroup: comp.std.c

    In article <ieut2i-07m.ln1@ID-313840.user.individual.net>,
    Geoff Clare <geoff@clare.see-my-signature.invalid> wrote:

    NaN support for each floating type can be queried, and a NaN
    obtained if supported, by calling nanf(), nan(), and nanl().

    But they are not required to be constant expressions, while
    the NAN macro expands to a constant expression.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Thu Oct 7 07:05:35 2021
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would
    not imply that INFINITY is usable, since for instance, long
    double may have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I
    think the implication is that it assumes either all floating types
    have NaNs and/or infinities, or none do. That might be a valid
    assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    If float has a NaN then so do double and long double, because of
    6.2.5 paragraph 10. Similarly for infinity (or infinities).
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Thu Oct 7 07:51:03 2021
    From Newsgroup: comp.std.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would
    not imply that INFINITY is usable, since for instance, long
    double may have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I
    think the implication is that it assumes either all floating types
    have NaNs and/or infinities, or none do. That might be a valid
    assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    If float has a NaN then so do double and long double, because of
    6.2.5 paragraph 10. Similarly for infinity (or infinities).

    Agreed. 6.2.5p10 says:

    There are three real floating types, designated as float, double,
    and long double. The set of values of the type float is a subset of
    the set of values of the type double; the set of values of the type
    double is a subset of the set of values of the type long double.

    (No need to make everyone look it up.)
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Fri Oct 8 00:02:31 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87pmsqizrh.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    [.. use of the INFINITY macro in an implementation that does not
    have a float value for infinity..]

    If I understand correctly, it means that if an infinite value is
    not available, then a program that refers to the INFINITY macro (in
    a context where it's treated as a floating-point expression)
    violates that constraint, resulting in a required diagnostic.

    I think the consequence is more than a diagnostic (which may yield
    a compilation failure in practice, BTW): AFAIK, the standard does
    not give a particular definition for "overflows at translation
    time", which would make it undefined behavior as usual for
    overflows.

    The compound phrase does not need defining because its relevant
    constituent elements are defined in the C standard. The word
    "overflows" is defined for floating point types in 7.12.1
    paragraph 5

    A floating result overflows if the magnitude of the
    mathematical result is finite but so large that the
    mathematical result cannot be represented without
    extraordinary roundoff error in an object of the specified
    type. [...]

    The word "translation" is defined in detail in section 5.1.1.
    The compound phrase "overflows at translation time" is simply a
    combination of these defined terms under normal rules of English
    usage.

    Moreover, the C standard is quite clear that violating a
    constraint must evoke a diagnostic even if there is also
    undefined behavior. Section 5.1.1.3 paragraph 1 says this:

    A conforming implementation shall produce at least one
    diagnostic message (identified in an implementation-defined
    manner) if a preprocessing translation unit or translation
    unit contains a violation of any syntax rule or constraint,
    even if the behavior is also explicitly specified as
    undefined or implementation-defined. [...]

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Fri Oct 8 08:30:22 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    [...]

    It means that if a program assumes that INFINITY is meaningful, and
    it's compiled for a target system where it isn't, a diagnostic is
    guaranteed. And again, it might have made more sense to say that
    INFINITY is not defined for such implementations (as is done for
    the NAN macro), but perhaps there was existing practice.

    Yes, currently there is no way of fallback (without things like
    autoconf tests).

    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)? [...]

    To me it seems better for INFINITY to be defined as it is rather
    than being conditionally defined. If what is needed is really an
    infinite value, just write INFINITY and the code either works or
    compiling it gives a diagnostic. If what is needed is just a very
    large value, write HUGE_VAL (or HUGE_VALF or HUGE_VALL, depending)
    and the code works whether infinite floating-point values are
    supported or not. If it's important that infinite values be
    supported but we don't want to risk a compilation failure, use
    HUGE_VAL combined with an assertion

    assert( HUGE_VAL == HUGE_VAL/2 );

    Alternatively, use INFINITY only in one small .c file, and give
    other sources a make dependency for a successful compilation
    (with of course a -pedantic-errors option) of that .c file. I
    don't see that having INFINITY be conditionally defined buys
    anything, except to more or less force use of #if/#else/#endif
    blocks in the preprocessor. I don't mind using the preprocessor
    when there is a good reason to do so, but here I don't see one.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Fri Oct 8 11:40:09 2021
    From Newsgroup: comp.std.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    [...]
    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)? [...]

    To me it seems better for INFINITY to be defined as it is rather
    than being conditionally defined. If what is needed is really an
    infinite value, just write INFINITY and the code either works or
    compiling it gives a diagnostic. If what is needed is just a very
    large value, write HUGE_VAL (or HUGE_VALF or HUGE_VALL, depending)
    and the code works whether infinite floating-point values are
    supported or not. If it's important that infinite values be
    supported but we don't want to risk a compilation failure, use
    HUGE_VAL combined with an assertion

    assert( HUGE_VAL == HUGE_VAL/2 );

    Alternatively, use INFINITY only in one small .c file, and give
    other sources a make dependency for a successful compilation
    (with of course a -pedantic-errors option) of that .c file. I
    don't see that having INFINITY be conditionally defined buys
    anything, except to more or less force use of #if/#else/#endif
    blocks in the preprocessor. I don't mind using the preprocessor
    when there is a good reason to do so, but here I don't see one.

    I don't see how that's better than conditionally defining INFINITY.

    If you really need an infinite value, just write INFINITY and the code
    either works or compiling it gives a *clearer* diagnostic for the
    undeclared identifier.

    If you need to test whether infinities are supported, #ifdef INFINITY is
    a lot clearer than assert( HUGE_VAL == HUGE_VAL/2 ).
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Fri Oct 8 11:41:22 2021
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would
    not imply that INFINITY is usable, since for instance, long
    double may have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I
    think the implication is that it assumes either all floating types
    have NaNs and/or infinities, or none do. That might be a valid
    assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    If float has a NaN then so do double and long double, because of
    6.2.5 paragraph 10. Similarly for infinity (or infinities).

    Agreed. 6.2.5p10 says:

    There are three real floating types, designated as float, double,
    and long double. The set of values of the type float is a subset of
    the set of values of the type double; the set of values of the type
    double is a subset of the set of values of the type long double.

    (No need to make everyone look it up.)

    I just noticed that leaves open the possibility, for example, that
    double supports infinity but float doesn't.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Sat Oct 9 19:49:27 2021
    From Newsgroup: comp.std.c

    In article <874k9r7419.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would
    not imply that INFINITY is usable, since for instance, long
    double may have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I
    think the implication is that it assumes either all floating types >>>>> have NaNs and/or infinities, or none do. That might be a valid
    assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    If float has a NaN then so do double and long double, because of
    6.2.5 paragraph 10. Similarly for infinity (or infinities).

    Agreed. 6.2.5p10 says:

    There are three real floating types, designated as float, double,
    and long double. The set of values of the type float is a subset of
    the set of values of the type double; the set of values of the type
    double is a subset of the set of values of the type long double.

    (No need to make everyone look it up.)

    I just noticed that leaves open the possibility, for example, that
    double supports infinity but float doesn't.

    This is what I had said above:

    "[...] for instance, long double may have an infinity but not float."
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Sat Oct 9 20:05:38 2021
    From Newsgroup: comp.std.c

    In article <86sfxbpm9d.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    To me it seems better for INFINITY to be defined as it is rather
    than being conditionally defined. If what is needed is really an
    infinite value, just write INFINITY and the code either works or
    compiling it gives a diagnostic.

    diagnostic and undefined behavior. So this is not better than
    the case where INFINITY would be conditionally defined. At least,
    with a conditionally defined macro, one can test it and have a
    fallback, e.g. a more complex algorithm.

    If what is needed is just a very large value, write HUGE_VAL (or
    HUGE_VALF or HUGE_VALL, depending) and the code works whether
    infinite floating-point values are supported or not.

    This will not work if the main code requires infinity with a possible
    fallback. As a workaround, one could test HUGE_VAL as you said, but
    there are still potential issues. For instance, the standard does not
    guarantee that HUGE_VAL has the largest possible double value, and
    this can break algorithms based on comparisons / sorting.

    See note 232:

    "HUGE_VAL, HUGE_VALF, and HUGE_VALL can be positive infinities in
    an implementation that supports infinities."

    with just "can be" instead of "shall be".
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Sat Oct 9 20:17:09 2021
    From Newsgroup: comp.std.c

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Sat Oct 9 14:28:11 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <874k9r7419.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <877dewimc9.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <87lf3ehy4v.fsf@nosuchdomain.example.com>,
    Even if FP_INFINITE could be defined conditionally, this would
    not imply that INFINITY is usable, since for instance, long
    double may have an infinity but not float.

    The standard only defines INFINITY and NAN for type float. I
    think the implication is that it assumes either all floating types
    have NaNs and/or infinities, or none do. That might be a valid
    assumption.

    But the standard doesn't say that explicitly. It even just says
    "if and only if the implementation supports quiet NaNs for the
    float type". If the intent were to have NaN support for all the
    FP types or none, why doesn't it say "... for the floating types"
    instead of "... for the float type"?

    Since the NAN macro is of type float (if it's define), it only makes
    sense to define it that way. Presumably if an implementation had
    NaN for float but not for double, it would define NAN.

    If float has a NaN then so do double and long double, because of
    6.2.5 paragraph 10. Similarly for infinity (or infinities).

    Agreed. 6.2.5p10 says:

    There are three real floating types, designated as float, double,
    and long double. The set of values of the type float is a subset of
    the set of values of the type double; the set of values of the type
    double is a subset of the set of values of the type long double.

    (No need to make everyone look it up.)

    I just noticed that leaves open the possibility, for example, that
    double supports infinity but float doesn't.

    This is what I had said above:

    "[...] for instance, long double may have an infinity but not float."

    Yes. My initial assumption was that the three floating-point types
    could independently have or not have infinities. Tim cited 6.2.5p10,
    which implies that if float has infinities, then the wider types do
    also. (I wonder if the authors had infinities and NaNs in mind when
    they wrote that, but the implication is still there.)

    If long double has infinities, then float and double may or may not.
    If float has infinities, then double and long double must.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Oct 11 12:40:02 2021
    From Newsgroup: comp.std.c

    On 10/9/21 4:17 PM, Vincent Lefevre wrote:
    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Oct 11 12:40:18 2021
    From Newsgroup: comp.std.c

    On 10/9/21 4:05 PM, Vincent Lefevre wrote:
    ...
    there are still potential issues. For instance, the standard does not guarantee that HUGE_VAL has the largest possible double value, and

    In fact, a fully conforming implementation could define it to match
    DBL_MIN. I think that's a defect.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Mon Oct 11 12:39:50 2021
    From Newsgroup: comp.std.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 10/9/21 4:17 PM, Vincent Lefevre wrote:
    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    But does that apply when a constraint is violated?

    6.4.4p2, a constraint, says:

    Each constant shall have a type and the value of a constant shall be
    in the range of representable values for its type.

    A "constraint", aside from triggering a required diagnostic, is a
    "restriction, either syntactic or semantic, by which the exposition of
    language elements is to be interpreted", which is IMHO a bit vague.

    My mental model is that if a program violates a constraint and the implementation still accepts it (i.e., the required diagnostic is a
    non-fatal warning) the program's behavior is undefined -- but the
    standard doesn't say that. Of course if the implementation rejects the program, it has no behavior.

    For what it's worth, given this:

    double too_big = 1e1000;

    gcc, clang, and tcc all print a warning and set too_big to infinity.
    That's obviously valid if the behavior is undefined. I think it's also
    valid if the behavior is defined; the nearest representable value is
    DBL_MAX, and the larger representable value immediately adjacent to
    DBL_MAX is infinity.

    It doesn't seem to me to be particularly useful to say that a program
    can be rejected, but its behavior is defined if the implementation
    chooses not to reject it.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Oct 11 21:04:32 2021
    From Newsgroup: comp.std.c

    On 10/11/21 3:39 PM, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    ...
    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    But does that apply when a constraint is violated?

    6.4.4p2, a constraint, says:

    Each constant shall have a type and the value of a constant shall be
    in the range of representable values for its type.

    A "constraint", aside from triggering a required diagnostic, is a "restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted", which is IMHO a bit vague.

    I can agree with the "a bit vague" description. I have previously said
    "I've never understood what it is that the part of that definition after
    the second comma was intended to convey."

    "If a rCyrCyshallrCOrCO or rCyrCyshall notrCOrCO requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard
    by the words rCyrCyundefined behaviorrCOrCO or by the omission of any explicit definition of behavior." (4p2)

    There's no mention in there of a constraint violation automatically
    having undefined behavior. Most constraint violations do qualify as
    undefined behavior due to the "omission of any explicit definition of
    behavior" when the constraint is violated. But this isn't an example:
    6.4.4.2p3 provide a perfectly applicable definition for the behavior.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Mon Oct 11 18:33:24 2021
    From Newsgroup: comp.std.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 10/11/21 3:39 PM, Keith Thompson wrote:
    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    ...
    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in >>> an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    But does that apply when a constraint is violated?

    6.4.4p2, a constraint, says:

    Each constant shall have a type and the value of a constant shall be
    in the range of representable values for its type.

    A "constraint", aside from triggering a required diagnostic, is a
    "restriction, either syntactic or semantic, by which the exposition of
    language elements is to be interpreted", which is IMHO a bit vague.

    I can agree with the "a bit vague" description. I have previously said
    "I've never understood what it is that the part of that definition after
    the second comma was intended to convey."

    "If a rCyrCyshallrCOrCO or rCyrCyshall notrCOrCO requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard
    by the words rCyrCyundefined behaviorrCOrCO or by the omission of any explicit
    definition of behavior." (4p2)

    There's no mention in there of a constraint violation automatically
    having undefined behavior. Most constraint violations do qualify as
    undefined behavior due to the "omission of any explicit definition of behavior" when the constraint is violated. But this isn't an example: 6.4.4.2p3 provide a perfectly applicable definition for the behavior.

    I don't disagree.

    On the other hand, one possible interpretation of the phrase "a
    restriction ... by which the exposition of language elements is to be interpreted" could be that if the constraint is violated, there is no meaningful interpretation. Or to put it another way, that the semantic description applies only if all constraints are satisfied.

    I've searched for the word "constraint" in the C89 and C99 Rationale
    documents. They were not helpful.

    I am admittedly trying to read into the standard what I think it
    *should* say. A rule that constraint violations cause undefined
    behavior would, if nothing else, make the standard a bit simpler.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Tue Oct 26 10:01:03 2021
    From Newsgroup: comp.std.c

    In article <sk1pd2$5e3$3@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/9/21 4:17 PM, Vincent Lefevre wrote:
    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    OK, but I was asking "where is the result of an overflow defined by
    the standard?" I don't see the word "overflow" in the above spec.

    Note that if the value is DBL_MAX, then it is in the range of
    representable values for its type, and the constraint is not
    violated.

    Note also that in case of overflow, "the nearest representable value"
    is not defined. IEEE 754 defines it as infinity. But what if Annex F
    is not supported and there is an infinity? Should the value still be
    the infinity or DBL_MAX (which is really the nearest, as the distance
    is finite, while the distance to the infinity is infinite).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Tue Oct 26 12:53:31 2021
    From Newsgroup: comp.std.c

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    In article <sk1pd2$5e3$3@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/9/21 4:17 PM, Vincent Lefevre wrote:
    ...
    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    OK, but I was asking "where is the result of an overflow defined by
    the standard?" I don't see the word "overflow" in the above spec.

    Overflow occurs when a floating constant is created whose value is
    greater than DBL_MAX or less than -DBL_MAX. Despite the fact that the
    above description does not explicitly mention the word "overflow", it's perfectly clear what that description means when overflow occurs. If the constant is greater than DBL_MAX, the "nearest representable value" is
    always DBL_MAX. The next smaller representable value is
    nextafter(DBL_MAX, 0). If infinity is representable, the "larger ... representable value" is infinity; otherwise, there is no "larger
    representable value", and one of the other two must be chosen.

    Note also that in case of overflow, "the nearest representable value"
    is not defined.

    No definition by the standard is needed; the conventional mathematical definitions of "nearest" are sufficient. If infinity is representable,
    DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other
    representable value.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Thu Oct 28 09:38:21 2021
    From Newsgroup: comp.std.c

    In article <sl9bqb$hf5$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    OK, but I was asking "where is the result of an overflow defined by
    the standard?" I don't see the word "overflow" in the above spec.

    Overflow occurs when a floating constant is created whose value is
    greater than DBL_MAX or less than -DBL_MAX. Despite the fact that the
    above description does not explicitly mention the word "overflow", it's perfectly clear what that description means when overflow occurs.

    Why "perfectly clear"??? This is even inconsistent with 7.12.1p5
    of N2596, which says:

    A floating result overflows if the magnitude (absolute value)
    of the mathematical result is finite but so large that the
    mathematical result cannot be represented without extraordinary
    roundoff error in an object of the specified type.

    If you have a mathematical value (exact value) much larger than
    DBL_MAX and that rounds to DBL_MAX (e.g. with round-toward-zero),
    there should be an overflow, despite the fact that the FP result
    is not greater than DBL_MAX (since it is equal to DBL_MAX).

    Moreover, with the above definition, it is DBL_NORM_MAX that is
    more likely taken into account, not DBL_MAX. But this is probably
    not what is expected with floating-point constants.

    Note also that in case of overflow, "the nearest representable value"
    is not defined.

    No definition by the standard is needed; the conventional mathematical definitions of "nearest" are sufficient. If infinity is representable, DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other representable value.

    The issue is that this may easily be confused with the result
    obtained in the FE_TONEAREST rounding mode with the IEEE 754 rules
    (where, for instance, 2*DBL_MAX rounds to +Inf, not to DBL_MAX,
    despite the fact that 2*DBL_MAX is closer to DBL_MAX than to +Inf).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Thu Oct 28 11:23:41 2021
    From Newsgroup: comp.std.c

    On 10/28/21 5:38 AM, Vincent Lefevre wrote:
    In article <sl9bqb$hf5$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    OK, but I was asking "where is the result of an overflow defined by
    the standard?" I don't see the word "overflow" in the above spec.

    Overflow occurs when a floating constant is created whose value is
    greater than DBL_MAX or less than -DBL_MAX. Despite the fact that the
    above description does not explicitly mention the word "overflow", it's
    perfectly clear what that description means when overflow occurs.

    Why "perfectly clear"??? This is even inconsistent with 7.12.1p5
    of N2596, which says:

    7.12.1p5 describes the math library, not the handling of floating point constants. While the C standard does recommended that "The
    translation-time conversion of floating constants should match the execution-time conversion of character strings by library functions,
    such as strtod , given matching inputs suitable for both conversions,
    the same result format, and default execution-time rounding."
    (6.4.4.2p11), it does not actually require such a match. Therefore, if
    there is any inconsistency it would not be problematic.

    A floating result overflows if the magnitude (absolute value)
    of the mathematical result is finite but so large that the
    mathematical result cannot be represented without extraordinary
    roundoff error in an object of the specified type.

    7.12.1p5 goes on to say that "If a floating result overflows and default rounding is in effect, then the function returns the value of the macro HUGE_VAL ...".
    As cited above, the standard recommends, but does not require, the use
    of default execution-time rounding mode for floating point constants.
    HUGE_VAL is only required to be positive (7.12p6) - it could be as small
    as DBL_MIN. However, on implementations that support infinities, it is
    allowed to be a positive infinity (footnote 245), and when
    __STDC_IEC_559__ is pre#defined by the implementation, it's required to
    be positive infinity (F10p2). Even if it isn't positive infinity, it is
    allowed to be DBL_MAX. DBL_MAX and positive infinity are two of the
    three options allowed by 6.4.4.2p4 for constants larger than DBL_MAX, in
    which case there's no conflict.
    If HUGE_VAL is not one of those three values, then 6.4.4.2p4 still
    applies, but 7.12.1p5 need not apply, since a match to the behavior of
    strtod() is only recommended, not required..

    If you have a mathematical value (exact value) much larger than
    DBL_MAX and that rounds to DBL_MAX (e.g. with round-toward-zero),
    there should be an overflow, despite the fact that the FP result
    is not greater than DBL_MAX (since it is equal to DBL_MAX).

    Agreed. As a result, the overflow exception should be signaled. However,
    the C standard mandates that "Floating constants are converted to
    internal format as if at translation-time. The conversion of a floating constant shall not raise an exceptional condition or a floating-point
    exception at execution time." (6.4.4.2p8). If an implementation chooses
    to do the conversion at translation-time, the exception would be raised
    only within the compiler, which has no obligation to do anything with
    it. The implementation could generate a diagnostic, but such a constant
    is not, in itself, justification for rejecting the program.

    Therefore, if an implementation chooses to defer actual conversion until run-time, it's required to produce the same results, which means it must
    clear that overflow exception before turning control over to the user code.

    Moreover, with the above definition, it is DBL_NORM_MAX that is
    more likely taken into account, not DBL_MAX.

    According to 5.2.4.2.2p19, DBL_MAX is the maximum representable finite
    floating point value, while DBL_NORM_MAX is the maximum normalized
    number. 6.4.4.2p4 refers only to representable values, saying nothing
    about normalization. Neither 7.12.5p1 nor 7.12p6 say anything to require
    that the value be normalized. Therefore, as far as I can see, DBL_MAX is
    the relevant value.

    Note also that in case of overflow, "the nearest representable value"
    is not defined.

    No definition by the standard is needed; the conventional mathematical
    definitions of "nearest" are sufficient. If infinity is representable,
    DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other
    representable value.

    The issue is that this may easily be confused with the result
    obtained in the FE_TONEAREST rounding mode with the IEEE 754 rules
    (where, for instance, 2*DBL_MAX rounds to +Inf, not to DBL_MAX,
    despite the fact that 2*DBL_MAX is closer to DBL_MAX than to +Inf).

    Yes, and DBL_MAX and +Inf are two of the three values permitted by
    6.4.4.2p4, so I don't see any conflict there. As far as I can see, the
    value required by IEEE 754 is always one of the three values permitted
    by 6.4.4.2p4, so there's never a conflict. Are you aware of any?

    For hexadecimal floating point constants on systems with FLT_RADIX a
    power of 2, 6.4.4.2p4 only allows one value - the one that is correctly
    rounded - but that's precisely the same value that IEEE 754 requires.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Fri Oct 29 12:12:02 2021
    From Newsgroup: comp.std.c

    In article <slef9t$98j$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/28/21 5:38 AM, Vincent Lefevre wrote:
    In article <sl9bqb$hf5$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    OK, but I was asking "where is the result of an overflow defined by
    the standard?" I don't see the word "overflow" in the above spec.

    Overflow occurs when a floating constant is created whose value is
    greater than DBL_MAX or less than -DBL_MAX. Despite the fact that the
    above description does not explicitly mention the word "overflow", it's
    perfectly clear what that description means when overflow occurs.

    Why "perfectly clear"??? This is even inconsistent with 7.12.1p5
    of N2596, which says:

    7.12.1p5 describes the math library, not the handling of floating point constants. While the C standard does recommended that "The
    translation-time conversion of floating constants should match the execution-time conversion of character strings by library functions,
    such as strtod , given matching inputs suitable for both conversions,
    the same result format, and default execution-time rounding."
    (6.4.4.2p11), it does not actually require such a match. Therefore, if
    there is any inconsistency it would not be problematic.

    Yes, but this means that any implicit use of overflow is not
    perfectly clear.

    A floating result overflows if the magnitude (absolute value)
    of the mathematical result is finite but so large that the
    mathematical result cannot be represented without extraordinary
    roundoff error in an object of the specified type.

    7.12.1p5 goes on to say that "If a floating result overflows and default rounding is in effect, then the function returns the value of the macro HUGE_VAL ...".
    As cited above, the standard recommends, but does not require, the use
    of default execution-time rounding mode for floating point constants. HUGE_VAL is only required to be positive (7.12p6) - it could be as small
    as DBL_MIN.

    Note that C2x (in particular, the current draft N2731) requires that nextup(HUGE_VAL) be HUGE_VAL, probably assuming that HUGE_VAL is the
    maximum value. I've just sent a mail to the CFP list about that.

    Moreover, with the above definition, it is DBL_NORM_MAX that is
    more likely taken into account, not DBL_MAX.

    According to 5.2.4.2.2p19, DBL_MAX is the maximum representable finite floating point value, while DBL_NORM_MAX is the maximum normalized
    number. 6.4.4.2p4 refers only to representable values, saying nothing
    about normalization. Neither 7.12.5p1 nor 7.12p6 say anything to require
    that the value be normalized. Therefore, as far as I can see, DBL_MAX is
    the relevant value.

    But DBL_NORM_MAX is the relevant value for the general definition
    of "overflow" (on double). So in 7.12p4, "overflows" is not used
    correctly, at least not this the usual meaning.

    More than that, with the IEEE 754 overflow definition, you have
    numbers larger than DBL_MAX (up to those within 1 ulp) that do not
    overflow.

    Note also that in case of overflow, "the nearest representable value"
    is not defined.

    No definition by the standard is needed; the conventional mathematical
    definitions of "nearest" are sufficient. If infinity is representable,
    DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other
    representable value.

    The issue is that this may easily be confused with the result
    obtained in the FE_TONEAREST rounding mode with the IEEE 754 rules
    (where, for instance, 2*DBL_MAX rounds to +Inf, not to DBL_MAX,
    despite the fact that 2*DBL_MAX is closer to DBL_MAX than to +Inf).

    Yes, and DBL_MAX and +Inf are two of the three values permitted by
    6.4.4.2p4, so I don't see any conflict there.

    My point is that this definition of "nearest" does not match the
    definition of IEEE 754's FE_TONEAREST. I'm not saying that there
    is a conflict, just that the text is ambiguous. If one follows
    the IEEE 754 definition, there are only two possible values
    (DBL_MAX and +Inf, thus excluding nextdown(DBL_MAX)).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Sat Oct 30 02:08:20 2021
    From Newsgroup: comp.std.c

    On 10/29/21 8:12 AM, Vincent Lefevre wrote:
    In article <slef9t$98j$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/28/21 5:38 AM, Vincent Lefevre wrote:
    In article <sl9bqb$hf5$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    ...
    7.12.1p5 describes the math library, not the handling of floating point
    constants. While the C standard does recommended that "The
    translation-time conversion of floating constants should match the
    execution-time conversion of character strings by library functions,
    such as strtod , given matching inputs suitable for both conversions,
    the same result format, and default execution-time rounding."
    (6.4.4.2p11), it does not actually require such a match. Therefore, if
    there is any inconsistency it would not be problematic.

    Yes, but this means that any implicit use of overflow is not
    perfectly clear.

    What is unclear about it? It very explicitly allows three different
    values, deliberately failing to specify only one of them as valid, and
    it is perfectly clear what those three values are.

    ...
    7.12.1p5 goes on to say that "If a floating result overflows and default
    rounding is in effect, then the function returns the value of the macro
    HUGE_VAL ...".
    As cited above, the standard recommends, but does not require, the use
    of default execution-time rounding mode for floating point constants.
    HUGE_VAL is only required to be positive (7.12p6) - it could be as small
    as DBL_MIN.

    Note that C2x (in particular, the current draft N2731) requires that nextup(HUGE_VAL) be HUGE_VAL, probably assuming that HUGE_VAL is the
    maximum value. I've just sent a mail to the CFP list about that.

    I've just downloaded N2731.pdf. Yes, that is an improvement over the
    previous specification, and strengthens my argument: the value that is
    required by 7.12.1p5 for strtod() in the event of overflow is now always
    one of two or three values permitted by 6.4.4.2p4 for overflowing floating-point constants, regardless of whether the floating point
    format supports infinities or IEEE 754.

    ...
    about normalization. Neither 7.12.5p1 nor 7.12p6 say anything to require
    that the value be normalized. Therefore, as far as I can see, DBL_MAX is
    the relevant value.

    But DBL_NORM_MAX is the relevant value for the general definition
    of "overflow" (on double). So in 7.12p4, "overflows" is not used
    correctly, at least not this the usual meaning.

    What do you consider the "general definition of overflow"? I would have
    though you were referring to 7.12.1p5, but I see no wording there that distinguishes between normalized and unnormalized values.

    More than that, with the IEEE 754 overflow definition, you have
    numbers larger than DBL_MAX (up to those within 1 ulp) that do not
    overflow.

    I don't see how that's a problem.

    ...
    No definition by the standard is needed; the conventional mathematical >>>> definitions of "nearest" are sufficient. If infinity is representable, >>>> DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other
    representable value.

    The issue is that this may easily be confused with the result
    obtained in the FE_TONEAREST rounding mode with the IEEE 754 rules
    (where, for instance, 2*DBL_MAX rounds to +Inf, not to DBL_MAX,
    despite the fact that 2*DBL_MAX is closer to DBL_MAX than to +Inf).

    Yes, and DBL_MAX and +Inf are two of the three values permitted by
    6.4.4.2p4, so I don't see any conflict there.

    My point is that this definition of "nearest" does not match the
    definition of IEEE 754's FE_TONEAREST.

    FE_TONEAREST is not "IEEE 754's". It is a macro defined by the C
    standard, and in the latest draft it's been changed so it now represents
    IEC 60559's "roundTiesToEven" rounding attribute.

    The C standard does not define "nearest", it merely uses it in the
    phrase "nearest representable value", the same exact phrase used for
    exactly the same purpose by IEC 60559 while describing the
    roundTiesToEven rounding attribute. Note that I'm not saying that roundTiesToEven is defined as producing the "nearest representable
    value" - only that the specification starts out from that phrase, and
    then adds complications to it, such as how ties and overflows are handled.

    Section 6.4.4.2p4 uses "nearest representable value" to identify one of
    the three permitted values, and uses that value to determine the other
    two permitted values. It does not define a rounding mode, and was not
    intended to do so. But every IEC 60559 rounding mode selects one of the
    three values permitted by 6.4.4.2p4.

    ... I'm not saying that there
    is a conflict, just that the text is ambiguous. If one follows
    the IEEE 754 definition, there are only two possible values
    (DBL_MAX and +Inf, thus excluding nextdown(DBL_MAX)).

    Yes, that was deliberate - it was intended to be compatible with IEC
    60559, but also to be sufficiently loose to allow use of non-IEC 60559
    floating point.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Mon Nov 8 02:44:17 2021
    From Newsgroup: comp.std.c

    In article <slingl$56v$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/29/21 8:12 AM, Vincent Lefevre wrote:
    In article <slef9t$98j$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/28/21 5:38 AM, Vincent Lefevre wrote:
    In article <sl9bqb$hf5$2@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/26/21 6:01 AM, Vincent Lefevre wrote:
    ...
    7.12.1p5 describes the math library, not the handling of floating point
    constants. While the C standard does recommended that "The
    translation-time conversion of floating constants should match the
    execution-time conversion of character strings by library functions,
    such as strtod , given matching inputs suitable for both conversions,
    the same result format, and default execution-time rounding."
    (6.4.4.2p11), it does not actually require such a match. Therefore, if
    there is any inconsistency it would not be problematic.

    Yes, but this means that any implicit use of overflow is not
    perfectly clear.

    What is unclear about it? It very explicitly allows three different
    values, deliberately failing to specify only one of them as valid, and
    it is perfectly clear what those three values are.

    These rules are not about overflow. They are general rules.

    What is not defined is when a value overflows (there are different definitions). And what is the consequence of the overflow (at runtime,
    there may be traps).

    But DBL_NORM_MAX is the relevant value for the general definition
    of "overflow" (on double). So in 7.12p4, "overflows" is not used
    correctly, at least not this the usual meaning.

    What do you consider the "general definition of overflow"?

    The one given by the standard in 7.12.1p5.

    I would have though you were referring to 7.12.1p5, but I see no
    wording there that distinguishes between normalized and unnormalized
    values.

    "A floating result overflows if the magnitude of the mathematical
    result is finite but so large that the mathematical result cannot
    be represented without extraordinary roundoff error in an object
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    of the specified type."

    If the exact result is above the maximum normal value, there is
    likely to be an extraordinary roundoff error.

    More than that, with the IEEE 754 overflow definition, you have
    numbers larger than DBL_MAX (up to those within 1 ulp) that do not overflow.

    I don't see how that's a problem.

    Your definition conflicts with IEEE 754.

    Note also that overflow is also used for any floating-point expression
    (not just math functions of the C library). See 7.6.2. And when Annex F
    is supported, the IEEE 754 definition necessarily applies to the
    associated FP types.

    ...
    No definition by the standard is needed; the conventional mathematical >>>> definitions of "nearest" are sufficient. If infinity is representable, >>>> DBL_MAX is always nearer to any finite value than infinity is.
    Regardless of whether infinity is representable, any finite value
    greater than DBL_MAX is closer to DBL_MAX than it is to any other
    representable value.

    The issue is that this may easily be confused with the result
    obtained in the FE_TONEAREST rounding mode with the IEEE 754 rules
    (where, for instance, 2*DBL_MAX rounds to +Inf, not to DBL_MAX,
    despite the fact that 2*DBL_MAX is closer to DBL_MAX than to +Inf).

    Yes, and DBL_MAX and +Inf are two of the three values permitted by
    6.4.4.2p4, so I don't see any conflict there.

    My point is that this definition of "nearest" does not match the
    definition of IEEE 754's FE_TONEAREST.

    FE_TONEAREST is not "IEEE 754's". It is a macro defined by the C
    standard, and in the latest draft it's been changed so it now represents
    IEC 60559's "roundTiesToEven" rounding attribute.

    If Annex F is supported, FE_TONEAREST corresponds to the IEEE 754-1985 round-to-nearest mode. This is what I mean.

    ... I'm not saying that there
    is a conflict, just that the text is ambiguous. If one follows
    the IEEE 754 definition, there are only two possible values
    (DBL_MAX and +Inf, thus excluding nextdown(DBL_MAX)).

    Yes, that was deliberate - it was intended to be compatible with IEC
    60559, but also to be sufficiently loose to allow use of non-IEC 60559 floating point.

    But what is allowed is not clear for an IEEE 754 format (this does
    not affect the INFINITY macro, but users could write exact values
    larger than DBL_MAX + 1 ulp, for which nextdown(DBL_MAX) could be
    unexpected as the obtained value).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Nov 8 01:46:18 2021
    From Newsgroup: comp.std.c

    On 11/7/21 9:44 PM, Vincent Lefevre wrote:
    In article <slingl$56v$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 10/29/21 8:12 AM, Vincent Lefevre wrote:
    ...
    Yes, but this means that any implicit use of overflow is not
    perfectly clear.

    What is unclear about it? It very explicitly allows three different
    values, deliberately failing to specify only one of them as valid, and
    it is perfectly clear what those three values are.

    These rules are not about overflow. They are general rules.

    Yes, and they are sufficiently general that it is perfectly clear how
    they apply to the case when there is overflow.

    What is not defined is when a value overflows (there are different definitions). And what is the consequence of the overflow (at runtime,
    there may be traps).

    We're talking about floating point constants here. The standard clearly specifies that "Floating constants are converted to internal format as
    if at translation-time. The conversion of a floating constant shall not
    raise an exceptional condition or a floating-point exception at
    execution time." Runtime behavior is not the issue, and traps are not
    allowed.

    The standard describes two cases: if infinities are supported (as they necessarily are when IEEE formats are used), INFINITY is required to
    expand to a constant expression that represents positive or unsigned
    infinity. This is not outside the range of representable values - that
    range includes either positive or unsigned infinity, so the constraint
    in 6.4.4p2 is not violated.

    If infinities are not supported (which is therefore necessarily not an
    IEEE format), then INFINITY is required to expand to a constant that
    will overflow. This does violate that constraint, which means that a
    diagnostic message is required.

    That's why it confuses me that you're talking about INFINITY violating
    the constraint in 6.4.4p2 and the requirements of IEEE 754 at the same
    time. If float uses an IEEE 754 floating point format, the way that
    INFINITY is required to be defined doesn't violate that constraint.

    It's normally the case that, when a constraint is violated, the behavior
    is undefined. However, that's not because of anything the standard says
    about constraint violations in general. It's because, in most cases, the behavior is undefined "by the omission of any explicit definition of
    behavior." (4p2). However, this is one of the rare exceptions: there is
    no such omission. There is a general definition of the behavior that
    continues to apply in a perfectly clear fashion even in the event of
    overflow. Therefore, an implementation is required to assign a value to
    such a constant that is one of the two identified by that definition,
    either FLT_MAX or nextdownf(FLT_MAX).

    But DBL_NORM_MAX is the relevant value for the general definition
    of "overflow" (on double). So in 7.12p4, "overflows" is not used
    correctly, at least not this the usual meaning.

    What do you consider the "general definition of overflow"?

    The one given by the standard in 7.12.1p5.

    I would have though you were referring to 7.12.1p5, but I see no
    wording there that distinguishes between normalized and unnormalized
    values.

    "A floating result overflows if the magnitude of the mathematical
    result is finite but so large that the mathematical result cannot
    be represented without extraordinary roundoff error in an object
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    of the specified type."

    If the exact result is above the maximum normal value, there is
    likely to be an extraordinary roundoff error.

    Your comment made me realize that I had no idea how DBL_NORM_MAX could
    possibly be less than DBL_MAX. I did some searching, and discovered
    official text of a committee decision indicating that they are normally
    the same - the only exception known to the committee was systems that implemented a long double as the sum of a pair of doubles, for which
    LDBL_MAX == 2.0L*DBL_MAX, while LDBL_NORM_MAX is just slightly larger
    than DBL_MAX.

    However, I'm confused about how this connects to the standard's
    definition of normalized floating-point numbers: "f_1 > 0"
    (5.2.4.2.2p4). It seems to me that, even for the pair-of-doubles format, LDBL_MAX is represented by a value with f_1 = 1, and therefore is a
    normalized floating point number that is larger than LDBL_NORM_MAX,
    which strikes me as a contradiction.

    In any event, INFINITY is required to expand into an expression of type "float", so if the only known exception involves long double, it's not
    very relevant.

    ...
    ... I'm not saying that there
    is a conflict, just that the text is ambiguous. If one follows
    the IEEE 754 definition, there are only two possible values
    (DBL_MAX and +Inf, thus excluding nextdown(DBL_MAX)).

    Yes, that was deliberate - it was intended to be compatible with IEC
    60559, but also to be sufficiently loose to allow use of non-IEC 60559
    floating point.

    But what is allowed is not clear for an IEEE 754 format (this does
    not affect the INFINITY macro, but users could write exact values
    larger than DBL_MAX + 1 ulp, for which nextdown(DBL_MAX) could be
    unexpected as the obtained value).

    It's unexpected because that would violate a requirement of IEEE 754,
    but the C standard doesn't require violating that requirement. Section 6.4.4.2p4 of the C standard allows such a constant to have any one of
    the three values (+infinity, FLT_MAX, or nextdownf(FLT_MAX)).
    Therefore, an implementation that wants to conform to both the C
    standard and IEEE 754 must select FLT_MAX. What's unclear or ambiguous
    about that?

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Tue Nov 9 07:13:02 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    I'm wondering if you have resolved your original uncertainty
    about the behavior of INFINITY in an implementation that does
    not support infinities?
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Wed Nov 10 13:16:40 2021
    From Newsgroup: comp.std.c

    In article <861r3pbbwh.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    I'm wondering if you have resolved your original uncertainty
    about the behavior of INFINITY in an implementation that does
    not support infinities?

    I suspect that by saying "overflow", the standard actually meant that
    the result is not in the range of representable values. This is the
    only way the footnote "In this case, using INFINITY will violate the
    constraint in 6.4.4 and thus require a diagnostic." can make sense
    (the constraint in 6.4.4 is about the range, not overflow). But IMHO,
    the failing constraint makes the behavior undefined, actually makes
    the program erroneous.

    Similarly, on

    static int i = 1 / 0;
    int main (void)
    {
    return 0;
    }

    GCC fails to translate the program due to the failing constraint:

    tst.c:1:16: error: initializer element is not constant
    1 | static int i = 1 / 0;
    | ^

    (this is not just a diagnostic, GCC does not generate an executable).

    Ditto with Clang:

    tst.c:1:18: error: initializer element is not a compile-time constant
    static int i = 1 / 0;
    ~~^~~
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Wed Nov 10 08:02:24 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <861r3pbbwh.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    I'm wondering if you have resolved your original uncertainty
    about the behavior of INFINITY in an implementation that does
    not support infinities?

    I suspect that by saying "overflow", the standard actually meant that
    the result is not in the range of representable values. This is the
    only way the footnote "In this case, using INFINITY will violate the constraint in 6.4.4 and thus require a diagnostic." can make sense
    (the constraint in 6.4.4 is about the range, not overflow). But IMHO,
    the failing constraint makes the behavior undefined, actually makes
    the program erroneous.

    Suppose we have an implementation that does not support
    infinities, a range of double and long double up to about ten to
    the 99999, and ask it to translate the following .c file

    double way_too_big = 1.e1000000;

    This constant value violates the constraint in 6.4.4. Do you
    think this .c file (and any program it is part of) has undefined
    behavior? If so, do you think any constraint violation implies
    undefined behavior, or just some of them?

    Similarly, on

    static int i = 1 / 0;
    int main (void)
    {
    return 0;
    }

    GCC fails to translate the program due to the failing constraint:

    tst.c:1:16: error: initializer element is not constant
    1 | static int i = 1 / 0;
    | ^

    (this is not just a diagnostic, GCC does not generate an
    executable).

    Note that the C standard does not distinguish between "errors"
    and "warnings" in diagnostic messages. Either is allowed
    regardless of whether undefined behavior is present.

    Ditto with Clang:

    tst.c:1:18: error: initializer element is not a compile-time constant
    static int i = 1 / 0;
    ~~^~~

    The messages indicate that the failure is not about exceeding the
    range of a type, but rather about satisfying the constraints for
    constant expressions, in particular 6.6 p4, which says in part

    Each constant expression shall evaluate to a constant [...]

    The problem here is that 1/0 doesn't evaluate to anything,
    because division by 0 is not defined. Any question of range of
    representable values doesn't enter into it.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Wed Nov 10 15:01:46 2021
    From Newsgroup: comp.std.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <861r3pbbwh.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    Vincent Lefevre <vincent-news@vinc17.net> writes:
    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    I'm wondering if you have resolved your original uncertainty
    about the behavior of INFINITY in an implementation that does
    not support infinities?

    I suspect that by saying "overflow", the standard actually meant that
    the result is not in the range of representable values. This is the
    only way the footnote "In this case, using INFINITY will violate the
    constraint in 6.4.4 and thus require a diagnostic." can make sense
    (the constraint in 6.4.4 is about the range, not overflow). But IMHO,
    the failing constraint makes the behavior undefined, actually makes
    the program erroneous.

    Suppose we have an implementation that does not support
    infinities, a range of double and long double up to about ten to
    the 99999, and ask it to translate the following .c file

    double way_too_big = 1.e1000000;

    This constant value violates the constraint in 6.4.4. Do you
    think this .c file (and any program it is part of) has undefined
    behavior? If so, do you think any constraint violation implies
    undefined behavior, or just some of them?

    (Jumping in though the question was addressed to someone else.)

    I think it's a tricky question. I think the language would be cleaner
    if the standard explicitly stated that violating a constraint always
    results in undefined behavior -- or if it explicitly stated that it
    doesn't. (The former is my personal preference.)

    Clearly a compiler is allowed (but not required) to reject a program
    that violates a constraint. If it does so, there is no behavior. So
    the question is whether the behavior is undefined if the implementation
    chooses not to reject it. (I personally don't see a whole lot of value
    in defining the behavior of code that could have been rejected outright.
    I'm also not a big fan of the fact that required diagnostics don't have
    to be fatal, but that's not likely to change.)

    The semantics of floating constants specify that the value is "either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner". Given that infinities are not
    supported, that would be DBL_MAX or its predecessor. Based on that, I'd
    say that:

    - A diagnostic is required.
    - A compiler may reject the program.
    - If the compiler doesn't reject the program, the value of way_too_big
    must be DBL_MAX or its predecessor. (Making it the predecessor of
    DBL_MAX would be weird but conforming.)

    *Except* that the definition of "constraint" is "restriction, either
    syntactic or semantic, by which the exposition of language elements is
    to be interpreted". I find that rather vague, but it could be
    interpreted to mean that if a constraint is violated, there is no valid interpretation of language elements.

    Rejecting 1.e1000000 with a fatal diagnostic is clearly conforming.

    Issuing a non-fatal warning for 1.e1000000 and setting way_too_big to
    DBL_MAX is conforming (even if the behavior is/were undefined, that's
    perfectly valid).

    An implementation that issues a non-fatal warning for 1.e1000000 and
    sets way_too_big to 42.0 is arguably non-conforming, but if its
    implementers argue that the behavior is undefined because of their interpretation of the standard's definition of "constraint", I'd have a
    hard time claiming they're wrong.

    [...]
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Fri Nov 12 23:55:37 2021
    From Newsgroup: comp.std.c

    In article <86wnlg9ey7.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose we have an implementation that does not support
    infinities, a range of double and long double up to about ten to
    the 99999, and ask it to translate the following .c file

    double way_too_big = 1.e1000000;

    This constant value violates the constraint in 6.4.4. Do you
    think this .c file (and any program it is part of) has undefined
    behavior? If so, do you think any constraint violation implies
    undefined behavior, or just some of them?

    I think that constraints are there to define conditions under which specifications make sense. Thus, if a constraint is not satisfied,
    behavior is undefined (unless the standard *specifically* defines
    cases for which the constraint would not be satisfied; this is true
    for other kinds of undefined behavior, such as with Annex F, which
    defines the result of 1.0 / 0.0).

    That's also why there are diagnostics, which would otherwise be
    useless in the standard.

    In case this is not clear, the intent of the diagnostic in the above
    case is not about an inaccuracy, because the inaccuracy also exists
    when infinities are supported (and in this case, the constraint is
    satisfied, i.e. no required diagnostics).

    Similarly, on

    static int i = 1 / 0;
    int main (void)
    {
    return 0;
    }

    GCC fails to translate the program due to the failing constraint:

    tst.c:1:16: error: initializer element is not constant
    1 | static int i = 1 / 0;
    | ^

    (this is not just a diagnostic, GCC does not generate an
    executable).

    Note that the C standard does not distinguish between "errors"
    and "warnings" in diagnostic messages. Either is allowed
    regardless of whether undefined behavior is present.

    Agreed (but I think that GCC will generally generate an error
    when this is undefined behavior, though one needs -pedantic-errors
    to make sure that no extensions are used to define things that
    are normally undefined).

    Ditto with Clang:

    tst.c:1:18: error: initializer element is not a compile-time constant static int i = 1 / 0;
    ~~^~~

    The messages indicate that the failure is not about exceeding the
    range of a type, but rather about satisfying the constraints for
    constant expressions, in particular 6.6 p4, which says in part

    Each constant expression shall evaluate to a constant [...]

    Yes, this was my point.

    The problem here is that 1/0 doesn't evaluate to anything,
    because division by 0 is not defined. Any question of range of
    representable values doesn't enter into it.

    My point is that 1 / 0 is not regarded as a constant expression
    (here because 1 / 0 isn't mathematically defined, but the cause
    could also be that the result is out of range, as seen below).

    Ditto with

    static int i = 2147483647 + 2147483647;

    but -pedantic-errors is needed as I've said above. On

    int main (void)
    {
    static int i = 2147483647 + 2147483647;
    return 0;
    }

    "gcc -pedantic-errors" gives

    tst.c:3:3: error: overflow in constant expression [-Woverflow]
    3 | static int i = 2147483647 + 2147483647;
    | ^~~~~~

    but no errors (= no diagnostics due to a failing constraint) for

    int main (void)
    {
    int i = 2147483647 + 2147483647;
    return 0;
    }

    because 2147483647 + 2147483647 is not regarded as a constant
    expression (as explained in DR 261).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Sat Nov 13 00:30:50 2021
    From Newsgroup: comp.std.c

    In article <87fss3wr6t.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    I think it's a tricky question. I think the language would be cleaner
    if the standard explicitly stated that violating a constraint always
    results in undefined behavior -- or if it explicitly stated that it
    doesn't. (The former is my personal preference.)

    I agree. But note that there's this definition:

    3.8
    constraint
    restriction, either syntactic or semantic, by which the exposition of
    language elements is to be interpreted

    As I understand, if such a restriction is not fulfilled, then there
    is no interpretation; hence undefined behavior (or program rejection).

    But DR 261 says that if one can do without having to use an
    unsatisfied constraint, then this is fine. For instance, 1 / 0
    is not regarded as a constant expression, just as a "normal"
    expression, because it fails to satisfy constraint 6.6p4 on
    constant expressions. (In a context of a required constant
    expression, there will be undefined behavior or the program will
    be rejected, whether the expression is not regarded as a constant
    expression or one just considers the failed constraint.)

    The semantics of floating constants specify that the value is "either
    the nearest representable value, or the larger or smaller representable
    value immediately adjacent to the nearest representable value, chosen in
    an implementation-defined manner". Given that infinities are not
    supported, that would be DBL_MAX or its predecessor. Based on that, I'd
    say that:

    - A diagnostic is required.
    - A compiler may reject the program.
    - If the compiler doesn't reject the program, the value of way_too_big
    must be DBL_MAX or its predecessor. (Making it the predecessor of
    DBL_MAX would be weird but conforming.)

    *Except* that the definition of "constraint" is "restriction, either syntactic or semantic, by which the exposition of language elements is
    to be interpreted". I find that rather vague, but it could be
    interpreted to mean that if a constraint is violated, there is no valid interpretation of language elements.

    Yes, this is rather vague, but I think that this should be regarded
    as undefined behavior (but nothing prevents the implementation from
    defining the behavior). Note that this would allow an implementation
    to leave the variable as uninitialized[*], assuming that if the user
    wants to use the program despite the diagnostic, the program will
    work perfectly as long as the variable is not used.

    [*] A possible justification is that if the user defined a variable
    whose initializer doesn't make sense on some plarform, this can
    mean that this variable will never be used on such a plarform,
    e.g. as being used in dead code only.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Fri Nov 12 21:03:18 2021
    From Newsgroup: comp.std.c

    On 11/12/21 6:17 PM, Vincent Lefevre wrote:
    In article <smgu08$3r1$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    ...
    I assume we've been talking about implementations that conform to the C
    standard, right? Otherwise there's nothing meaningful that can be said.

    The issue is more related to (strictly) conforming programs.

    It can't be. Strictly conforming programs are prohibited from having
    output that depends upon behavior that the standard leaves unspecified. 6.4.4.2p4 identifies what is usually three different possible values for
    each floating point constant (four if the constant describes a value
    exactly half-way between two consecutive representable values, but only
    two if it describes a value larger than DBL_MAX or smaller than -DBL_MAX
    on a platform that doesn't support infinities), and leaves it
    unspecified which one of those values is chosen. Since that is precisely
    the freedom of choice that you're complaining about, we can't be
    discussing strictly conforming programs - if your program's output
    didn't depend upon which choice was made, you'd have no reason to worry
    about which choice was made.

    And at this point, I've officially grown weary of this discussion, and
    am bowing out.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Mon Nov 15 09:18:31 2021
    From Newsgroup: comp.std.c

    In article <smn6d8$c92$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/12/21 6:17 PM, Vincent Lefevre wrote:
    In article <smgu08$3r1$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    ...
    I assume we've been talking about implementations that conform to the C
    standard, right? Otherwise there's nothing meaningful that can be said.

    The issue is more related to (strictly) conforming programs.

    It can't be. Strictly conforming programs are prohibited from having
    output that depends upon behavior that the standard leaves unspecified.

    This is not how I interpret the standard. Otherwise there would be
    an obvious contradiction with note 3, which uses

    #ifdef __STDC_IEC_559__

    while the value of __STDC_IEC_559__ is not specified in the standard.

    What matters is that the program needs to take every possibility into
    account and make sure that the (visible) behavior is the same in each
    case. So...

    6.4.4.2p4 identifies what is usually three different possible values for
    each floating point constant (four if the constant describes a value
    exactly half-way between two consecutive representable values, but only
    two if it describes a value larger than DBL_MAX or smaller than -DBL_MAX
    on a platform that doesn't support infinities), and leaves it
    unspecified which one of those values is chosen.

    The program can deal with that in order to get the same behavior in
    each case, so that it could be strictly conforming. However, if the
    behavior is undefined (assumed as a consequence of the failed
    constraint), there is *nothing* that one can do.

    That said, since the floating-point accuracy is not specified, can be
    extremely low and is not even checkable by the program (so that there
    is no possible fallback in case of low accuracy), there is not much
    one can do with floating point.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Nov 15 07:59:00 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86wnlg9ey7.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose we have an implementation that does not support
    infinities, a range of double and long double up to about ten to
    the 99999, and ask it to translate the following .c file

    double way_too_big = 1.e1000000;

    This constant value violates the constraint in 6.4.4. Do you
    think this .c file (and any program it is part of) has undefined
    behavior? If so, do you think any constraint violation implies
    undefined behavior, or just some of them?

    I think that constraints are there to define conditions under which specifications make sense. Thus, if a constraint is not satisfied,
    behavior is undefined [...]

    Suppose again we have an implementation that does not support
    infinities and has a range of double and long double up to about
    ten to the 99999. Question one: as far as the C standard is
    concerned, is the treatment of this .c file

    double way_too_big = 1.e1000000;

    and of this .c file

    #include <math.h>

    double way_too_big = INFINITY;

    the same in the two cases? (The question is meant to disregard
    differences that are purely implementation choices, as for
    example possibly labelling one case a "warning" and the other
    case an "error".)

    Question two: does the C standard require that at least one
    diagnostic be issued for each of the above .c files?

    Note that both of these are yes/no questions.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Nov 15 14:25:37 2021
    From Newsgroup: comp.std.c

    On 11/15/21 4:18 AM, Vincent Lefevre wrote:
    In article <smn6d8$c92$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/12/21 6:17 PM, Vincent Lefevre wrote:
    ...
    The issue is more related to (strictly) conforming programs.

    It can't be. Strictly conforming programs are prohibited from having
    output that depends upon behavior that the standard leaves unspecified.

    This is not how I interpret the standard.

    I don't see how there's room for interpretation: "A strictly conforming
    program ... shall not produce output dependent on any unspecified ...
    behavior, ..." (4p6).

    Otherwise there would be
    an obvious contradiction with note 3, which uses



    #ifdef __STDC_IEC_559__

    while the value of __STDC_IEC_559__ is not specified in the standard.

    What matters is that the program needs to take every possibility into
    account and make sure that the (visible) behavior is the same in each
    case. So...

    The example in that footnote is based upon the fact that it's
    unspecified whether the macro FE_UPWARD is #defined in <fenv.h>. The
    call to fesetround(FE_UPWARD) would refer to an undeclared identifier if
    it wasn't. The technique shown in Footnote 3 ensures that fsetround()
    doesn't even get called unless __STDC_IEC_60559_BFP__ is already
    #defined, thereby ensuring that FE_UPWARD is #defined, and as a result
    the output doesn't change just because that call is made. Note: it would
    have been better to write

    #ifdef FE_UPWARD
    fesetround(FE_UPWARD);
    #endif

    Implementations that don't fully support IEC 60559 might still support FE_UPWARD.

    The example code in that footnote is, however, rather badly chosen,
    because it's pretty nearly impossible to make any meaningful use of
    floating point operations without producing output that depends upon
    things that are unspecified. While the technique shown in Footnote 3
    does prevent the call to fesetround() from being problematic in itself,
    any situation where the developer cares about the rounding direction
    implies that the output from the program will depend upon how rounding
    is performed. If that weren't the case, why bother calling it?

    That's even more true of __STD_IEC_60559_BFP__. Any program that does
    anything with floating point values other than comparing floating point constants for relative order might have greatly different output
    depending upon whether an implementation conforms to IEC_60599, or takes maximal advantage of the freedom the standard gives them when __STDC_IEC_60559_BFP__ is not pre#defined. You can write code that
    doesn't care whether LDBL_MAX - LDBL_MIN > LDBL_MIN - LDBL_MAX is true
    or false, but only by, for all practical purposes, making no meaningful
    use of floating point operations.

    6.4.4.2p4 identifies what is usually three different possible values for
    each floating point constant (four if the constant describes a value
    exactly half-way between two consecutive representable values, but only
    two if it describes a value larger than DBL_MAX or smaller than -DBL_MAX
    on a platform that doesn't support infinities), and leaves it
    unspecified which one of those values is chosen.

    The program can deal with that in order to get the same behavior in
    each case, so that it could be strictly conforming.

    Agreed - and if your program were so written, you'd have no cause to
    complain about which of the three was chosen. But you are complaining
    about the possibility that a different one might be chosen than the one
    you think should be.

    ... However, if the
    behavior is undefined (assumed as a consequence of the failed
    constraint), there is *nothing* that one can do.

    Yes, but nowhere does the standard specify that violating a constraint
    does, in itself, render the behavior undefined. Most constraint
    violations do render the behavior undefined "by omission of any explicit definition of the behavior", but not this one. You might not like the definition that 6.4.4.2p4 provides, but it does provide one.

    That said, since the floating-point accuracy is not specified, can be extremely low and is not even checkable by the program (so that there
    is no possible fallback in case of low accuracy), there is not much
    one can do with floating point.

    ??? You can check for __STDC_IEC_60559_BFP__; if it's defined, then
    pretty much the highest possible accuracy is required.
    Are you worried about __STDC_IEC_60559_BFP__ being falsely pre#defined? Accuracy lower that required by IEC 60559 is pretty easily detected,
    unless an implementation takes truly heroic efforts to cover it up. To
    render the inaccuracy uncheckable would require almost as much hard work
    and ingenuity as producing the right result.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Mon Nov 15 23:39:59 2021
    From Newsgroup: comp.std.c

    In article <86v90t8l6j.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose again we have an implementation that does not support
    infinities and has a range of double and long double up to about
    ten to the 99999. Question one: as far as the C standard is
    concerned, is the treatment of this .c file

    double way_too_big = 1.e1000000;

    and of this .c file

    #include <math.h>

    double way_too_big = INFINITY;

    the same in the two cases?

    IMHO, this is undefined behavior in both cases, due to the
    unsatisfied constraint. So, yes.

    Question two: does the C standard require that at least one
    diagnostic be issued for each of the above .c files?

    Yes: The constraint is unsatisfied in both cases, so at least one
    diagnostic is required in both cases.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Nov 15 20:00:53 2021
    From Newsgroup: comp.std.c

    On 11/15/21 6:39 PM, Vincent Lefevre wrote:
    In article <86v90t8l6j.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose again we have an implementation that does not support
    infinities and has a range of double and long double up to about
    ten to the 99999. Question one: as far as the C standard is
    concerned, is the treatment of this .c file

    double way_too_big = 1.e1000000;

    and of this .c file

    #include <math.h>

    double way_too_big = INFINITY;

    the same in the two cases?

    IMHO, this is undefined behavior in both cases, due to the
    unsatisfied constraint. So, yes.

    So, of the three ways used by the standard to indicate that the behavior
    is undefined, which one was used in this case?

    "If a "shall" or "shall not" requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this document by the words "undefined behavior" or by the omission of any explicit definition of
    behavior. There is no difference in emphasis among these three; they all describe "behavior that is undefined"." (4p2).

    If it's a "shall" or an explicit "undefined behavior", please identify
    the clause containing those words.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Tue Nov 16 01:17:23 2021
    From Newsgroup: comp.std.c

    In article <smuc7i$6hq$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/15/21 4:18 AM, Vincent Lefevre wrote:
    In article <smn6d8$c92$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/12/21 6:17 PM, Vincent Lefevre wrote:
    ...
    The issue is more related to (strictly) conforming programs.

    It can't be. Strictly conforming programs are prohibited from having
    output that depends upon behavior that the standard leaves unspecified.

    This is not how I interpret the standard.

    I don't see how there's room for interpretation: "A strictly conforming program ... shall not produce output dependent on any unspecified ... behavior, ..." (4p6).

    I'm not sure what you intended to mean, but IMHO, the "It can't be."
    is wrong based on the unsatisfied constraint and definition 3.8 of
    "constraint" (but this should really be clarified).

    [...]
    ... However, if the
    behavior is undefined (assumed as a consequence of the failed
    constraint), there is *nothing* that one can do.

    Yes, but nowhere does the standard specify that violating a constraint
    does, in itself, render the behavior undefined. Most constraint
    violations do render the behavior undefined "by omission of any explicit definition of the behavior", but not this one. You might not like the definition that 6.4.4.2p4 provides, but it does provide one.

    But the fact that a restriction is not fulfilled (definition 3.8)
    is what matters.

    Another example:

    6.5.2.2 Function calls

    Constraints
    [...]
    2 If the expression that denotes the called function has a type that
    includes a prototype, the number of arguments shall agree with the
    number of parameters. [...]

    IMHO, if one provides an additional argument, this is undefined
    behavior, even though the semantics describe the behavior in this
    case.

    Another one:

    6.5.3.3 Unary arithmetic operators

    Constraints
    [...]
    1 The operand of the unary + or - operator shall have arithmetic type
    [...]

    Even though the semantics for +X still makes sense for any object type,
    IMHO, this is undefined behavior if X does not have an arithmetic type.

    It happens that the compilers reject such code. But what if they
    chose not to reject it? Would they be forced to use the defined
    semantics or be allowed to have some other behavior as an extension?
    I would say the latter.

    The example 6.5.16.1p6 regards a constraint violation as invalid code.

    That said, since the floating-point accuracy is not specified, can be extremely low and is not even checkable by the program (so that there
    is no possible fallback in case of low accuracy), there is not much
    one can do with floating point.

    ??? You can check for __STDC_IEC_60559_BFP__; if it's defined, then
    pretty much the highest possible accuracy is required.

    Indeed, well, almost I think. One should also check that
    FLT_EVAL_METHOD is either 0 or 1. Otherwise the accuracy
    becomes unknown.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Tue Nov 16 01:28:26 2021
    From Newsgroup: comp.std.c

    In article <smuvs5$6qh$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/15/21 6:39 PM, Vincent Lefevre wrote:
    In article <86v90t8l6j.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose again we have an implementation that does not support
    infinities and has a range of double and long double up to about
    ten to the 99999. Question one: as far as the C standard is
    concerned, is the treatment of this .c file

    double way_too_big = 1.e1000000;

    and of this .c file

    #include <math.h>

    double way_too_big = INFINITY;

    the same in the two cases?

    IMHO, this is undefined behavior in both cases, due to the
    unsatisfied constraint. So, yes.

    So, of the three ways used by the standard to indicate that the behavior
    is undefined, which one was used in this case?

    "If a "shall" or "shall not" requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this document by the words "undefined behavior" or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe "behavior that is undefined"." (4p2).

    Omission of any explicit definition of behavior. There is a constraint (restriction) that is not satisfied. Thus the code becomes invalid and
    nothing gets defined as a consequence. This is like, in math, applying
    a theorem where the hypotheses are not satisfied.

    I would expect the implementation to reject the code, or accept it
    in a way unspecified by the standard (but the implementation could
    document what happens, as an extension).
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Tue Nov 16 01:57:03 2021
    From Newsgroup: comp.std.c

    In article <20211116011941$1337@zira.vinc17.org>,
    Vincent Lefevre <vincent-news@vinc17.net> wrote:

    I would expect the implementation to reject the code, or accept it
    in a way unspecified by the standard (but the implementation could
    document what happens, as an extension).

    As a useful example, I would say that an implementation that doesn't
    support infinities but has NaNs would be allow to track out-of-range
    values to try to emulate infinities (e.g. for safety reasons).

    For instance,

    INFINITY - INFINITY

    could yield NaN instead of 0.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Derek Jones@derek@NOSPAM-knosof.co.uk to comp.std.c on Tue Nov 16 11:32:54 2021
    From Newsgroup: comp.std.c

    All,

    I don't see how there's room for interpretation: "A strictly conforming program ... shall not produce output dependent on any unspecified ... behavior, ..." (4p6).

    Indeed.

    Now the order of evaluation of binary operators is
    unspecified. But this does not mean that all programs containing
    at least one binary operator is not strictly conforming.

    For instance, the order of evaluation of the two
    operands in the following expression-statement is unspecified.
    But unless they are volatile qualified the output does
    not depend on the unspecified behavior:

    x+y;

    But in:

    a[printf("Hello")]+a[printf(" World")];

    the output does depend on the order of evaluation,
    and a program containing this code is not strictly conforming.

    #ifdef __STDC_IEC_559__

    while the value of __STDC_IEC_559__ is not specified in the standard.

    The output of a strictly conforming program does not depend on the implementation used.

    Since the value of __STDC_IEC_559__ depends on the implementation,
    its use can produce a program that is not strictly conforming.

    ps. This whole discussion has been very interesting.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Tue Nov 16 09:52:43 2021
    From Newsgroup: comp.std.c

    On 11/15/21 8:28 PM, Vincent Lefevre wrote:
    In article <smuvs5$6qh$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/15/21 6:39 PM, Vincent Lefevre wrote:
    In article <86v90t8l6j.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Suppose again we have an implementation that does not support
    infinities and has a range of double and long double up to about
    ten to the 99999. Question one: as far as the C standard is
    concerned, is the treatment of this .c file

    double way_too_big = 1.e1000000;

    and of this .c file

    #include <math.h>

    double way_too_big = INFINITY;

    the same in the two cases?

    IMHO, this is undefined behavior in both cases, due to the
    unsatisfied constraint. So, yes.

    So, of the three ways used by the standard to indicate that the behavior
    is undefined, which one was used in this case?

    "If a "shall" or "shall not" requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined.
    Undefined behavior is otherwise indicated in this document by the words
    "undefined behavior" or by the omission of any explicit definition of
    behavior. There is no difference in emphasis among these three; they all
    describe "behavior that is undefined"." (4p2).

    Omission of any explicit definition of behavior.

    The fact that a constraint is violated does not erase the definition
    provided by 6.4.4.2p4, or render it any less applicable.

    ... There is a constraint
    (restriction) that is not satisfied.

    Agreed.

    ... Thus the code becomes invalid and
    nothing gets defined as a consequence.

    This is, I presume, what makes you think that 6.4.4.2p4 is effectively
    erased?

    The standard says nothing to that effect. The only meaningful thing it
    says is that a diagnostic is required (5.1.1.3p1). I do not consider the standard's definition of "constraint" to be meaningful: "restriction,
    either syntactic or semantic, by which the exposition of language
    elements is to be interpreted" (3.8). What that sentence means,if
    anything, is not at all clear, but one thing is clear - it says nothing
    about what should happen if the restriction is violated. 5.1.1.3p1 is
    the only clause that says anything about that issue.
    Note: the requirement specified in 5.1.1.3p1 would also be erased, if a constraint violation is considered to effectively erase unspecified
    parts of the rest of the standard. Surely you don't claim that 3.8
    specifies which parts get erased?

    I would expect the implementation to reject the code, or accept it
    in a way unspecified by the standard (but the implementation could
    document what happens, as an extension).

    While an implementation is not required to accept and translate such
    code (that's only required for the "one program"), if it does translate
    such code, then (in the absence of any other problems) the resulting
    executable must produce the same observable behavior as if such a
    constant was given a value of either DBL_MAX or nextdown(DBL_MAX) - any
    other result fails to meet the requirements of 6.4.4.2p4.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Tue Nov 16 10:29:19 2021
    From Newsgroup: comp.std.c

    On 11/15/21 8:17 PM, Vincent Lefevre wrote:
    In article <smuc7i$6hq$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/15/21 4:18 AM, Vincent Lefevre wrote:
    In article <smn6d8$c92$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    On 11/12/21 6:17 PM, Vincent Lefevre wrote:
    ...
    The issue is more related to (strictly) conforming programs.

    It can't be. Strictly conforming programs are prohibited from having
    output that depends upon behavior that the standard leaves unspecified. >>>
    This is not how I interpret the standard.

    I don't see how there's room for interpretation: "A strictly conforming
    program ... shall not produce output dependent on any unspecified ...
    behavior, ..." (4p6).

    I'm not sure what you intended to mean, but IMHO, the "It can't be."
    is wrong based on the unsatisfied constraint and definition 3.8 of "constraint" (but this should really be clarified).

    I said that this issue cannot be "related to (strictly) conforming
    programs". This issue can't come up in strictly conforming programs, nor
    does the way in which this issue might be resolved have any effect on
    whether a program qualifies as strictly conforming. Not only is there inherently a constraint violation, but the value of such a constant
    would be unspecified even if there were no constraint, and the only
    reason to care about which value is selected by the implementation would
    be if the value affects the observable behavior of your program, which
    would mean that it's not strictly conforming.

    ...
    That said, since the floating-point accuracy is not specified, can be
    extremely low and is not even checkable by the program (so that there
    is no possible fallback in case of low accuracy), there is not much
    one can do with floating point.

    ??? You can check for __STDC_IEC_60559_BFP__; if it's defined, then
    pretty much the highest possible accuracy is required.

    Indeed, well, almost I think. One should also check that
    FLT_EVAL_METHOD is either 0 or 1. Otherwise the accuracy
    becomes unknown.

    A value of 2 tells you that the implementation will evaluate "all
    operations and constants to the range and precision of the long double
    type", which is pretty specific about what the accuracy is. It has
    precisely the same accuracy that it would have had on an otherwise
    identical implementation where FLT_EVAL_METHOD == 0, if you explicitly converted all double operands to long double, and then converted the
    final result back to double. Would you consider the accuracy of such
    code to be unknown?

    A value of -1 leaves some uncertainty about the accuracy. However, the evaluation format is allowed to have range or precision that is greater
    than that of the expression's type. The accuracy of such a type might be greater than that of the expression's type, but it's not allowed to be
    worse. That's far less uncertainty than what is allowed if __STDC_IEC_60559_BFP__ is NOT pre#defined by the implementation.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Tue Nov 16 10:35:32 2021
    From Newsgroup: comp.std.c

    On 11/16/21 6:32 AM, Derek Jones wrote:
    All,

    I don't see how there's room for interpretation: "A strictly conforming
    program ... shall not produce output dependent on any unspecified ...
    behavior, ..." (4p6).

    Indeed.

    Now the order of evaluation of binary operators is
    unspecified. But this does not mean that all programs containing
    at least one binary operator is not strictly conforming.

    For instance, the order of evaluation of the two
    operands in the following expression-statement is unspecified.
    But unless they are volatile qualified the output does
    not depend on the unspecified behavior:

    x+y;

    But in:

    a[printf("Hello")]+a[printf(" World")];

    the output does depend on the order of evaluation,
    and a program containing this code is not strictly conforming.

    #ifdef __STDC_IEC_559__

    while the value of __STDC_IEC_559__ is not specified in the standard.

    The output of a strictly conforming program does not depend on the implementation used.

    Since the value of __STDC_IEC_559__ depends on the implementation,
    its use can produce a program that is not strictly conforming.

    Agreed. But it also can produce program that is strictly conforming,
    just like your example of x+y above.

    However, given how horrible the accuracy requirements are when __STDC_IEC_60559_BFP__ is not pre#defined, the only way that a program
    could make any meaningful use of floating point and still be strictly conforming is if it limits such use to comparing floating point
    constants for relative order - and even then, that's only true if the
    constants are sufficiently far apart in value to guarantee the result of
    that comparison.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Tue Nov 16 19:00:02 2021
    From Newsgroup: comp.std.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:
    On 11/15/21 8:28 PM, Vincent Lefevre wrote:
    In article <smuvs5$6qh$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:
    [...]
    "If a "shall" or "shall not" requirement that appears outside of a
    constraint or runtime-constraint is violated, the behavior is undefined. >>> Undefined behavior is otherwise indicated in this document by the words
    "undefined behavior" or by the omission of any explicit definition of
    behavior. There is no difference in emphasis among these three; they all >>> describe "behavior that is undefined"." (4p2).

    Omission of any explicit definition of behavior.

    The fact that a constraint is violated does not erase the definition
    provided by 6.4.4.2p4, or render it any less applicable.

    I suggest that that may be an open question.

    ... There is a constraint
    (restriction) that is not satisfied.

    Agreed.

    ... Thus the code becomes invalid and
    nothing gets defined as a consequence.

    This is, I presume, what makes you think that 6.4.4.2p4 is effectively erased?

    The standard says nothing to that effect. The only meaningful thing it
    says is that a diagnostic is required (5.1.1.3p1). I do not consider the standard's definition of "constraint" to be meaningful: "restriction,
    either syntactic or semantic, by which the exposition of language
    elements is to be interpreted" (3.8). What that sentence means,if
    anything, is not at all clear, but one thing is clear - it says nothing about what should happen if the restriction is violated. 5.1.1.3p1 is
    the only clause that says anything about that issue.
    Note: the requirement specified in 5.1.1.3p1 would also be erased, if a constraint violation is considered to effectively erase unspecified
    parts of the rest of the standard. Surely you don't claim that 3.8
    specifies which parts get erased?

    The standard's definition of "constraint" is uncomfortably vague -- but
    that doesn't mean I'm comfortable ignoring it.

    Given the definition of a "constraint" as a "restriction, either
    syntactic or semantic, by which the exposition of language elements is
    to be interpreted", it seems to me to be at least plausible that when a constraint is violated, the "exposition of language elements" cannot be interpreted.

    The implication would be that any program that violates a constraint has undefined behavior (assuming it survives translation). And yes, I'm
    proposing that violating any single constraint makes most of the rest of
    the standard moot.

    I'm not saying that this is the only way to interpret that wording.
    It's vague enough to permit a number of reasonable readings. But I
    don't think we can just ignore it.

    I'd like to see a future standard settle this one way or the other.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Thomas Koenig@tkoenig@netcologne.de to comp.std.c on Thu Dec 2 22:14:43 2021
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> schrieb:

    I think it's a tricky question. I think the language would be cleaner
    if the standard explicitly stated that violating a constraint always
    results in undefined behavior -- or if it explicitly stated that it
    doesn't. (The former is my personal preference.)

    Other language standards use different concepts, and maybe the C
    standard could be improved by adopting them.

    The Fortran standard, for example, has numbered constraints and
    general prohibitions or requirements, denoted by "shall not"
    and "shall", respectively.

    If a numbered constraint is violated, the compiler has to detect
    and report this. If it fails to do so, it's a compiler bug.
    This is usually done for things that can easily be checked
    at compile time.

    If a "shall" or "shall not" directive is violated, then this is
    a bug in the program, and quite specifically the programmer's fault.
    A compiler may or may not report an error, this is then mostly
    a quality of implementation issue, and often a tradeoff with
    execution speed.

    It's cleaner than what C has, IMHO.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Wed Dec 8 10:09:03 2021
    From Newsgroup: comp.std.c

    Sorry for the late reply (not much time ATM).

    In article <sn0iog$gna$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    [...]
    ??? You can check for __STDC_IEC_60559_BFP__; if it's defined, then
    pretty much the highest possible accuracy is required.

    Indeed, well, almost I think. One should also check that
    FLT_EVAL_METHOD is either 0 or 1. Otherwise the accuracy
    becomes unknown.

    A value of 2 tells you that the implementation will evaluate "all
    operations and constants to the range and precision of the long double
    type", which is pretty specific about what the accuracy is. It has
    precisely the same accuracy that it would have had on an otherwise
    identical implementation where FLT_EVAL_METHOD == 0, if you explicitly converted all double operands to long double, and then converted the
    final result back to double. Would you consider the accuracy of such
    code to be unknown?

    Simply because the accuracy of long double is unknown and may be lower
    than the one of float. Annex F says for long double:

    F.2 Types
    [...]
    The long double type matches an IEC 60559 extended format,363) else
    a non-IEC 60559 extended format, else the IEC 60559 double format.

    Any non-IEC 60559 extended format used for the long double type
    shall have more precision than IEC 60559 double and at least the
    range of IEC 60559 double.364) The value of FLT_ROUNDS applies to
    all IEC 60559 types supported by the implementation, but need not
    apply to non-IEC 60559 types.

    Just consider a non-IEC 60559 extended format. Note that the standard
    says that it shall have more *precision* than IEC 60559 double, but
    does not say anything about accuracy.

    A value of -1 leaves some uncertainty about the accuracy. However, the evaluation format is allowed to have range or precision that is greater
    than that of the expression's type. The accuracy of such a type might be greater than that of the expression's type, but it's not allowed to be
    worse.

    I don't see where the standard says that it's not allowed to be worse.
    One just has:

    5.2.4.2.2 Characteristics of floating types <float.h>
    [...]
    6 The accuracy of the floating-point operations (+, -, *, /) and
    of the library functions in <math.h> and <complex.h> that return
    floating-point results is implementation-defined, as is the
    accuracy of the conversion between floating-point internal
    representations and string representations performed by the
    library functions in <stdio.h>, <stdlib.h>, and <wchar.h>. The
    implementation may state that the accuracy is unknown.
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Vincent Lefevre@vincent-news@vinc17.net to comp.std.c on Wed Dec 8 10:56:07 2021
    From Newsgroup: comp.std.c

    In article <87pmqzv64t.fsf@nosuchdomain.example.com>,
    Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:

    The standard's definition of "constraint" is uncomfortably vague -- but
    that doesn't mean I'm comfortable ignoring it.

    Given the definition of a "constraint" as a "restriction, either
    syntactic or semantic, by which the exposition of language elements is
    to be interpreted", it seems to me to be at least plausible that when a constraint is violated, the "exposition of language elements" cannot be interpreted.

    DR 261[*] goes in this way, IMHO. Here, the constraint on constant
    expressions is used to determine whether an expression may be
    regarded as a constant expression or not. Thus, if the constraint
    is not matched, then the expression is not a constant expression,
    and what falls under this constraint does not apply.

    Note that the Committee Response says "valid interpretation of the
    code", i.e. if the requirements of a constraint are not met, then
    there is no "valid interpretation of the code".

    [*] http://www.open-std.org/JTC1/SC22/WG14/www/docs/dr_261.htm
    --
    Vincent Lef|?vre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
    100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
    Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Fri Dec 17 21:00:20 2021
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    [...]

    Shouldn't the standard by changed to make INFINITY conditionally
    defined (if not required to expand to a true infinity)? [...]

    To me it seems better for INFINITY to be defined as it is rather
    than being conditionally defined. If what is needed is really an
    infinite value, just write INFINITY and the code either works or
    compiling it gives a diagnostic. If what is needed is just a very
    large value, write HUGE_VAL (or HUGE_VALF or HUGE_VALL, depending)
    and the code works whether infinite floating-point values are
    supported or not. If it's important that infinite values be
    supported but we don't want to risk a compilation failure, use
    HUGE_VAL combined with an assertion

    assert( HUGE_VAL == HUGE_VAL/2 );

    Alternatively, use INFINITY only in one small .c file, and give
    other sources a make dependency for a successful compilation
    (with of course a -pedantic-errors option) of that .c file. I
    don't see that having INFINITY be conditionally defined buys
    anything, except to more or less force use of #if/#else/#endif
    blocks in the preprocessor. I don't mind using the preprocessor
    when there is a good reason to do so, but here I don't see one.

    I don't see how that's better than conditionally defining INFINITY.

    It's better only in the sense that it works with the existing
    C standards, and may give acceptable results in practice.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Fri Dec 17 21:02:40 2021
    From Newsgroup: comp.std.c

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86sfxbpm9d.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    To me it seems better for INFINITY to be defined as it is rather
    than being conditionally defined. If what is needed is really an
    infinite value, just write INFINITY and the code either works or
    compiling it gives a diagnostic.

    diagnostic and undefined behavior. [...]

    Not everyone agrees with this conclusion.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 3 11:55:53 2022
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 10/9/21 4:17 PM, Vincent Lefevre wrote:

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint. A
    diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    "For decimal floating constants, and also for hexadecimal floating
    constants when FLT_RADIX is not a power of 2, the result is either
    the nearest representable value, or the larger or smaller
    representable value immediately adjacent to the nearest
    representable value, chosen in an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2,
    the result is correctly rounded." (6.4.4.2p3)

    In the case of overflow, for a type that cannot represent infinity,
    there is only one "nearest representable value", which is DBL_MAX.

    But does that apply when a constraint is violated?

    6.4.4p2, a constraint, says:

    Each constant shall have a type and the value of a constant shall be
    in the range of representable values for its type.

    A "constraint", aside from triggering a required diagnostic, is a "restriction, either syntactic or semantic, by which the exposition
    of language elements is to be interpreted",

    Note that the C standard uses the word "constraint" in at least
    two different senses. One is the sense of the definition given
    above. Another is the sense of any stated restriction in a
    'Constraints' section (and nothing else). AFAICT (I have not
    tried to do a thorough search) the second sense never includes
    a syntactic restriction.

    which is IMHO a bit vague.

    Certainly it is at least ambiguous and subjective.

    My mental model is that if a program violates a constraint and the implementation still accepts it (i.e., the required diagnostic is a
    non-fatal warning) the program's behavior is undefined -- but the
    standard doesn't say that. Of course if the implementation rejects
    the program, it has no behavior.

    This paragraph uses the word "behavior" in two different senses.
    The C standard uses "behavior" to mean behavior in the abstract
    machine, or sometimes to mean a description of behavior in the
    abstract machine. In this sense the program has behavior whether
    it is rejected or not: if it has defined behavior, then that is
    the behavior, and if it has undefined behavior then the behavior is
    "undefined behavior". The sentence "if the implementation rejects
    the program, it has no behavior" uses the word behavior in the
    sense of "run-time behavior", which is a different sense than how
    "behavior" is used in the C standard. A C program has behavior,
    in the sense that the C standard uses the term, whether it is
    accepted or not, or even whether it is compiled or not.

    For what it's worth, given this:

    double too_big = 1e1000;

    gcc, clang, and tcc all print a warning and set too_big to infinity.
    That's obviously valid if the behavior is undefined. I think it's
    also valid if the behavior is defined; the nearest representable
    value is DBL_MAX, and the larger representable value immediately
    adjacent to DBL_MAX is infinity.

    Since the implementations listed all have infinities, the value of
    the constant is in the range of representable values for its type,
    so no constraint is violated, and the behavior is always defined.

    It doesn't seem to me to be particularly useful to say that a
    program can be rejected, but its behavior is defined if the
    implementation chooses not to reject it.

    Such cases occur often. Consider an implementation where SIZE_MAX
    is 4294967295. If translating a program that has a declaration

    static char blah[3221225472];

    then the implementation is free to reject it, but the behavior is
    defined whether the implementation accepts the program or rejects
    it. Behavior is a property of the program, not the implementation.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 3 12:03:53 2022
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [ is a constraint violation always undefined behavior? ]

    [...] one possible interpretation of the phrase "a restriction
    ... by which the exposition of language elements is to be
    interpreted" could be that if the constraint is violated, there
    is no meaningful interpretation. Or to put it another way,
    that the semantic description applies only if all constraints
    are satisfied.

    I've searched for the word "constraint" in the C89 and C99
    Rationale documents. They were not helpful.

    I am admittedly trying to read into the standard what I think
    it *should* say. A rule that constraint violations cause
    undefined behavior would, if nothing else, make the standard a
    bit simpler.

    Note that constraint violations are not undefined behavior in a
    strict literal reading of the definition. Undefined behavior
    means there are no restrictions as to what an implemenation may
    do, but constraint violations require the implementation to
    issue at least one diagnostic, which is not the same as "no
    restrictions".
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 3 12:48:56 2022
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <861r3pbbwh.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Vincent Lefevre <vincent-news@vinc17.net> writes:

    In article <86wnmoov7c.fsf@linuxsc.com>,
    Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    What occurs is defined behavior and (for implementations that do
    not have the needed value for infinity) violates a constraint.
    A diagnostic must be produced.

    If this is defined behavior, where is the result of an overflow
    defined by the standard? (I can see only 7.12.1p5, but this is
    for math functions; here, this is a constant that overflows.)

    I'm wondering if you have resolved your original uncertainty
    about the behavior of INFINITY in an implementation that does
    not support infinities?

    I suspect that by saying "overflow", the standard actually meant that
    the result is not in the range of representable values. This is the
    only way the footnote "In this case, using INFINITY will violate the
    constraint in 6.4.4 and thus require a diagnostic." can make sense
    (the constraint in 6.4.4 is about the range, not overflow). But IMHO,
    the failing constraint makes the behavior undefined, actually makes
    the program erroneous.

    Suppose we have an implementation that does not support
    infinities, a range of double and long double up to about ten to
    the 99999, and ask it to translate the following .c file

    double way_too_big = 1.e1000000;

    This constant value violates the constraint in 6.4.4. Do you
    think this .c file (and any program it is part of) has undefined
    behavior? If so, do you think any constraint violation implies
    undefined behavior, or just some of them?

    (Jumping in though the question was addressed to someone else.)

    I think it's a tricky question. I think the language would be
    cleaner if the standard explicitly stated that violating a
    constraint always results in undefined behavior -- or if it
    explicitly stated that it doesn't. (The former is my personal
    preference.)

    Here are some statements that I believe are true:

    1. The C standard has no statement that says directly that
    constraint violations result in undefined behavior.

    2. The definition of "constraint" in the C standard is ambiguous
    and does not have a single objective meaning.

    3. There are no indications (at least none that I am aware of) in
    the C standard, or any other official writing of the WG14 group,
    of what meaning is intended by the ISO C group for the question
    in question.

    Clearly a compiler is allowed (but not required) to reject a program
    that violates a constraint. If it does so, there is no behavior.

    Same comment as I gave in my other recent posting - programs have
    behavior, in the sense used in the C standard, regardless of
    whether any implementation accepts or rejects them. (The behavior
    may be "undefined behavior".)

    So the question is whether the behavior is undefined if the
    implementation chooses not to reject it. (I personally don't see a
    whole lot of value in defining the behavior of code that could have
    been rejected outright.

    Again, there are lots of constructs that clearly have defined
    behavior, and yet implementations can choose to reject them.

    I'm also not a big fan of the fact that
    required diagnostics don't have to be fatal, but that's not likely
    to change.)

    IMO this view is short sighted. Implementations are allowed to
    define extensions as long as they are documented and don't change
    the meaning of any strictly conforming program. If any required
    diagnostic has to be fatal, that would disallow all kinds of
    useful extensions.

    Speaking just for myself, I would like implementations to provide
    an option under which any required diagnostic would result in the
    program being rejected. But only an option, and in any case that
    is in the area of QOI issues, which the C standard has explicitly
    chosen not to address.

    [analysis of possible interpretations of the above code fragment]

    My question was only about whether there is undefined behavior.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 3 12:56:19 2022
    From Newsgroup: comp.std.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On 11/15/21 8:28 PM, Vincent Lefevre wrote:

    In article <smuvs5$6qh$1@dont-email.me>,
    James Kuyper <jameskuyper@alumni.caltech.edu> wrote:

    [...]

    "If a "shall" or "shall not" requirement that appears outside of
    a constraint or runtime-constraint is violated, the behavior is
    undefined. Undefined behavior is otherwise indicated in this
    document by the words "undefined behavior" or by the omission of
    any explicit definition of behavior. There is no difference in
    emphasis among these three; they all describe "behavior that is
    undefined"." (4p2).

    Omission of any explicit definition of behavior.

    The fact that a constraint is violated does not erase the
    definition provided by 6.4.4.2p4, or render it any less applicable.

    I suggest that that may be an open question.

    ... There is a constraint
    (restriction) that is not satisfied.

    Agreed.

    ... Thus the code becomes invalid and
    nothing gets defined as a consequence.

    This is, I presume, what makes you think that 6.4.4.2p4 is
    effectively erased?

    The standard says nothing to that effect. The only meaningful
    thing it says is that a diagnostic is required (5.1.1.3p1). I do
    not consider the standard's definition of "constraint" to be
    meaningful: "restriction, either syntactic or semantic, by which
    the exposition of language elements is to be interpreted" (3.8).

    (Incidental remark: the problem is not that the definition of
    constraint is meaningless; the problem is that the meaning
    of the definition is ambiguous and subjective (but that's not
    the same as meaningless (or "not meaningful")).)

    What that sentence means,if anything, is not at all clear, but one
    thing is clear - it says nothing about what should happen if the
    restriction is violated. 5.1.1.3p1 is the only clause that says
    anything about that issue. Note: the requirement specified in
    5.1.1.3p1 would also be erased, if a constraint violation is
    considered to effectively erase unspecified parts of the rest of
    the standard. Surely you don't claim that 3.8 specifies which
    parts get erased?

    The standard's definition of "constraint" is uncomfortably vague
    -- but that doesn't mean I'm comfortable ignoring it.

    Given the definition of a "constraint" as a "restriction, either
    syntactic or semantic, by which the exposition of language
    elements is to be interpreted", it seems to me to be at least
    plausible that when a constraint is violated, the "exposition of
    language elements" cannot be interpreted.

    The implication would be that any program that violates a constraint
    has undefined behavior (assuming it survives translation). And yes,
    I'm proposing that violating any single constraint makes most of the
    rest of the standard moot.

    I'm not saying that this is the only way to interpret that wording.
    It's vague enough to permit a number of reasonable readings. [...]

    So you're saying that the meaning of the definition of constraint
    is to some extent subjective, ie, reader dependent?
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Richard Damon@Richard@Damon-Family.org to comp.std.c on Mon Jan 3 16:45:32 2022
    From Newsgroup: comp.std.c

    On 1/3/22 3:03 PM, Tim Rentsch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [ is a constraint violation always undefined behavior? ]

    [...] one possible interpretation of the phrase "a restriction
    ... by which the exposition of language elements is to be
    interpreted" could be that if the constraint is violated, there
    is no meaningful interpretation. Or to put it another way,
    that the semantic description applies only if all constraints
    are satisfied.

    I've searched for the word "constraint" in the C89 and C99
    Rationale documents. They were not helpful.

    I am admittedly trying to read into the standard what I think
    it *should* say. A rule that constraint violations cause
    undefined behavior would, if nothing else, make the standard a
    bit simpler.

    Note that constraint violations are not undefined behavior in a
    strict literal reading of the definition. Undefined behavior
    means there are no restrictions as to what an implemenation may
    do, but constraint violations require the implementation to
    issue at least one diagnostic, which is not the same as "no
    restrictions".

    Although, after issuing that one diagnostic, if the implementation
    continues and generates an output program, and that program is run, then
    its behavior is explicitly defined to be undefined behavior.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.std.c on Mon Jan 3 14:36:08 2022
    From Newsgroup: comp.std.c

    Richard Damon <Richard@Damon-Family.org> writes:
    On 1/3/22 3:03 PM, Tim Rentsch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    [ is a constraint violation always undefined behavior? ]

    [...] one possible interpretation of the phrase "a restriction
    ... by which the exposition of language elements is to be
    interpreted" could be that if the constraint is violated, there
    is no meaningful interpretation. Or to put it another way,
    that the semantic description applies only if all constraints
    are satisfied.

    I've searched for the word "constraint" in the C89 and C99
    Rationale documents. They were not helpful.

    I am admittedly trying to read into the standard what I think
    it *should* say. A rule that constraint violations cause
    undefined behavior would, if nothing else, make the standard a
    bit simpler.
    Note that constraint violations are not undefined behavior in a
    strict literal reading of the definition. Undefined behavior
    means there are no restrictions as to what an implemenation may
    do, but constraint violations require the implementation to
    issue at least one diagnostic, which is not the same as "no
    restrictions".

    Although, after issuing that one diagnostic, if the implementation
    continues and generates an output program, and that program is run,
    then its behavior is explicitly defined to be undefined behavior.

    Explicitly? Where does the standard say that.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Mon Jan 3 22:45:27 2022
    From Newsgroup: comp.std.c

    On Monday, January 3, 2022 at 3:56:22 PM UTC-5, Tim Rentsch wrote:
    Keith Thompson <Keith.S.T...@gmail.com> writes:

    James Kuyper <james...@alumni.caltech.edu> writes:
    ...
    The standard says nothing to that effect. The only meaningful
    thing it says is that a diagnostic is required (5.1.1.3p1). I do
    not consider the standard's definition of "constraint" to be
    meaningful: "restriction, either syntactic or semantic, by which
    the exposition of language elements is to be interpreted" (3.8).
    ...
    The standard's definition of "constraint" is uncomfortably vague
    -- but that doesn't mean I'm comfortable ignoring it.

    Given the definition of a "constraint" as a "restriction, either
    syntactic or semantic, by which the exposition of language
    elements is to be interpreted", it seems to me to be at least
    plausible that when a constraint is violated, the "exposition of
    language elements" cannot be interpreted.
    ...
    I'm not saying that this is the only way to interpret that wording.
    It's vague enough to permit a number of reasonable readings. [...]

    So you're saying that the meaning of the definition of constraint
    is to some extent subjective, ie, reader dependent?

    As I said above, it seems to me to be so poorly worded that it's not
    clear to me that it has any meaning, much less one that is subjective.
    Since other people disagree with me on that point, there would
    appear to be some subjectivity at play in that judgment, but after
    reading their arguments, I remain at a loss as to how they can
    interpret that phrase as being meaningful.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From James Kuyper@jameskuyper@alumni.caltech.edu to comp.std.c on Tue Jan 4 02:10:02 2022
    From Newsgroup: comp.std.c

    On 1/3/22 4:45 PM, Richard Damon wrote:
    On 1/3/22 3:03 PM, Tim Rentsch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [ is a constraint violation always undefined behavior? ]

    [...] one possible interpretation of the phrase "a restriction
    ... by which the exposition of language elements is to be
    interpreted" could be that if the constraint is violated, there
    is no meaningful interpretation. Or to put it another way,
    that the semantic description applies only if all constraints
    are satisfied.

    I've searched for the word "constraint" in the C89 and C99
    Rationale documents. They were not helpful.

    I am admittedly trying to read into the standard what I think
    it *should* say. A rule that constraint violations cause
    undefined behavior would, if nothing else, make the standard a
    bit simpler.

    Note that constraint violations are not undefined behavior in a
    strict literal reading of the definition. Undefined behavior
    means there are no restrictions as to what an implemenation may
    do, but constraint violations require the implementation to
    issue at least one diagnostic, which is not the same as "no
    restrictions".

    Although, after issuing that one diagnostic, if the implementation
    continues and generates an output program, and that program is run, then
    its behavior is explicitly defined to be undefined behavior.

    Where? The standard specifies that there are only two explicit ways
    whereby undefined behaviro is indicated: a "shall" or "shall not" that
    appears outside of a constraint or runtime-constraint, or the use of the
    words "undefined behavior". In which clause to is there a relevant use
    of "shall", "shall not" or "undefined behavior"?

    There's one implicit method, and that's "by the omission of any explicit definition of behavior", but I've argued that there is an explicit
    definition of the behavior that applies in this case. In the absence of
    a general statement that "a constraint shall be satisfied" or "a
    constraint shall not be violated" or "violation of a constraint has
    undefined behavior", or some other corresponding wording that qualifies
    as explicitly making the behavior undefined, the existence of that
    explicit definition of behavior is not erased by the constraint violation.
    If a constraint violation does not render an explicit definition of the behavior inapplicable, the only consequences of that violation are a
    mandatory diagnostic and permission to reject the program. Should an implementation choose not to reject the program, and should the
    resulting executable be run, the behavior of that program is still
    constrained by all of the requirements of the standard.
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 17 05:35:26 2022
    From Newsgroup: comp.std.c

    James Kuyper <jameskuyper@alumni.caltech.edu> writes:

    On Monday, January 3, 2022 at 3:56:22 PM UTC-5, Tim Rentsch wrote:

    Keith Thompson <Keith.S.T...@gmail.com> writes:

    James Kuyper <james...@alumni.caltech.edu> writes:

    ...

    The standard says nothing to that effect. The only meaningful
    thing it says is that a diagnostic is required (5.1.1.3p1). I do
    not consider the standard's definition of "constraint" to be
    meaningful: "restriction, either syntactic or semantic, by which
    the exposition of language elements is to be interpreted" (3.8).

    ...

    The standard's definition of "constraint" is uncomfortably vague
    -- but that doesn't mean I'm comfortable ignoring it.

    Given the definition of a "constraint" as a "restriction, either
    syntactic or semantic, by which the exposition of language
    elements is to be interpreted", it seems to me to be at least
    plausible that when a constraint is violated, the "exposition of
    language elements" cannot be interpreted.

    ...

    I'm not saying that this is the only way to interpret that wording.
    It's vague enough to permit a number of reasonable readings. [...]

    So you're saying that the meaning of the definition of constraint
    is to some extent subjective, ie, reader dependent?

    As I said above, it seems to me to be so poorly worded that it's not
    clear to me that it has any meaning, much less one that is subjective.
    Since other people disagree with me on that point, there would
    appear to be some subjectivity at play in that judgment, but after
    reading their arguments, I remain at a loss as to how they can
    interpret that phrase as being meaningful.

    So is what you're saying that whether the meaning is subjective is
    itself a subjective question?
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.std.c on Mon Jan 17 10:09:08 2022
    From Newsgroup: comp.std.c

    Richard Damon <Richard@Damon-Family.org> writes:

    On 1/3/22 3:03 PM, Tim Rentsch wrote:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [ is a constraint violation always undefined behavior? ]

    [...] one possible interpretation of the phrase "a restriction
    ... by which the exposition of language elements is to be
    interpreted" could be that if the constraint is violated, there
    is no meaningful interpretation. Or to put it another way,
    that the semantic description applies only if all constraints
    are satisfied.

    I've searched for the word "constraint" in the C89 and C99
    Rationale documents. They were not helpful.

    I am admittedly trying to read into the standard what I think
    it *should* say. A rule that constraint violations cause
    undefined behavior would, if nothing else, make the standard a
    bit simpler.

    Note that constraint violations are not undefined behavior in a
    strict literal reading of the definition. Undefined behavior
    means there are no restrictions as to what an implemenation may
    do, but constraint violations require the implementation to
    issue at least one diagnostic, which is not the same as "no
    restrictions".

    Although, after issuing that one diagnostic, if the implementation
    continues and generates an output program, and that program is run,
    then its behavior is explicitly defined to be undefined behavior.

    I don't think so. It may be the case that the C standard is
    meant to imply that a constraint violation will necessarily
    also result in undefined behavior, but AFAICT there is no
    explicit statement to that effect.
    --- Synchronet 3.21d-Linux NewsLink 1.2