From 52f2241a020809306739a4cf7cca3d312bc4feb8 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 6 Sep 2018 09:54:56 +0000 Subject: [PATCH] Added int-to-double.md A rendered version of patch set 17 of this CL is available here: https://gist.github.com/eernstg/a70884d5249abbecb68d7771cb18ae37. Change-Id: If175f1787c11603bb4ed9bf89181cd8585afa54f Reviewed-on: https://dart-review.googlesource.com/68683 Reviewed-by: Lasse R.H. Nielsen --- docs/language/informal/int-to-double.md | 184 ++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/language/informal/int-to-double.md diff --git a/docs/language/informal/int-to-double.md b/docs/language/informal/int-to-double.md new file mode 100644 index 00000000000..d9cd3400247 --- /dev/null +++ b/docs/language/informal/int-to-double.md @@ -0,0 +1,184 @@ +## Feature: Evaluating integer literals as double values + +**Author**: eernst@. + +**Version**: 0.4 (2018-08-14). + +**Status**: Background material, in language specification as of +[d14b256](https://github.com/dart-lang/sdk/commit/d14b256e351464db352f361f1206e1415db65d9c). + +**This document** is a feature specification of the support in Dart 2 for +evaluating integer literals occurring in a context where the expected type +is `double` to a value of type `double`. + + +## Motivation + +In a situation where a value of type `double` is required, e.g., as an +actual argument to a constructor or function invocation, it may be +convenient to write an integer literal because it is more concise, and +the intention is clear. For instance: + +```dart +double one = 1; // OK, would have to be `1.0` without this feature. +``` + +This mechanism only applies to integer literals, and only when the expected +type is a type `T` such that `double` is assignable to `T` and `int` is not +assignable to `T`; in particular, it applies when the expected type is +`double`. + +That is, the result of a computation (say, `a + b` or even a lone variable +like `a` of type `int`) will never be converted to a double value +implicitly, and it also doesn't happen when the expected type is a type +variable declared in an enclosing scope, no matter whether that type +variable in a given situation at run time has the value `double`. The one +case where conversion does happen when the expected type is a type variable +is when its upper bound is a subtype of `double` (including `double` +itself). For example: + +```dart +class C { + X foo(X x) => x; + double d1 = foo(42); // OK. + double d2 = foo(42); // OK, type argument inferred as `double`. + num n1 = 42 as double; // OK, `42` evaluates to 42.0. + N n2 = 42; // Error, neither `int` nor `double` assignable to `N`. + NN n3 = 42; // OK, `int` not assignable, but `double` is. + FutureOr n4 = 42; // OK, same reason. + N n5 = n1; // OK statically, dynamic error if `N` is `int`. +} +``` + + +## Syntax + +This feature has no effect on the grammar. + + +## Static Analysis + +Let _i_ be a lexical token which is syntactically an _integer literal_ (as +defined in the language specification section 16.3 Numbers). If _i_ occurs +as an expression in a context where the expected type `T` is such that +`double` is assignable to `T` and `int` is not assignable to `T` then we +will say that _i_ is a _double valued integer literal_. + +The static type of a double valued integer literal is `double`. + +The _unbounded integer value_ of an integer literal _i_ is the mathematical +integer (that is, unlimited in size and precision) that corresponds to the +numeral consisting of the digits of _i_, using radix 16 when _i_ is prefixed +by `0x` or `0X`, and radix 10 otherwise. + +It is a compile-time error if the unbounded integer value of a double +valued integer literal is less than +-(1−2−53) * 21024 +and if it is greater +than (1−2−53) * 21024. + +It is a compile-time error if the unbounded integer value of a double +valued integer literal cannot be represented exactly as an IEEE 754 +double-precision value, assuming that the mantissa is extended with zeros +until the precision is sufficiently high to unambiguously specify a single +integer value. + +*That is, we consider a IEEE 754 double-precision bit pattern to represent +a specific number rather than an interval, namely the number which is +obtained by extending the mantissa with zeros. In this case we are only +interested in such bit patterns where the exponent part is large enough to +make the represented number a whole number, which means that we will need +to add a specific, finite number of zeros.* + +*Consequently, +`double d = 18446744073709551614;` +has no error and it will initialize `d` to have the double value +represented as 0x43F0000000000000. But +`int i = 18446744073709551614;` +is a compile-time error because 18446744073709551614 is too large to be +represented as a 64 bit 2's complement number, and +`double d = 18446744073709551615;` +is a compile-time error because it cannot be represented exactly using the +IEEE 754 double-precision format.* + + +## Dynamic Semantics + +At run time, evaluation of a double valued integer literal _i_ yields a +value of type `double` which according to the IEEE 754 standard for +double-precision numbers represents the unbounded integer value of _i_. + +Signed zeros in IEEE 754 present an ambiguity. It is resolved by +evaluating an expression which is a unary minus applied to a double valued +integer literal whose unbounded integer value is zero to the IEEE 754 +representation of `-0.0`, and other occurrences of a double valued integer +literal whose unbounded integer value is zero to the representation of +`0.0`. + +*We need not specify that the representation is extended with zeros as +needed, because there is in any case only one IEEE 754 double-precision bit +pattern that can be said to represent the given unbounded integer value: It +would belong to the interval under any meaningful interpretation of such a +bit pattern as an interval.* + + +## Discussion + +We have chosen to make it an error when a double valued integer literal +cannot be represented exactly by an IEEE 754 double-precision encoding. We +could have chosen to allow for a certain deviation from that, such that it +would be allowed to have a double valued integer literal whose unbounded +integer value would differ "somewhat" from the nearest representable value. + +However, we felt that it would be misleading for developers to read a large +double valued integer literal, probably assuming that every digit is +contributing to the resulting double value, if in fact many of the digits +are ignored, in the sense that they must be replaced by different digits in +order to express the nearest representable IEEE double-precision value. + +For instance, +11692013098647223344361828061502034755750757138432 is represented as +0x4A20000000000000, but so is +11692013098647223344638182605120307455757075314823, which means that +the 29 least significant digits are replaced by completely different +digits. The former corresponds to an extension of the IEEE representation +with a suitable number of zeros in the mantissa which will translate back +to exactly that number, and the latter is just some other number which is +close enough to have the same IEEE representation as the nearest +representable value. + +We expect such large double valued integer literals to occur very rarely, +which means that such a situation will not arise very frequently. However, +when it does arise it may be quite frustrating for developers to find a +representable number, assuming that they start out with something like +11692013098647223344638182605120307455757075314823. It is hence recommended +that tools emit an error message where the nearest representable value is +mentioned, such that a developer may copy it into the code in order to +eliminate the error. + +Another alternative would be to accept only those double valued integer +literals whose unbounded integer value can be represented as a 2's +complement bit pattern in 64 bits or in an unsigned 64 bit representation, +that is, only those which are also accepted as integer literals of type +`int`. This would ensure that developers avoid the situation where a large +number of digits are incorrectly taken to imply a very high precision. +This is especially relevant with decimal double valued integer literals, +because they do not end in a large number of zeros, which make them "look" +like a high-precision number where every digit means something. However, we +felt that this reduction of the expressive power brings so few benefits +that we preferred the approach where also "large numbers" could be +expressed using a double valued integer literal. + + +## Updates + +* Version 0.4 (2018-08-14), adjusted rules to allow more expected types, + such as `FutureOr`, for double valued integer literals. + +* Version 0.3 (2018-08-09), changed error rules such that it is now an + error for a double valued integer literal to have an unbounded + integer value which is not precisely representable. + +* Version 0.2 (2018-08-08), added short discussion section. + +* Version 0.1 (2018-08-07), initial version of this feature specification.