# Numbers and strings

This chapters covers in detail the built-in objects used to manipulate numbers and strings. First the integer, relatif and real numbers are described. There is offers a broad range of methods for these three objects to support numerical computation. As a second step, string and character objects are described. Many examples show the various operations which can be used as automatic conversion between one type and another. Finally, the boolean object is described. These objects belongs to the class of literal objects, which are objects that have a string representation.

## Integer number

The fundamental number representation is the `Integer`. The integer is a 64 bits signed 2's complement number. Even when running with a 32 bits machine, the 64 bits representation is used. If a larger representation is needed, the `Relatif` object might be more appropriate. The `Integer` object is a literal object that belongs to the number class.

### Integer format

The default literal format for an integer is the decimal notation. The minus sign (without blank) indicates a negative number. Hexadecimal and binary notations can also be used with prefix `0x` and `0b`. The underscore character can be used to make the notation more readable.

const a 123 trans b -255 const h 0xff const b 0b1111_1111

Integer number are constructed from the literal notation or by using an explicit integer instance. The `Integer` class offers standard constructors. The default constructor creates an integer object and initialize it to 0. The other constructors take either an integer, a real number, a character or a string.

const a (Integer) const b (Integer 2000) const c (Integer "23")

When the hexadecimal or binary notation is used, care should be taken to avoid a negative integer. For example, `0x_8000_0000_0000_0000` is the smallest negative number.

### Integer arithmetic

Standard arithmetic operators are available as built-in operators. The usual addition `+`, multiplication `*` and division `/` operate with two arguments. The subtraction `-` operates with one or two arguments.

+ 3 4 - 3 4 - 3 * 3 4 / 4 2

As a built-in object, the `Integer` object offers various methods for built-in arithmetic which directly operates on the object. The following example illustrates these methods.

trans i 0 i:++ i:-- i:+ 4 i:= 4 i:- 1 i:* 2 i:/ 2 i:+= 1 i:-= 1 i:*= 2 i:/= 2

As a side effect, these methods allows a const symbol to be modified. Since the methods operates on an object, they do not modify the state of the symbol. Such methods are called mutable methods.

const i 0 i:= 1

### Integer comparison

The comparison operators works the same. The only difference is that they always return a `Boolean` result. The comparison operators are namely equal `==`, not equal `!=`, less than `<`, less equal `<=`, greater `>` and greater equal `>=`. These operators take two arguments.

== 0 1 != 0 1

Like the arithmetic methods, the comparison operators are supported as object methods. These methods return a `Boolean` object.

i:= 1 i:== 1 i:!= 0

### Integer calculus

Armed with all these functions, it is possible to develop a battery of functions operating with numbers. As another example, we revisit the Fibonacci sequence as demonstrated in the introduction chapter. Such example was terribly slow, because of the double recursion. Another method suggested by Springer and Friedman uses two functions to perform the same job.

const fib-it (gamma (n acc1 acc2) ( if (== n 1) acc2 (fib-it (- n 1) acc2 (+ acc1 acc2))))

const fiboi (gamma (n) ( if (== n 0) 0 (fib-it n 0 1)))

This later example is by far much faster, since it uses only one recursion. Although, it is no the fastest way to write it, it is still an elegant way to write complex functions.

### Other Integer methods

The `Integer` class offers other convenient methods. The `odd-p` and `even-p` are predicates. The `mod` take one argument and returns the modulo between the calling integer and the argument. The `to-string` method returns a string representation of the integer. The `abs` methods returns the absolute value of the calling integer.

i:even-p i:odd-p i:mod 2 i:= -1 i:abs i:to-string

## Relatif number

A relatif or big number is an integer with infinite precision. The `Relatif` class is similar to the `Integer` class except that it works with infinitely long number. The relatif notation uses a `r` or `R` suffix to express a relatif number versus an integer one. The `Relatif` object is a literal object that belongs to the number class.

const a 123R trans b -255R const c 0xffR const d 0b1111_1111R const e (Relatif) const f (Relatif 2000) const g (Relatif "23")

### Relatif operations

Most of the `Integer` class operations are supported by the `Relatif` object. The only difference is that there is no limitation on the number size. This naturally comes with a computational price. An amazing example is to compute the biggest know prime Mersenne number. The world record exponent is 6972593. The number is therefore:

const i 1R const m (- (i:shl 6972593) 1)

This number has 2098960 digits. You can use the `println` method if you wish, but you have been warned...

## Real number

The `real` class implements the representation for floating point number. The internal representation is machine dependent, and generally follows the double representation with 64 bits as specified by the IEEE 754-1985 standard for binary floating point arithmetic. All integer operations are supported for real numbers. The `Real` object is a literal object that belongs to the number class.

### Real format

The parser supports two types of literal representation for real number. The first representation is the dotted decimal notation. The second notation is the scientific notation.

const a 123.0 # a positive real const b -255.5 # a negative real const c 2.0e3 # year 2000.0

