E's integers can represent any mathematical integer, no matter how big. These are often known as bignums, and is traditionally illustrated using recursive factorial: ? pragma.syntax("0.8") ? def factorial(n) :any { > if (n <= 0) { > 1 > } else { > n * factorial(n-1) > } > } # value: <factorial> ? factorial(3) # value: 6 ? factorial(30) # value: 265252859812191058636308480000000 The above code uses a number of arithmetic operators. Here are the integer operators organized by precedence and associativity. Precedence and associativity determine how an expression involving multiple operators is to be read. For example, how should one read the following? x + y * u - w - z E's answer is "((x + (y * u)) - w) - z", because
Higher precedence means that it groups tighter than operators of lower precedence. Left associative means that it groups left-to-right. Non-associative means it doesn't group with itself. For example, in E you can't say "5 == 6 == 7" since == is non-associative. Boolean Comparisons (non-associative)
On integers, these do just what you'd expect from any C-tradition language. Since E's integers are not precision limited, the bitwise operators see negative integers as having an infinite number of leading one bits, and the non-negative integers as having an infinite number of leading zero bits. Magnitude Comparisons (non-associative)
On integers, these have the conventional meaning. Interval Expressions (non-associative)
The interval expression makes it especially convenient to form interval objects. An interval object acts like a consecutive sequence of numbers, but uses a more compact representation. Intervals are useful, for example, in iteration: ? for i in 0..4 { > println(`i => ${factorial(i)}`) > } 0 => 1 1 => 1 2 => 2 3 => 6 4 => 24 The reason for the strange syntax "..!" is that inclusive-exclusive intervals are often the most useful (and least accident prone) but have no natural notation. "x ..! y" can be thought of as "from x to, but not, y". Bit Shift Expressions (left associative)
Additive Expressions (left associative)
As you'd expect. Multiplicative Expressions (left associative)
Multiplication is add you'd expect. Division and remainder present an interesting problem. Integer division cannot of course be exact. E's "/" always gives the nearest floating point answer, even for cases that have an exact integer answer. E's "//" (pronounced "floor-divide") always gives the nearest integer not greater than the actual answer, ie, rounding towards negative infinity. By contrast, Java's "/" rounds towards zero. E's integers respond to the "truncDivide" message with this Java behavior. "%" is the remainder of truncDivide. "%%" is the remainder of "//", which is equivalent to the mathematical notion of modulo. It turns out that modular exponentiation can be calculated vastly faster than the equivalent modulo of an exponentiation, so E's expansion recognizes this one case of a three-operand operator expression. Here's a useful demonstration of a mathematical discovery by Whit Diffee and Martin Hellman: ? def base := 2 # value: 2 ? def mod := 3717 # value: 3717 ? def JoeSecret := 298724 # value: 298724 ? def JoePublic := base ** JoeSecret %% mod # value: 3280 ? def BettySecret := 378627 # value: 378627 ? def BettyPublic := base ** BettySecret %% mod # value: 8 ? BettyPublic ** JoeSecret %% mod # value: 631 ? JoePublic ** BettySecret %% mod # value: 631 If base and mod are publicly known, and if Joe and Betty each publicize only their calculated public numbers, then the above calculation shows them how they can calculate a new number, eg, 631, that they both agree on.
In the above example, base, mod, JoeSecret, and BettySecret were chosen by flinging my fingers at the keyboard. If instead they are chosen well, then no one who only knows base, mod, JoePublic, and BettyPublic will be able to calculate the number that Joe and Betty have come to agree on. This is known as Diffee Hellman Key Agreement. Exercise for the reader: If the above example used larger numbers, would this web page be export controlled? For the numerically savvy, there's another way in which "x ** y %% z" is better than "(x ** y) %% z", beyond being more efficient. If y is negative the latter expression doesn't make any sense (and throws an exception) while the former expression calculates "(x ** y.abs()).modInverse(z)", though once again, more efficiently. Exponentiation Expression (non associative)
As you'd expect. Negative exponents are not allowed at this time. Unary Expressions (left associative)
As you'd expect.
Additional integer MessagesIn addition to the messages corresponding to the above operators, integers respond to the following messages. ? (-5).truncDivide(3) # value: -1 "truncDivide" is integer division where the answer is rounded to an integer by rounding towards zero. It correspond to Java's "/" operator. ? (-5).ceil() # value: -5 ? (-5).floor() # value: -5 ? (-5).round() # value: -5 ? (-5).truncate() # value: -5 On float64s, "ceil", "floor", "round", and "trunc" are used to get a corresponding integer. They are defined on integers as well to just return the integer itself. Why? That way, if you've got a number and you ask for an integer, it works even if you already have an integer. ? 33.asChar() # value: '!' Returns the character whose character code in unicode is 33. ? 33.asFloat64() # value: 33.0 Converts to a floating point number. ? (-5).abs() # value: 5 Absolute value. ? 248972.gcd(872346) # value: 2 Greatest Common Divisor. Integer Syntax** To be written |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
|