2023-12-15
document number | date | comment |
---|---|---|
n3206 | 202312 | this paper, original proposal |
CC BY, see https://creativecommons.org/licenses/by/4.0
The current state if imaginary types in clause 6 and Annex G is not really operational, so we should either make it so or remove them from there.
They are not operational because it is not possible to map their mathematical properties to our type/operator/conversion model as-is. Our model imposes that the result of binary operator in general is one of
int
(for comparisons and logical operators),<<
) orThis model does not fit for imaginary types because we need result types according to the following table:
operator kind | operand types | result type |
---|---|---|
additive | ||
real + imaginary | complex | |
multiplicative | ||
real * imaginary | imaginary | |
imaginary * imaginary | real |
Our Annex G does exactly propose such a model for the arithmetic itself, but without showing how these would work together with usual arithmetic conversion; in our process of determination of operand conversions and operator result type usual arithmetic conversion is applied whenever the types to not exactly fit. For example with only Annex G, and an implementation that has imaginary types the innocent looking expression
(where I
is the standard macro) has undefined behavior by omission, because the first operand has type double
and the second has _Imaginary float
and no rule is defined for them as usual arithmetic conversion. On the other hand, the same lexical expression has well-defined behavior on implementations with only complex types but without imaginary types.
Nevertheless, the definition and designated use case of macros like I
in case there is an imaginary type build exactly these kind of mixed operations to define imaginary parts in complex expressions of different floating point rank. The use of this kind of expression is well established in the field.
In our current model this kind of operation is only possible if such operations would first map the operands to a complex type and then would return that same type. This would undercut the purpose that the imaginary types could have
There do not seem to be a lot of implementations that provide this feature, at least a first web search that I did with the corresponding keywords only turned up references to the C standard, and to mentions that the corresponding compiler does not implement the feature. But this may be a hen an egg problem; implementations that maybe started looking into this found that the specification is missing, people in the standardization process didn’t bother with it because there are no implementations.
Even worse, we found an implementation (gcc v .13 with glibc) that claims to adhere to Annex G by definining __STDC_IEC_60559_COMPLEX__
but that does not implement imaginary types at all. There are bug reports pointing fingers but no satisfying solution to any of this. For gcc this is really a pity, because they have very good support for complex numbers throughout and even extend this concept to integer types.
Generally, implementions that would start to provide imaginary types from one version to another would probable put their user base into trouble. Not only the kind of expression as discussed has UB, but also types and sizes of expression would change and type inspection via _Generic
or typeof
would lead to unexpected results. In principle, user code that uses complex types could always test for imaginary
or so, but I don’t think anybody ever does that. And there is a good reason for users not to do such tests: there is no platform on which they even could compile fallback code that uses imaginary
.
All of this means that imaginary types are not yet of much importance in C’s ecosystem. So a consequence of the lack of a clear specification and the lack of implementations could be to remove the feature from clause 6, Annex G, and all references to these types. This would not be difficult (there are only a few places outside the annex) and would not even be much of a normative change for the core language: the correponding keywords in clause 6 are in the space of reserved identifier, anyhow.
To summarize:
Many implementations that have complex types now have moved to a representation of imaginary literals in the grammar: a floating point literal followed by i
(and maybe I
) is considered to have a complex value with only an imaginary part. I think that we should add this feature to the C standard, such that we could have support for complex types and operations, even without refering to the correponding header file.
But then for these new literals the same questions as for _Complex_I
arise:
1.i
have complex type or imaginary type?I think that for portability it would be good to fix that answer such that there is only one possible outcome.
Are WG14 members aware of any context where these types would be missing?
That would then probably be delegated to the FP study group.
1.i
notation for imaginary literals?1.i
literals have?__STDC_IEC_60559_COMPLEX__
to just mean “supports complex types according to Annex G”?This would make gcc conforming. Other compilers that don’t have this macro for exactly that reason (clang for example) could then follow.
__STDC_IEC_60559_IMAGINARY__
?