Real number are constructed from the literal notation or by using an explicit real instance. The `Real` class offers standard constructors. The default constructor creates a real number object and initialize it to 0.0. The other constructors takes either an integer, a real number, a character or a string.

### Real arithmetic

The real arithmetic is similar to the integer one. When an integer is added to a real number, that number is automatically converted to a real. Ultimately, a pure integer operation might generate a real result.

+ 1999.0 1 # 2000.0 + 1999.0 1.0 # 2000.0 - 2000.0 1 # 1999.0 - 2000.0 1.0 # 1999.0 * 1000 2.0 # 2000.0 * 1000.0 2.0 # 2000.0 / 2000.0 2 # 1000.0 / 2000.0 2.0 # 1000.0

Like the `Integer` object, the `Real` object has arithmetic built-in methods.

trans r 0.0 # 0.0 r:++ # 1.0 r:-- # 0.0 r:+ 4.0 # 4.0 r:= 4.0 # 4.0 r:- 1.0 # 3.0 r:* 2.0 # 8.0 r:/ 2.0 # 2.0 r:+= 1.0 # 5.0 r:-= 1.0 # 4.0 r:*= 2.0 # 8.0 r:/= 2.0 # 4.0

### Real comparison

The comparison operators works as the integer one. As for the other operators, an implicit conversion between an integer to a real is done automatically.

== 2000 2000 # true != 2000 1999 # true

Comparison methods are also available for the `Real` object. These methods take either an integer or a real as argument.

r:= 1.0 # 1.0 r:== 1.0 # true r:!= 0.0 # true

### A complex example

One of the most interesting point with functional programming language is the ability to create complex computation function. For example, let's assume we wish to compute the value at a point `x` of the Legendre polynomial of order n. One of the solution is to encode the function given its order. Another solution is to compute the function and then compute the value.

# legendre polynomial order 0 and 1 const lp-0 (gamma (x) 1) const lp-1 (gamma (x) x)

# legendre polynom of order n const lp-n (gamma (n) ( if (> n 1) { const lp-n-1 (lp-n (- n 1)) const lp-n-2 (lp-n (- n 2)) gamma (x) (n lp-n-1 lp-n-2) (/ (- (* (* (- (* 2 n) 1) x) (lp-n-1 x)) (* (- n 1) (lp-n-2 x))) n) } (if (== n 1) lp-1 lp-0) ))

# generate order 2 polynom const lp-2 (lp-n 2)

# print lp-2 (2) println "lp2 (2) = " (lp-2 2)

Note that the computation can be done either with integer or real numbers. With integers, you might get some strange results anyway, but it will work. Note also how the closed variable mechanism is used. The recursion capture each level of the polynom until it is constructed. As an exercise, try to use a lambda expression instead of a gamma one, and compare the execution result with large number of `n`. Note also that we have here a double recursion.

### Other real methods

The real numbers are delivered with a battery of functions. These include the trigonometric functions, the logarithm and couple others. Hyperbolic functions like `sinh`, `cosh`, `tanh`, `asinh`, `acosh` and `atanh` are also supported. The square root `sqrt` method return the square root of the calling real. The `floor` and `ceiling` returns respectively the floor and the ceiling of the calling real.

const r0 0.0 # 0.0 const r1 1.0 # 1.0 const r2 2.0 # 2.0 const rn -2.0 # -2.0 const rq (r2:sqrt) # 1.414213 const pi 3.1415926 # 3.141592

rq:floor # 1.0 rq:ceiling # 2.0 rn:abs # 2.0 r1:log # 0.0 r0:exp # 1.0 r0:sin # 0.0 r0:cos # 1.0 r0:tan # 0.0 r0:asin # 0.0 pi:floor # 3.0 pi:ceiling # 4.0

### Accuracy and formatting

Real numbers are not necessarily accurate, nor precise. The accuracy and precision are highly dependent on the hardware as well as the nature of the operation being performed. In any case, never assume that a real value is an exact one. Most of the time, a real comparison will fail, even if the numbers are very close together. When comparing real numbers, it is preferable to use the `?=` operator. Such operator result is bounded by the internal precision representation and will generally return the desired value. The real precision is an interpreter value which is set with the `set-absolute-precision` method while the `get-absolute-precision` returns the interpreter precision. There is also a `set-relative-precision` and `get-relative-precision` methods used for the definition of relative precision. By default, the absolute precision is set to 0.00001 and the relative precision is set to 1.0E-8.

interp:set-epsilon 0.0001 const r 2.0 const s (r:sqrt) # 1.4142135 (s:?= 1.4142) # true

Real number formatting is another story. The `format` method takes a precision argument which indicates the number of digits to print for the decimal part. Note that the format command might round the result as indicated in the example below.

const pi 3.1415926535 pi:format 3 # 3.142

If additional formatting is needed, the `String` `fill-left` and `fill-right` methods can be used.

const pi 3.1415926535 # 3.1415926535 const val (pi:format 4) # 3.1416 (val:fill-left '0' 9) # 0003.1416

## Character

The `Character` object is another built-in object. A character is internally represented by a quad by using a 31 bit representation as specified by the Unicode standard and ISO 10646.

