|Anonymous | Login||2022-09-29 14:18 UTC|
|Main | My View | View Issues | Change Log | Docs|
|Viewing Issue Simple Details|
|ID||Category||Severity||Type||Date Submitted||Last Update|
|0000801||[1003.1(2013)/Issue7+TC1] Base Definitions and Headers||Editorial||Clarification Requested||2013-11-21 00:12||2019-06-10 08:55|
|Priority||normal||Resolution||Accepted As Marked|
|Final Accepted Text||Note: 0002146|
|Summary||0000801: Clarify requirements on M_* macros with FLT_EVAL_METHOD!=0|
Regarding the following text:
"The <math.h> header shall define the following symbolic constants. The values shall have type double and shall be accurate within the precision of the double type.
M_E Value of e
It seems unclear how these should be defined on implementations where floating point evaluation has excess precision (FLT_EVAL_METHOD!=0). In particular, at least some such implementations have compilers (modern GCC on i386 with -std=c99 or -fexcess-precision=standard) where floating point constants are evaluated with excess precision, so that, for example, (double)0.1==0.1 is false (the righthand 0.1 has nominal type double but carries excess precision).
For the sake of making a clear example, I'm going to assume we're in the case where long double is 80-bit extended precision and double is standard IEEE double precision (the only common real-world case). There are at least 3 plausible definitions for M_PI (an arbitrary example chosen because everybody's familiar with pi):
1. Mathematically correct pi to 21 decimal places: 3.14159265358979323846
Yields a value as double of 0x1.921fb54442d18p+1 and a value as ld80 of 0x1.921fb54442d1846ap+1 and (double)M_PI!=M_PI.
2. Just 17 decimal places (sufficient for double): 3.1415926535897932
Yields a value as double of 0x1.921fb54442d18p+1 and a value as ld80 of 0x1.921fb54442d18306p+1 and (double)M_PI!=M_PI.
3. With the double-precision representation of pi to 21 decimal places: 3.14159265358979311600
Yields the same value as double or long double: 0x1.921fb54442d18p+1, so (double)M_PI==M_PI.
What's not clear is which of these definitions satisfy the "shall be accurate within the precision of the double type" requirement. Option 1 tends to lead to the nicest mathematical behavior (actually taking advantage of the excess precision) but could be seen as not being "accurate within the precision of the double type". The only thing nice about option 2 is that you avoid writing "incorrect" decimal digits; it gives slightly worse mathematical results than option 1 and doesn't avoid the (double)M_PI!=M_PI weirdness despite a false appearance that it does. Option 3 largely masks the effects (both positive and negative) of excess precision, but seems to clearly satisfy the requirements.
Clarify the requirements on the definitions of the M_* constants.
|Tags||C11, c99, tc2-2008|
edited on: 2013-11-21 04:10
From <float.h> I would think the values specified would be so FLT_ROUNDS doesn't affect the precision when an explicit (double) M_PI specified. The DBL_DIG value should reflect this, as I read it, with the provided values being minimums. The C standard says it should be 15 for IEC 60559 double. Use with mantissa widths greater than DBL_MANT_DIG would be extended with 0 bits, so ((double) M_PI == (long double) M_PI) is true, as would ( (float) M_PI == ((float) (long double) M_PI) ) or ( M_PI == (double_t) M_PI ). That's the behavior I saw as being required, but I may have missed something. That hardware might support an internal representation even larger than long double and provides some or all required values to this largest precision as hardwired constants I don't think means these constants are supposed to be rounded in some way from that highest precision value, or the decimal representation used with M_* constants include extra precision that might be converted to those, whatever the setting of FLT_EVAL_METHOD. Separate constants that provide this behavior would be an extension.
The examples for ld80 are missing the explicit 'l' suffix that would make the representations different from an implicit cast of double to long double the compiler should be doing, so I'm not positive they represent valid cases. If they are, I believe just 16 digits for #define M_PI 3.141592653589793 is the most precise value that preserves these conditions. With some constants only the 15 of DBL_DIG may be appropriate, where large positive or negative exponents are involved.
|I don't follow how the comment by shware_systems relates to the question, which is specifically about constants whose nominal type is double on implementations with FLT_EVAL_METHOD!=0. Constants involving an L suffix are unrelated. On such implementations, while 17 (not 15; DBL_DIG is something else entirely) digits are sufficient to faithfully represent any IEEE double, the evaluation of constants may actually have excess precision beyond that of the nominal type. In the case of ld80 excess precision, despite 3.14159265358979323846 and 3.1415926535897932 both determining the same IEEE double, the expression 3.14159265358979323846==3.1415926535897932 is actually false. (At least the GCC interpretation of the C standard is such that it's false, and GCC is going out of its way to provide this behavior, so the GCC team presumably believes it's the correct interpretation.)|
It relates because the C standard has FLT_ROUNDS applying possibly to the compile time translation of double constants in decimal or hexadecimal format, not FLT_EVAL_METHOD. Wider may be used in the conversion process, but the value is expected to apply FLT_ROUNDS to the LSB of DBL_MANT_DIG before any casts to a wider value are used in expressions affected by FLT_EVAL_METHOD=2. Those casts are required to be by 0 bit extension; expression results can evaluate to have 1 bits in the extended part but these are still not storeable as lvalues when FLT_EVAL_METHOD!=0. Constants like M_PI are supposed to be treated as stored assuming FLT_EVAL_METHOD=0 before additional use. That's how I reconcile the language of the references below. GCC is apparently skipping that FLT_ROUNDS application so (M_PI == (ld80) M_PI) is false where it should always be true, and haven't interpreted things properly, it seems. Also, DBL_DIG does apply there; the 17 is the standard value of DECIMAL_DIG when long double = double. For safety no double constant should use more than 15 decimal digits, wherever the decimal point is, as that relates to p, not pmax.
Refs: c99tc3, Sect 18.104.22.168.2, 22.214.171.124, 126.96.36.199, Annex F.5
As explained in F.7.2, the translation-time rounding mode is always to nearest and conversion of constants from decimal/hex text to their floating-point type uses that rounding mode and raises no exceptions; FLT_ROUNDS is not involved. As explained in the semantics of FLT_EVAL_METHOD in 188.8.131.52.2, where it says "and constants", that *does* apply to interpretation of constants. If M_PI is a constant of type double, the decimal or hex digits sequence is converted in round-to-nearest to the type implied by the setting of FLT_EVAL_METHOD. Casting such a constant of type double to type double then does a runtime conversion, removing excess precision, using the runtime rounding mode.
If you want rounding modes to affect compile time translation of constants, you need the FENV_ROUND pragma from DTS 18661-1.
|That overrides what Section 6 has that applies whether __STDC_IEC_559__ defined or not... *shrug* If F.7.2 leads to ambiguities like described above I'm more inclined to think that wasn't the intent. The behavior I describe does make precise what's supposed to be there for the M_* constants, based more on DBL_DIG than DECIMAL_DIG as to how many digits are usable. Applying Section 6 with how f and l suffixes are used and are expected to be cast before <float.h> stuff or Annex F keeps things consistent.|
|Clause 6 explicitly says "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.". That is, the default rounding mode, not FLT_ROUNDS; F.7.2 simply makes the choice of default rounding a requirement. Again, you need the FENV_ROUND pragma to change the rounding mode for interpretation of floating constants.|
edited on: 2014-01-30 17:45
If FENV_ROUND is similar to <fenv.h> fesetround() then yes, that's the method needed for an application to change the default mode. If it's for rounding precision control then that's an option C and POSIX doesn't support. FLT_ROUNDS is supposed to report the default execution time rounding used in a system-independent manner, where fegetround() returns implementation defined constant values to work with feget/setround() explicitly. FLT_ROUNDS reflects any changes, per note 18, p.24, made by an application using fesetround(), not is modified directly. When __STDC_IEC_559__ defined, FLT_ROUNDS should report 1 for round to nearest being default. For "the same result format" that is determined by the suffix, none, 'f' or 'l', and, as I see it, applies before any casts to accommodate FLT_EVAL_METHOD. With no suffix it should always behave as if strtod() is used, not strtold() might be used if FLT_EVAL_METHOD=2. For float_t and double_t I could see extra precision being used, but not basic float and double.
That's all... It's more a side issue, being more C than POSIX specific, that would probably be left as "No conformance distinction can be made" for an Interpretation Request. Whether the C folks want to look at it is up to them.
For this issue, if the consensus is more language is actually needed, the most portable and historically backwards compatible resolution I can see is, at Line 9596, to add:
"The double type shall be considered as if FLT_EVAL_METHOD is 0 for the purposes of figuring the maximum number of digits usable for accurate precision, whether a decimal or hexadecimal double constant is used. For decimal constant values at least DBL_DIG, as defined in <float.h>, significant digits shall be specified."
edited on: 2014-02-21 09:50
At page 289 line 9596 section <math.h> change:
shall be accurate within the precision of the double type
shall be accurate to at least the precision of the double type
Add a note to Application usage (p 295, line 9860):
Note that if FLT_EVAL_METHOD is neither 0 nor 1, then some constants might
not compare equal as expected, for example (double)M_PI == M_PI can fail.
Add after line 12423 on p 368:
The <stropts.h> header may also define macros for message types using
names that start with M_.
Add M_ prefix reservation for <math.h> in the table on page 475, shaded XSI.
The standard does not speak to this issue, and as such no conformance
distinction can be made between alternative implementations based on
this. This is being referred to the sponsor.
Notes to the Editor (not part of this interpretation):
Make the changes in Note: 0002145
One small correction:
"Note that if FLT_EVAL_METHOD == 2..."
"Note that if FLT_EVAL_METHOD is defined with a value other than 0 or 1..."
This is since FLT_EVAL_METHOD may be defined as -1 (indeterminable) or any other negative value (with implementation-defined meaning).
|I have made some minor changes to Note: 0002145 to address Note: 0002148 and Bruce Evans' email to the reflector. I also realised that since the M_* constants in <math.h> are XSI the reservation of the M_ prefix should be shaded XSI and have altered the page 475 change accordingly.|
|Interpretation Proposed 21 Feb 2014|
|Interpretation Approved: 25 March 2014|
|2013-11-21 00:12||dalias||New Issue|
|2013-11-21 00:12||dalias||Name||=> Rich Felker|
|2013-11-21 00:12||dalias||Organization||=> musl libc|
|2013-11-21 00:12||dalias||Section||=> math.h|
|2013-11-21 00:12||dalias||Page Number||=> unknown|
|2013-11-21 00:12||dalias||Line Number||=> unknown|
|2013-11-21 04:08||shware_systems||Note Added: 0002003|
|2013-11-21 04:10||shware_systems||Note Edited: 0002003|
|2013-11-21 04:38||dalias||Note Added: 0002004|
|2013-11-21 11:11||shware_systems||Note Added: 0002006|
|2013-11-21 13:49||jsm28||Note Added: 0002008|
|2013-11-21 15:58||shware_systems||Note Added: 0002009|
|2013-11-21 16:38||jsm28||Note Added: 0002010|
|2013-11-21 22:56||shware_systems||Note Added: 0002012|
|2014-01-30 16:17||nick||Tag Attached: C11|
|2014-01-30 17:13||eblake||Tag Attached: c99|
|2014-01-30 17:17||Don Cragun||Page Number||unknown => 289-290|
|2014-01-30 17:17||Don Cragun||Line Number||unknown => 9595-9609|
|2014-01-30 17:17||Don Cragun||Interp Status||=> ---|
|2014-01-30 17:45||shware_systems||Note Edited: 0002012|
|2014-02-20 16:50||geoffclare||Note Added: 0002145|
|2014-02-20 16:52||geoffclare||Note Edited: 0002145|
|2014-02-20 16:57||geoffclare||Interp Status||--- => Pending|
|2014-02-20 16:57||geoffclare||Final Accepted Text||=> Note: 0002146|
|2014-02-20 16:57||geoffclare||Note Added: 0002146|
|2014-02-20 16:57||geoffclare||Status||New => Interpretation Required|
|2014-02-20 16:57||geoffclare||Resolution||Open => Accepted As Marked|
|2014-02-20 16:57||geoffclare||Tag Attached: tc2-2008|
|2014-02-20 17:12||nick||Issue cloned||0000828|
|2014-02-20 17:12||nick||Relationship added||parent of 0000828|
|2014-02-21 03:12||dalias||Note Added: 0002148|
|2014-02-21 09:50||geoffclare||Note Edited: 0002145|
|2014-02-21 09:55||geoffclare||Note Added: 0002149|
|2014-02-21 15:39||ajosey||Interp Status||Pending => Proposed|
|2014-02-21 15:39||ajosey||Note Added: 0002152|
|2014-03-25 13:42||ajosey||Interp Status||Proposed => Approved|
|2014-03-25 13:42||ajosey||Note Added: 0002199|
|2019-06-10 08:55||agadmin||Status||Interpretation Required => Closed|
|Mantis 1.1.6[^] Copyright © 2000 - 2008 Mantis Group|