E's float64s are the subset of standard IEEE double precision floating point values specified by Java. This is identical to the IEEE standard except that there's only one (non-signalling) NaN value, and the only rounding mode supported is round-to-even. Therefore, a float64 can only have one of four kinds of values:
As explained in When Are Two Things the Same?, "==" tests whether two values are computationally equivanelent. As applied to float64 values, leaving aside NaNs, -0.0, or mixing float64s with integers, this is the same as arithmetic equality (as defined by the IEEE floating point standard).
? pragma.syntax("0.8") ? 5.1 == 5.1 # value: true
You can use "<=>" operator to test for arithmetic equality:
The following cases are all those for which being the same differs from being arithmetically equal:
? NaN == NaN # value: true ? NaN <=> NaN # value: false
These are clearly the same, and E says so. However, according to the IEEE standard, NaNs are not arithmetically equal to anything, including themselves.
? 0.0 == -0.0 # value: false ? 0.0 <=> -0.0 # value: true
IEEE states that positive zero and negative zero are distinct values that are nevertheless arithmetically equal. Since they're distinct, they aren't the same, and E says so.
? 3.0 == 3 # value: false ? 3.0 <=> 3 # value: true
Of course, integer values are distinct from floating point values, even when they represent the same real number.
? 3 == 3.0 # value: false ? 3 <=> 3.0 # value: true
In all cases, "a != b" is equivalent to "!(a == b)".
Magnitude Comparisons (non-associative)
On float64, these have the standard conventional meaning, but you may find this meaning surprising:
? 3.0 <= NaN # value: false ? NaN <= 3.0 # value: false ? NaN >= 3.0 # value: false ? NaN <= NaN # value: false
Yup. If at least one of the operands is a NaN, the answer's always false. This means that the double precision floating point values are not fully ordered, and many sorting algorithms many fail to sort them. All this applies equally to Java.
Interval Expressions (non-associative)
Whereas on integers, 5..!9 is equivalent to 5..8, on float64s 5.0..!9.0 includes all the double precision floating point numbers up to but excluding 9.0. It approximates the mathematical concept of a closed-open interval. We have yet to determine what the protocol is of the resulting float64 interval, but (unlike integer intervals) it cannot act like a ConstList, as it would be too exhausting to enumerate one.
Additive Expressions (left associative)
As you'd expect.
Multiplicative Expressions (left associative)
These mean the same as they do for integers. Notice that for both integers and float64s, "/" produces a float64 and "//" produces an integer.
Exponentiation Expression (non associative)
As you'd expect.
Negation Expression (left associative)
As you'd expect.
Additional float64 Messages
In addition to the messages corresponding to the above operators, float64s respond to the following messages.
? (-5.1).truncDivide(3.1) # value: -1
"truncDivide" is integer division where the answer is rounded to an integer by rounding towards zero. It correspond to Java's "/" operator on integers.
? (-5.1).ceil() # value: -5
Nearest integer by rounding towards positive infinity.
? (-5.1).floor() # value: -6
Nearest integer by rounding towards negative infinity.
? (-5.1).round() # value: -5 ? (-5.6).round() # value: -6
The actually nearest integer.
? (-5.1).truncate() # value: -5 ? (-5.1).truncate() # value: -5
Nearest integer by rounding towards zero.
? (-5.1).abs() # value: 5.1
Additional messages log, sin, cos, tan, sqrt, exp, asin, acos, atan, atan2(y), min(other), and max(other) are simply the corresponding static methods of java.lang.Math turned into instance methods of float64. See the javadoc-umentation of java.lang.Math for their specification.
Some useful constants and corresponding tests:
? NaN.isNaN() # value: true? Infinity.isInfinite() # value: true? def PI := (0.0.acos()) * 2.0 # value: 3.141592653589793 ? def e := 1.0.exp() # value: 2.7182818284590455
Mixing integers and float64s
Obsolete: E adopts a simple but strange rule regarding expressions of mixed arithmetic type: unless specified otherwise, the right operand must always adapt to the left operand. This is known as the left-side-wins rule. Integers are happy to adapt by automatically converting to float64. However, since there's no one right way for a float64 to convert to an integer, the programmer must specify:
? 3.1 + 5 # value: 8.1 ? 3 + 5.1 # value: 8.1 ? 3 + 5.1.round() # value: 8
The chapter on capability programming style will explain how the left-side-wins rule accomodates both extensibility and security.
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.