### Character format

The standard quote notation is used to represent a character. In that respect, there is hare a substantial difference with other functional language where the quote protect a form.

const LA01 'a' # the character a const ND10 '0' # the digit 0

All characters from the Unicode codeset are supported by the engine. The characters are constructed from the literal notation or by using an explicit character instance. The `Character` class offers standard constructors. The default constructor creates a null character. The other constructors take either an integer, a character or a string. The string can be either a single quoted character or the literal notation based on the `U+` notation in hexadecimal. For example, `U+40` is the @ character while `U+3A3` is the sigma capital letter Σ.

const nilc (Character) # null character const a (Character 'a') # a const 0 (Character 48) # 0 const mul (Character "*") # * const div (Character "U+40") # @

### Character arithmetic

A character is like an integer, except that it operates in the range 0 to 0x7FFFFFFF. The character arithmetic is simpler compared to the integer one and no overflow or underflow checking is done. Note that the arithmetic operations take an integer as an argument.

+ 'a' 1 # 'b' - '9' 1 # '8'

Several `Character` object methods are also provided for arithmetic operations in a way similar to the `Integer` class.

trans c 'a' # 'a' c:++ # 'b' trans c '9' # '9' c:-- # '8' c:+ 1 # '9' c:- 9 # '0'

### Character comparison

Comparison operators are also working with the `Character` object. The standard operators are namely equal `==`, not equal `!=`, less than `<`, less equal `<=`, greater `>` and greater equal `>=`. These operators take two arguments.

== 'a' 'b' # false != '0' '1' # true

### Other character methods

The `Character` object comes with additional methods. These are mostly conversion methods and predicates. The `to-string` method returns a string representation of the calling character. The `to-integer` method returns an integer representation the calling character. The predicates are `alpha-p`, `digit-p`, `blank-p`, `eol-p`, `eos-p` and `nil-p`.

const LA01 'a' # 'a' const ND10 '0' # '0' LA01:to-string # "a" LA01:to-integer # 97 LA01:alpha-p # true ND10:digit-p # true

## String

The `String` object is one of the most important built-in object in the engine. Internally, a string is a vector of Unicode characters. Because a string operates with Unicode characters, care should be taken when using composing characters.

### String format

The standard double quote notation is used to represent literally a string. Standard escape sequences are also accepted to construct a string.

const hello "hello"

Any literal object can be used to construct a string. This means that integer, real, boolean or character objects are all valid to construct strings. The default constructor creates a null string. The string constructor can also takes a string.

const nils (String) # "" const one (String 1) # "1" const a (String 'a') # "a" const b (String true) # "true"

### String operations

The `String` object provides numerous methods and operators. The most common ones are illustrated in the example below. The `length` methods returns the total number of characters in the string object. It is worth to note that this number is not necessarily the number of printed characters since some characters might be combining characters used, for example, as diacritics. The `non-combining-length` method might be more adapted to get the number of printable characters.

const h "hello" h:length # 5 h:get 0 # 'h' h:== "world" # false h:!= "world" # true h:+= " world" # "hello world"

The `sub-left` and `sub-right` methods return a sub-string, given the position index. For `sub-left`, the index is the terminating index, while `sub-right` is the starting index, counting from 0.

The `strip`, `strip-left` and `strip-right` are methods used to strip blanks and tabs. The `strip` method combines both `strip-left` and `strip-right`.

The `split` method returns a vector of strings by splitting the string according to a break sequence. By default, the break sequence is the blank, tab and newline characters. The break sequence can be one or more characters passed as one single argument to the method.

The `fill-left` and `fill-right` methods can be used to fill a string with a character up to a certain length. If the string is longer than the length, nothing happens.

# example of sub-left method const msg "hello world" msg:sub-left 5 # "hello" msg:sub-right 6 # "world"

# example of split method const str "hello:world" const vec str:split ":" # "hello" "world" println (vec:length) # 2

# example of fill-left method const pi 3.1415926535 # 3.1415926535 const val (pi:format 4) # 3.1416 val:fill-left '0' 9 # 0003.1416

### String hash value

The `hashid` method is a method that computes the hash value of a string. The value depends on the target machine and will change between a 32 bits and a 64 bits machine. Example example 0203.als illustrates the computation of a hash value for our favorite test string.

# test our favorite string const hello "hello world" hello:hashid # 1054055120

The algorithm used by the engine is shown as an example below. As a side note, it is recommended to print the shift amount in the program. One may notice, that the value remains bounded by 24. Since we are xoring the final value, it does illustrate that the algorithm is design for a 32 bits machine. With a 64 bits machine the algorithm is slightly modified to use the extra space. This also means that the hashid value is not portable across platforms.

# compute string hashid const hashid (s) { const len (s:length) trans cnt 0 trans val 0 trans sht 17 do { # compute the hash value trans i (Integer (s:get cnt)) val:= (val:xor (i:shl sht)) # adjust shift index if (< (sht:-= 7) 0) (sht:+= 24) } (< (cnt:++) len) eval val }