Builtins and Libraries
3.1 Global Utilities
3.2 Numbers
3.3 Strings
3.4 Booleans
3.5 Raw  Array
3.6 Tables
3.7 lists
3.8 sets
3.9 arrays
3.10 string-dict
3.11 option
3.12 pick
3.13 either
3.14 srcloc
3.15 pprint
3.16 s-exp
3.17 s-exp-structs
3.18 image-structs
3.19 image
3.20 world
3.21 reactors
3.22 plot
On this page:
3.2.1 Number Annotations
Number
Exactnum
Roughnum
Num  Integer
Num  Rational
Num  Positive
Num  Negative
Num  Non  Positive
Num  Non  Negative
3.2.2 Number Literals
3.2.3 Number Functions
num-equal
num-max
num-min
num-abs
num-sin
num-cos
num-tan
num-asin
num-acos
num-atan
num-modulo
num-truncate
num-sqrt
num-sqr
num-ceiling
num-floor
num-round
num-round-even
num-log
num-exp
num-expt
num-to-rational
num-to-roughnum
num-is-integer
num-is-rational
num-is-roughnum
num-is-positive
num-is-negative
num-is-non-positive
num-is-non-negative
num-to-string
num-to-string-digits
num-within-abs
num-within-rel
within
within-abs
within-rel
within-abs-now
within-rel-now
3.2.4 Random Numbers
num-random
num-random-seed
3.2.5 Other Number Functions
num-is-fixnum
num-exact

3.2 Numbers

Pyret numbers are of two kinds: exact numbers and rough numbers (“roughnums”). Both are to base ten; real; and finite.

Exact numbers are arbitrarily precise rational numbers: these include integers and rational fractions. For integers whose magnitude is less than (num-expt(2, 53) - 1), Pyret internally uses JavaScript fixnums, in order to optimize basic arithmetic.

Roughnums are numbers that are necessarily or deliberately imprecise. These correspond to the same set of values covered by JavaScript fixnums (a.k.a. doubles), and thus cover a large but limited range (magnitude less than 1.7976931348623157e308).

Operations on exact numbers typically return exacts. However, if the operation can yield irrationals, and it is not possible to determine that a particular result is definitely rational, that result is returned as a roughnum. Thus, trigonometric functions on exact numbers typically yield roughnum answers, except for well-known edge cases such as the sine or cosine of zero. Fractional powers of rationals are usually roughnum, except for small roots where it can be ascertained that an exact root is possible.

Operations that are non-casting and with at least one argument that is roughnum automatically coerce the result to be a roughnum. This is known as roughnum contagion.

Exact numbers allow the usual comparison predicates. Roughnums do too, with the significant exception that trying to compare roughnums for equality throws an error.

An operation whose numerical result is not determinate or finite throws an error, with the message signaling either an overflow or some more specific problem.

3.2.1 Number Annotations

The type of number values
The type of exact number values
The type of roughnum values
The type of exact integer values
The type of exact rational number values. Same as Exactnum.
The type of number values that are greater than zero
The type of number values that are less than zero
The type of number values that are less than or equal to zero
The type of number values that are equal to or greater than zero

3.2.2 Number Literals

Literal exact rationals can be integers, fractions represented with a solidus, or decimals, with an optional exponent. In the following, the numerals on the same line denote the same Pyret number.

Examples:

42 +42 -42 22/7 -22/7 2.718281828 +2.718281828 -2.718281828 1/2 0.5 6.022e23 +6.022e23 6.022e+23 +6.022e+23 -6.022e23 -6.022e+23 -6.022e-23

Exact numbers are of arbitrary precision.

Literal roughnums are represented with a leading tilde. They are either integers or decimals, with an optional exponent.

Examples:

~42 ~+42 ~-42 ~2.718281828 ~+2.718281828 ~-2.718281828 ~6.022e23 ~+6.022e23 ~6.022e+23 ~+6.022e+23 ~-6.022e23 ~-6.022e+23 ~-6.022e-23

Roughnums cannot be made arbitrarily precise. The absolute value ranges between 0 and 1.7976931348623157e+308 (JS’s Number.MAX_VALUE) with a granularity of 5e-324 (JS’s Number.MIN_VALUE).

