7.2 Numbers
A number can be an integer (see Integer), rational number (see Rational), or real number (see Real), or complex number (see Number), where each of those categories includes the earlier categories. For the last three categories, a number is either exact (see Exact) or inexact (see Inexact), where inexact real numbers are represented using a 64-bit IEEE floating-point representation. An integer is always exact. Inexact complex numbers have inexact real and imaginary components, except that the real component can be exact 0. The “real” category is something of a misnomer, since it is rational numbers plus the special constants #inf, #neginf, and #nan that correspond to IEEE floating-point infinities and non-a-number. An inexact real number is a flonum.
The precision and size of exact numbers is limited only by available memory and the precision of operations that can produce irrational numbers. Adding, multiplying, subtracting, and dividing exact numbers always produces an exact result. A fixnum (see Fixnum) is an integer that is small enough to have a specialized representation.
Real numbers are comparable, which means that generic operations like < and > work on real numbers, while specialized operations like .< and .> work only on real numbers. Two numbers are the same according to == when they have the same exactness as well as the same numerical value. Comparison with .= conceptually coerces an inexact argument to an exact representation before comparing with ==.
The syntax of numbers is determined by the shrubbery layer. Note that _ is allowed as a separator between digits, so 1_000_000 is the same as 1000000. Complex number literals rely on a escape to S-expression syntax.
annotation | |
Although only real numbers are comparable, to make the results of arithmetic operations easier to compare in static mode, static information associated by Number specifies Real-specific Comparable operations.
#true
#true
#true
#true
#true
#true
#false
#false
annotation | ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
| ||||||||||||
annotation | ||||||||||||
| ||||||||||||
|
The Int.in annotation constraints a integers to be within the given range, which is specified either by constructing a Range or by providing separate start and end numbers. When a range is specific by separate numbers, then each end of the range is inclusive by default, but ~inclusive or ~exclusive can be specified. Using .., ..=, <.., or <..= directly to construct a range is treated the same as specifying one or two separate numbers, instead of constructing an intermediate Range value.
#true
#true
#true
#true
#true
#true
#false
#true
#false
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
The Real.at_least, Real.above, Real.below, and Real.at_most annotations further constrain the number to be equal to or greater than, greater than, less then, or equal to or less than the given number, respectively.
The Real.in annotation constraints a real number to be within the given range, where each end of the range is inclusive by default, but ~inclusive or ~exclusive can be specified.
#true
#true
#true
#true
#false
> 1 is_a Real.at_least(1)
#true
> 1 is_a Real.above(1)
#false
#true
#false
annotation | |
#true
#false
annotation | |
#true
#true
#false
annotation | |
#true
#true
#false
#false
annotation | |
#true
#false
annotation | |
#true
#false
#true
expression | |
| |
| |
repetition | |
| |
| |
binding operator | |
|
> Byte#"a"
97
| ~else: "no"
"yes"
> Byte#"too long"
Byte: expected a literal single-byte byte string
Byte: expected a literal single-byte byte string
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
|
When expressions for both x and y have static information from Flonum (or just x in the case of prefix the - operator), then the arithmetic operation is specialized to one that expects Flonum arguments. If the static information is incorrect (e.g., because a non-checking :~ is used), then a run-time error is reported if an argument is not a Flonum.
Note that forms like +1, -1, and 1/2 are immediate numbers, as opposed to uses of the +, -, and / operators.
> 1+2
3
> 3-4
-1
> - 4
-4
> 5*6
30
> 8 / 2
4
> 7 / 2
7/2
> 7.0/2
3.5
7
> 2**10
1024
9
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
|
> 7 div 5
1
> 7 rem 5
2
> 7 mod 5
2
> 7 mod -5
-3
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
| ||
| ||
operator | ||
|
These comparisons are specialized like + for arguments with Flonum static information.
> 1 .< 2
#true
> 3 .>= 3.0
#true
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
| ||
function | ||
When a call to the math.abs, math.max, math.min, math.floor, math.ceiling, math.round, math.truncate, math.sin, math.cos, or math.tan function has arguments with static information from Flonum, then the functions are specialized to ones that require Flonum arguments, similar to operations like +. The other functions are not specialized, because they do not always produce Flonum results for Flonum arguments.
> math.abs(-1.5)
1.5
> math.min(1, 2)
1
> math.max(1, 2)
2
> math.floor(1.5)
1.0
> math.ceiling(1.5)
2.0
> math.round(1.5)
2.0
> math.sqrt(4)
2
> math.cos(3.14)
-0.9999987317275395
> math.sin(3.14)
0.0015926529164868282
0.9992039901050427
> math.acos(1)
0
> math.asin(1)
1.5707963267948966
> math.atan(0.5)
0.4636476090008061
> math.atan(1, 2)
0.4636476090008061
> math.log(2.718)
0.999896315728952
> math.exp(1)
2.718281828459045
> math.exact(5.0)
5
> math.inexact(5)
5.0
function | |
| |
function | |
| |
function | |
| |
function | |
> math.real_part(5)
5
> math.real_part(math.sqrt(-1))
0
> math.imag_part(math.sqrt(-1))
1
> math.magnitude(1 + math.sqrt(-1))
1.4142135623730951
> math.angle(1 + math.sqrt(-1))
0.7853981633974483
function | |
| |
function | |
> math.numerator(256/6)
128
> math.denominator(256/6)
3
> math.denominator(0.125)
8.0
function | |
| |
function | |
For non-integer arguments, the result for math.gcd is the greatest common divisor of the numerators divided by the least common multiple of the denominators. The result for math.lcm for non-integer arguments is the absolute value of the product divided by the math.gcd of the arguments.
If no arguments are provided, the result of math.gcd is 0 and the result of math.lcm is 1. If all arguments for math.gcd are zero, the result is zero. If any argument for math.lcm is zero, the result is zero, and the result is exact 0 if any argument is exact 0.
> math.gcd(2, 3, 7)
1
> math.gcd(4, 2, 16)
2
> math.lcm(2, 3, 7)
42
> math.lcm(4, 10, 2)
20
> math.gcd()
0
> math.lcm()
1
function | ||
| ||
function | ||
| ||
| ||
function | ||
When called with n, returns a random integer between 0 (inclusive) and n (exclusive).
When called with start and end, returns a random integer between start (inclusive) and end (exclusive).
See also Random.random.
> math.random()
0.5348255534758128
> math.random(17)
13
> math.random(1, 42)
21
function | |
| |
reducer | |
| |
function | |
| |
reducer | |
> math.sum()
0
> math.sum(1, 2, 3, 4)
10
> math.product(1, 2, 3, 4)
24
i
45
function | |
| |
function | |
| |
function | |
| |
function | |
| |
function | |
> math.less()
#true
> math.less(1)
#true
> math.less(2, 1)
#false
> math.less(1, 2, 3, 4)
#true
> math.less(1, 2, 3, 0)
#false
> math.pi
3.141592653589793
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
operator | ||||
| ||||
| ||||
function | ||||
| ||||
function | ||||
|
bits.and, bits.or (inclusive), bits.xor, work on pairs of bits from n and m;
bits.not inverts every bit in n;
bits.(<<) and bits.(>>) perform a left shift or arithmetic right shift of n by m bits;
bits.(?) reports whether the bit at position m (counting from 0 as the least-significant bit) is set within n;
bits.length reports the number of bits that remain in n if all identical leading bits (0s for a position n or 1s for a negative n) are removed; and
bits.field produces the integer represented by bits start (inclusive) through end (exclusive) of n.
> 5 bits.and 3
1
> 5 bits.or 3
7
> 5 bits.xor 3
6
> bits.not 3
-4
> 5 bits.(<<) 2
20
> 5 bits.(>>) 2
1
> bits.length(2)
2
> bits.length(-2)
1
> bits.field(255, 1, 4)
7