Allow ties in floating literals
Table of contents
Problem
Proposal #143 suggested that we do not allow ties in floating-point literals. That is, given a literal whose value lies exactly half way between two representable values, we should reject rather than arbitrarily picking one of the two possibilities.
However, the statistical argument presented in that proposal misses an important fact: the distribution of the values that are exactly half way between representable values includes several values of the form A x 10B, where A and B are small integers.
For example, the current rule rejects this very reasonable looking code:
var v: f32 = 9.0e9;
… because 9 x 109 lies exactly half way between the nearest two representable values of type f32
, namely 8999999488 and 9000000512. Similar examples exist for larger floating point types:
// Error, half way between two exactly representable values.
var w: f64 = 5.0e22;
We would also reject an attempted workaround such as:
var v: f32 = 5 * 1.0e22;
… because the literal arithmetic would be performed exactly, resulting in the same tie. A workaround such as
var v1: f32 = 5.0e22 + 1.0;
var v2: f32 = 5.0e22 - 1.0;
… to request rounding upwards and downwards, respectively, would work. However, these seem cumbersome and burden the Carbon developer with floating-point minutiae about which they very likely do not care.
Background
For background on the ties-to-even rounding rule, see this Wikipedia article. The ties-to-even rule is the default rounding mode specified by ISO 60559 / IEEE 754.
Proposal
Instead of rejecting exact ties, we use the default IEEE floating point rounding mode: we round to even.
Details
See design changes.
Rationale based on Carbon’s goals
- Code that is easy to read, understand, and write
- This improves the ease of both reading and writing floating-point literals that would result in ties.
- This improves the language consistency, by performing the same rounding when converting literals as is performed by default when converting runtime values.
- Practical safety and testing mechanisms
- It is unlikely that making an arbitrary but consistent rounding choice will harm safety or program correctness.
- Fast and scalable development
- Modern OS platforms, hardware architectures, and environments
- Interoperability with and migration from existing C++ code
- This rule, likely because it is the IEEE default rounding mode, already appears to be used by major C++ compilers such as Clang, GCC, MSVC, and ICC.
Alternatives considered
We could round to even only for decimal floating-point literals, and still use the rule that ties are rejected for hexadecimal floating point. In the latter case, a tie means that too many digits were specified, and the trailing digits were exactly 80000...
.
However, because we support arithmetic on literals, forming other literals, this would mean that whether a literal was originally written in hexadecimal would form part of its value and thereby part of its type. There would also be problems with literals produced by arithmetic. The complexity involved here far outweighs any perceived benefit of diagnosing mistyped literals.