3.2.3 Number Functions
num-equal :: (n1 :: Number, n2 :: Number)

If both arguments are exact, returns a boolean. If either argument is roughnum, raises an error.

Examples:

check: num-equal(2, 2) is true num-equal(2, 3) is false num-equal(1/2, 0.5) is true num-equal(1 / 2, 0.5) is true num-equal(1/3, 0.33) is false num-equal(1/3, ~0.33) raises "roughnums cannot be compared for equality" end

Throws an error on non-numeric arguments, which can be a useful alternative to equal-always in situations where the program shouldn’t compare non-numbers.

num-max :: (n1 :: Number, n2 :: Number) -> Number

Returns the larger of the two arguments.

Examples:

check: num-max(1, 2) is 2 num-max(2, ~3) is ~3 num-max(4, ~4) is ~4 num-max(~4, 4) is 4 num-max(-1.1, 0) is 0 end

num-min :: (n1 :: Number, n2 :: Number) -> Number

Returns the smaller of the two arguments.

Examples:

check: num-min(1, 2) is 1 num-min(2, ~3) is 2 num-min(4, ~4) is ~4 num-min(~4, 4) is 4 num-min(-1.1, 0) is -1.1 end

num-abs :: (n :: Number) -> Number

Returns the absolute value of the argument. The result is exact only if the argument is.

Examples:

check: num-abs(2) is 2 num-abs(-2.1) is 2.1 num-abs(~2) is ~2 num-abs(~-2.1) is ~2.1 end

num-sin :: (n :: Number) -> Number

Returns the sine of the argument, usually as a roughnum. If the argument is exact 0, the result is exact 0 too.

Examples:

check: num-sin(0) is 0 num-sin(1) is%(within-abs(0.01)) 0.84 end

num-cos :: (n :: Number) -> Number

Returns the cosine of the argument, usually as a roughnum. If the argument is exact 0, the result is exact 1.

Examples:

check: num-cos(0) is 1 num-cos(1) is%(within-abs(0.01)) 0.54 end

num-tan :: (n :: Number) -> Number

Returns the tangent of the argument, usually as a roughnum. However, if the argument is exact 0, the result is exact 1.

Examples:

check: num-tan(0) is 0 num-tan(1) is%(within-abs(0.01)) 1.56 end

num-asin :: (n :: Number) -> Number

Returns the arc sine of the argument, usually as a roughnum. However, if the argument is exact 0, the result is exact 0.

Examples:

check: num-asin(0) is 0 num-asin(0.84) is%(within-abs(0.01)) 1 end

num-acos :: (n :: Number)

Returns the arc cosine of the argument, usually as a roughnum. However, if the argumet is exact 1, the result is exact 0.

Examples:

check: num-acos(1) is 0 num-acos(0.54) is%(within-abs(0.01)) 1 end

num-atan :: (n :: Number) -> Number

Returns the arc tangent of the argument, usually as a roughnum. However, if the argumet is exact 0, the result is exact 0.

Examples:

check: num-atan(0) is 0 num-atan(1.56) is%(within-abs(0.01)) 1 end

num-modulo :: (n :: Number, divisor :: Number) -> Number

Returns the modulo of the first argument with respect to the second.

Examples:

check: num-modulo(5, 2) is 1 num-modulo(-5, 2) is 1 num-modulo(-5, -2) is -1 num-modulo(7, 3) is 1 num-modulo(0, 5) is 0 num-modulo(-7, 3) is 2 end

It is useful for calculating if one number is a multiple of another, by checking for a zero remainder.

Examples:

fun is-odd(n :: Number) -> Boolean: num-modulo(n, 2) == 0 where: is-odd(6) is true is-odd(3) is false end

Returns the integer part of its argument by cutting off any decimal part. Does not do any rounding.

Examples:

check: num-truncate(3.14) is 3 num-truncate(-3.14) is -3 num-truncate(~3.14) is ~3 num-truncate(~-3.14) is ~-3 end

num-sqrt :: (n :: Number) -> Number

Returns the square root. If the argument is exact and a perfect square, the result is exact.

Examples:

check: num-sqrt(4) is 2 num-sqrt(5) is%(within-abs(0.001)) ~2.236 num-sqrt(~4) is ~2 num-sqrt(~5) is%(within-abs(0.001)) ~2.236 num-sqrt(0.04) is 1/5 num-sqrt(-1) raises "negative argument" end

num-sqr :: (n :: Number) -> Number

Returns the square.

Examples:

check: num-sqr(4) is 16 num-sqr(5) is 25 num-sqr(-4) is 16 num-sqr(~4) is ~16 num-sqr(0.04) is 1/625 end

Returns the smallest integer greater than or equal to the argument. The result is exact even if the argument is rough.

Examples:

check: num-ceiling(4.2) is 5 num-ceiling(-4.2) is -4 end

num-floor :: (n :: Number) -> Number

Returns the largest integer less than or equal to the argument. The result is exact even if the argument is rough.

Examples:

check: num-floor(4.2) is 4 num-floor(-4.2) is -5 end

num-round :: (n :: Number) -> Number

Returns the closest integer to the argument. The result is exact even if the argument is rough.

Examples:

check: num-round(4.2) is 4 num-round(4.8) is 5 num-round(-4.2) is -4 num-round(-4.8) is -5 end

If the argument is midway between integers, returns the integer away from zero.

Examples:

check: num-round(3.5) is 4 num-round(2.5) is 3 end

Similar to num-round, except that if the argument is midway between integers, returns the even integer.

Examples:

check: num-round-even(3.5) is 4 num-round-even(2.5) is 2 end

num-log :: (n :: Number) -> Number

Returns the natural logarithm (ln) of the argument, usually as a roughnum. However, if the argument is exact 1, the result is exact 0. If the argument is non-positive, an error is thrown.

Examples:

check: num-log(1) is 0 num-log(0) raises "non-positive argument" num-log(-1) raises "non-positive argument" num-log(2.718281828) is%(within-abs(0.01)) 1 num-log(10) is%(within-abs(0.1)) 2.3 end

num-exp :: (n :: Number) -> Number

Returns e raised to the argument, usually as a roughnum. However, if the argument is exact 0, the result is exact 1.

Examples:

check: num-exp(-1) is%(within-abs(0.0001)) (1 / num-exp(1)) num-exp(0) is 1 num-exp(1) is%(within-abs(0.0001)) 2.718281828 num-exp(3) is%(within-abs(0.0001)) num-expt(2.718281828, 3) num-exp(710) raises "overflow" end

num-expt :: (base :: Number, exponent :: Number) -> Number

Returns the first argument raised to the second argument. The result is exact if both arguments are exact, except that an error is thrown if the first argument is zero and the second is negative. Furthermore, if the first argument is exact 0 or 1, or the second argument is exact 0, then the result is exact even if the other argument is rough.

Examples:

check: num-expt(3, 0) is 1 num-expt(1, 3) is 1 num-expt(0, 0) is 1 num-expt(0, 3) is 0 num-expt(0, -3) raises "division by zero" num-expt(2, 3) is 8 num-expt(2, -3) is 1/8 end

Same as num-exact. first argumetn is zero and the second is negative.

Given an exact num, returns the roughnum version of it. Given a roughnum, returns it directly.

Examples:

check: num-is-roughnum(num-to-roughnum(3.14)) is true num-is-roughnum(num-to-roughnum(~3.14)) is true end

Returns true if argument is an exact integer.

Examples:

check: num-is-integer(2) is true num-is-integer(1/2) is false num-is-integer(1.609) is false num-is-integer(~2) is false end

Returns true if argument is an exact rational.

Examples:

check: num-is-rational(2) is true num-is-rational(1/2) is true num-is-rational(1.609) is true num-is-rational(~2) is false end

Returns true if argument is a roughnum.

Examples:

check: num-is-roughnum(2) is false num-is-roughnum(1/2) is false num-is-roughnum(1.609) is false num-is-roughnum(~2) is true end

Returns true if argument is greater than zero.

Examples:

check: num-is-positive(~-2) is false num-is-positive(-2) is false num-is-positive(0) is false num-is-positive(-0) is false num-is-positive(2) is true num-is-positive(~2) is true end

Returns true if argument is less than zero.

Examples:

check: num-is-negative(~-2) is true num-is-negative(-2) is true num-is-negative(0) is false num-is-negative(-0) is false num-is-negative(2) is false num-is-negative(~2) is false end

Returns true if argument is less than or equal to zero.

Examples:

check: num-is-non-positive(~-2) is true num-is-non-positive(-2) is true num-is-non-positive(0) is true num-is-non-positive(-0) is true num-is-non-positive(2) is false num-is-non-positive(~2) is false end

Returns true if argument is greater than or equal to zero.

Examples:

check: num-is-non-negative(~-2) is false num-is-non-negative(-2) is false num-is-non-negative(0) is true num-is-non-negative(-0) is true num-is-non-negative(2) is true num-is-non-negative(~2) is true end

Returns a string representing a literal form of the number.

Examples:

check: num-to-string(2.5) is "5/2" num-to-string(2) is "2" num-to-string(2/3) is "2/3" num-to-string(~2.718) is "~2.718" num-to-string(~6.022e23) is "~6.022e+23" end

num-to-string-digits :: (n :: Number, digits :: Number) -> String

Converts the number to a string, providing digits precision in the output. If digits is positive, provides that many digits to the right of the decimal point (including adding zeroes beyond the actual precision of the number). If digits is negative, rounds that many positions to the left of the decimal, replacing them with zeroes.

Note that num-to-string-digits is only for formatting, and its output’s apparent precision may be unrelated to the actual precision of the input number, which may have been an approximation, or unrepresentable in decimal.

Examples:

check: num-to-string-digits(2/3, 3) is "0.667" num-to-string-digits(-2/3, 3) is "-0.667" num-to-string-digits(5, 2) is "5.00" num-to-string-digits(5, 0) is "5" num-to-string-digits(555, -2) is "600" end

Returns a predicate that checks if the difference of its two arguments is less than tol.

Examples:

check: 1 is%(num-within-abs(0.1)) 1 1 is%(num-within-abs(0.1)) ~1 ~3 is%(num-within-abs(0.1)) ~3 ~2 is-not%(num-within-abs(0.1)) ~3 ~2 is%(num-within-abs(1.1)) ~3 ~2 is-not%(num-within-abs(~1)) ~3 2 is-not%(num-within-abs(1)) ~3 5 is%(num-within-abs(4)) 3 num-within-abs(-0.1)(1, 1.05) raises "negative tolerance" end

Returns a predicate that checks that its first number argument is no more than the fraction tol off from its second argument.

This function is a.k.a. num-within.

Examples:

check: 100000 is%(num-within-rel(0.1)) 95000 100000 is-not%(num-within-rel(0.1)) 85000 end

within :: (tol :: Number)
within-abs :: (tol :: Number)
within-rel :: (tol :: Number)

These comparison functions compare both numbers and structures, and are documented in Bounded Equalities.

3.2.4 Random Numbers
num-random :: (max :: Number) -> Number

Returns a pseudo-random positive integer from 0 to max - 1.

Examples:

check: fun between(min, max): lam(v): (v >= min) and (v <= max) end end for each(i from range(0, 100)): n = num-random(i) print(n) n satisfies between(0, i - 1) end end

Sets the random seed. Setting the seed to a particular number makes all future uses of random produce the same sequence of numbers. Useful for testing and debugging functions that have random behavior.

Examples:

check: num-random-seed(0) n = num-random(1000) n2 = num-random(1000) n is-not n2 num-random-seed(0) n3 = num-random(1000) n3 is n n4 = num-random(1000) n4 is n2 end

3.2.5 Other Number Functions

A few other number functions are useful in limited cases that don’t come up in most programs.

Returns true if the argument is represented directly as a primitive JavaScript number (i.e., JavaScript double).

Examples:

check: num-is-fixnum(10) is true num-is-fixnum(~10) is false num-is-fixnum(1000000000000000) is true num-is-fixnum(10000000000000000) is false num-is-fixnum(1.5) is false end

N.B. Pyret representes exact rationals that are non-integers as tuples, and hence even small rationals such as 1.5 are considered non-fixnum, although they could be represented as JavaScript doubles.

num-exact :: (n :: Number) -> Number

Given a roughnum, returns an exact number most equal to it. Given an exact num, returns it directly.

Examples:

check: num-sqrt(2) is%(within-abs(0.000001)) ~1.4142135623730951 num-exact(num-sqrt(2)) is 1767766952966369/1250000000000000 end