# Math Library

The definitions provided by this library operate on numbers or streams of numbers providing statistics or other mathematical evaluations.

## Functions

Many of the functions here are implemented in Perl. The definitions are examples of how some of these might be implemented in Dallycot.

### abs

(x: Numeric) → Numeric

Returns the absolute value of a numeric datum.

#### Examples

```
abs(-1) = 1
abs(0) = 0
abs(1) = 1
```

#### Implementation

This is implemented natively.

```
(x) :> (
(x < 0) : -x
( ) : x
)
```

### arc-tan

(y: Numeric, x: Numeric, units -> “degrees”, accuracy -> 40) → Numeric

#### Implementation

This is implemented natively.

### binomial

(n: Numeric, k: Numeric) → Numeric

Returns the binomial coefficient
*n* over *k*. The binomial coefficient can be used to generate
Pascal’s Triangle.

#### Examples

##### Boundary conditions

When the second argument is zero or when both arguments are the same value,
the `binomial`

is one.

```
binomial(n, 0) = 1
binomial(n, n) = 1
```

##### Fourth row of Pascal’s Triangle

The first five rows of the triangle are:

```
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
```

The fourth row (starting at zero) is then:

```
binomial(4, 0) = 1
binomial(4, 1) = 4
binomial(4, 2) = 6
binomial(4, 3) = 4
binomial(4, 4) = 1
```

#### Implementation

This is implemented natively.

```
(n, k) :> factorial(n) div ( factorial(k) * factorial(n - k) )
```

### ceil

(x: Numeric) → Numeric

Returns the smallest integer greater than or equal to the given number.

#### Examples

```
ceil(1.23) = 2
ceil(-1.23) = -1
ceil(1) = 1
ceil(-1) = -1
```

#### Implementation

This is implemented natively.

### cos

(angle: Numeric, units -> “degrees”, accuracy -> 40) → Numeric

Calculates the cosine of an angle. The `units`

may be `degrees`

, `radians`

, or `gradians`

. The calculation will be done to `accuracy`

digits.

#### Examples

```
cos(90) = 0
cos(60) = 1/2
cos(0) = 1
cos(89, accuracy -> 3) = 7/400
cos(89, accuracy -> 3, units -> "radians") = 841/1000
```

#### Implementation

This is implemented natively.

### count-and-sum

(s: [Numeric]) → [<Numeric, Numeric>]

Returns a stream of duples (count and sum) produced by counting and summing each element in the input stream.

#### Examples

```
count-and-sum(1..) = [ <1,1>, <2,3>, <3,6>, <4,10>, <5,15>, <6,21>, ... ]
count-and-sum(primes) = [ <1,1>, <2,3>, <3,6>, <4,11>, <5,18>, ... ]
```

#### Implementation

```
foldl(
<0,0>,
(
(pad, element) :> <pad[1] + 1, pad[2] + element>
),
_
)
```

### differences

(s: [Numeric]) → [Numeric]

Returns a stream of numbers representing the difference between successive elements in the input numeric stream.

#### Examples

```
differences(1..) = [ -1, -1, -1, ... ]
differences(primes) = [ -1, -1, -2, -2, -4, -2, ... ]
```

#### Implementation

```
(
diff := y-combinator(
(self, sh, st) :> (
(?sh and ?st) : [ sh - st', self(self, st', st...) ]
(?sh ) : [ sh ]
( ) : [ ]
)
);
{ diff(#', #...) }
)
```

### divisible-by?

(n: Numeric, d: Numeric) → Boolean

Returns `true`

if the numerator (*n*) is divisible by the denominator (*d*).

#### Examples

```
divisible-by?(10, 3) = false
divisible-by?(123, 3) = true
divisible-by?(3, 1) = true
divisible-by?(1, 3) = false
```

#### Implementation

This is implemented natively.

```
(n, d) :> n mod d = 0
```

### even?

(x: Numeric) → Boolean

Returns `true`

if the given number is even.

#### Examples

```
even? @ 1.. = [ false, true, false, true, false, true, ... ]
even?(123) = false
even?(0) = true
even?(1.23) = false
```

#### Implementation

This is implemented natively.

```
divisible-by?(_, 2)
```

### factorial

(n: Numeric) → Numeric

Calculates the factorial (*n!*) of a number.

#### Examples

```
factorial(1) = 1
factorial(3) = 6
factorial @ 1.. = [ 1, 2, 6, 24, 120, 720, ... ]
```

#### Implementation

This is implemented natively.

```
(n) :> (
(n > 1) : last(product(2..n))
(n = 1) : 1
( ) : 0
)
```

### fibonacci

(n: Numeric) → Numeric

#### Implementation

```
(n) :> fibonacci-sequence[n]
```

### floor

(x: Numeric) → Numeric

Returns the largest integer less than or equal to the given number.

#### Examples

```
floor(1.23) = 1
floor(1) = 1
floor(-1) = -1
floor(-1.23) = -2
```

#### Implementation

This is implemented natively.

### gcd

(*x: Numeric) → Numeric

Calculates the greatest common divisor shared by two or more numbers.

#### Examples

```
gcd(63, 42) = 21
gcd(64, 42) = 2
gcd(65, 42) = 1
```

#### Implementation

This is implemented natively.

For two arguments, this is equivalent to the following:

```
y-combinator(
(self, a, b) :> (
(a = 0) : b
(b = 0) : a
(a > b) : self(self, a mod b, b)
( ) : self(self, a, b mod a)
)
)
```

### golden-ration

(accuracy: Numeric = 40) → Numeric

Provides a numerical approximation of phi, the golden ration, to the desired accuracy. Defaults to 40 digits.

#### Examples

```
golden-ratio(1) = 2
golden-ratio(2) = 8/5
golden-ratio(3) = 81/50
golden-ratio(9) = 161803399/100000000
```

#### Implementation

This is implemented natively.

```
(accuracy) :>
(1 + sqrt(5, accuracy -> accuracy)) / 2
```

### lcm

(*x: Numeric) → Numeric

Calculates the least common multiple of two or more numbers.

#### Examples

```
lcm(63, 42) = 126
lcm(64, 42) = 1344
lcm(65, 42) = 2730
```

#### Implementation

This is implemented natively.

For two arguments, this is equivalent to:

```
(x, y) :> x * y div gcd(x,y)
```

### leonardo

#### Implementation

```
(n) :> leonardo-sequence[n]
```

### make-evens

() → [ 2, 4, 6, … ]

Creates a new stream consisting of the positive, non-zero even integers.

This is useful when you need a stream of even numbers and want to garbage collect the stream after using it.

#### Examples

```
make-evens() = [ 2, 4, 6, ... ]
```

#### Implementation

```
() :> ({ # * 2 } @ 1..)
```

### make-odds

() → [ 1, 3, 5, … ]

Creates a new stream consisting of the positive, non-zero even integers.

This is useful when you need a stream of odd numbers and want to garbage collect the stream after using it.

#### Examples

```
make-odds() = [ 1, 3, 5, ... ]
```

#### Implementation

```
() :> ({ # * 2 + 1} @ 0..)
```

### max

(s: [Numeric]) → [Numeric]

Given a stream of numbers, `max`

returns a new stream representing the maximum
number seen up to that point in the input stream.

#### Examples

```
max(primes) = primes
max(1..) = 1..
max([1,3,5,3,1]) = [ 1, 3, 5, 5, 5 ]
```

#### Implementation

```
foldl1({(
(#1 > #2) : #1
( ) : #2
)}/2, _)
```

### mean

(s: [Numeric]) → [Numeric]

Given a stream of numbers, `mean`

returns a new stream representing the mean of
the numbers seen up to that point in the input stream.

#### Examples

```
mean([1, 3, 5, 3, 1]) = [ 1, 2, 3, 3, 13/5 ]
mean(1..) = [ 1, 3/2, 2, 5/2, 3, ... ]
```

#### Implementation

```
{ #[2] div #[1] } @ count-and-sum
```

### min

(s: [Numeric]) → [Numeric]

Given a stream of numbers, `min`

returns a new stream representing the minimum
number seen up to that point in the input stream.

#### Examples

```
min(primes) = [ 1, 1, 1, ... ]
min(1..) = [ 1, 1, 1, ... ]
min([1,3,5,3,1]) = [ 1, 1, 1, 1, 1 ]
min([-1, -3, -5, -3, -1]) = [ -1, -3, -5, -5, -5 ]
```

#### Implementation

```
foldl1({(
(#1 < #2) : #1
( ) : #2
)}/2, _)
```

### odd?

(x: Numeric) → Boolean

Returns `true`

if the given number is odd.

#### Examples

```
odd? @ 1.. = [ true, false, true, false, true, false, ... ]
odd?(123) = true
odd?(0) = false
odd?(1.23) = false
```

#### Implementation

This is implemented natively.

```
~even?
```

### pi

(accuracy: Numeric = 40) → Numeric

Provides a numerical approximation of PI to the desired accuracy. Defaults to 40 digits.

#### Examples

```
pi(1) = 3
pi(2) = 31/10
pi(3) = 157/50
pi(9) = 62831853/20000000
```

#### Implementation

This is implemented natively.

### prime

(n: Numeric) → Numeric

#### Implementation

```
(n) :> primes[n]
```

### product

(s: [Numeric]) → [Numeric]

Transforms a stream of numbers into a stream of cumulative products.

#### Examples

```
product(1..) = [ 1, 2, 6, 24, 120, ... ]
product(primes) = [ 1, 2, 6, 30, 180, ... ]
product([1, 3, 5, 3, 1]) = [ 1, 3, 15, 45, 135, 135 ]
```

#### Implementation

```
foldl(1, { #1 * #2 }/2, _)
```

### random

(spec: Numeric|<Numeric,Numeric>) → Numeric

Creates a pseudo-random integer up to the number given or in the range given by a vector of numbers. The upper bound must be greater than zero.

#### Examples

```
0 <= random(10) <= 10
20 <= random(<20,40>) <= 40
```

#### Implementation

This is implemented natively.

### sin

(angle: Numeric, units -> “degrees”, accuracy -> 40) :> Numeric

Calculates the sine of an angle. The `units`

may be `degrees`

, `radians`

, or `gradians`

. The calculation will be done to `accuracy`

digits.

#### Examples

```
sin(0) = 0
sin(30) = 1/2
sin(90) = 1
sin(1, accuracy -> 3) = 7/400
sin(1, accuracy -> 3, units -> "radians") = 841/1000
```

#### Implementation

This is implemented natively.

### sum

(s: [Numeric]) → [Numeric]

Transforms a stream of numbers into a stream of cumulative sums.

#### Examples

```
sum(1..) = [ 1, 3, 6, 10, 15, ... ]
sum(primes) = [ 1, 3, 6, 11, 18, ... ]
sum([1, 3, 5, 3, 1]) = [ 1, 4, 9, 12, 13 ]
```

#### Implementation

```
foldl(0, { #1 + #2 }/2, _)
```

### tan

(angle: Numeric, units -> “degrees”, accuracy -> 40) :> Numeric

Calculates the tangent of an angle. The `units`

may be `degrees`

, `radians`

, or `gradians`

. The calculation will be done to `accuracy`

digits.

#### Examples

```
sin(0) = 0
sin(30) = 1/2
sin(90) = 1
sin(1, accuracy -> 3) = 7/400
sin(1, accuracy -> 3, units -> "radians") = 841/1000
```

#### Implementation

```
(angle, units -> "degrees", accuracy -> 40) :> (
sin(angle, units -> units, accuracy -> accuracy) div
cos(angle, units -> units, accuracy -> accuracy)
)
```

### weighted-count-and-sum

(s: [<Numeric, Numeric>]) → [<Numeric, Numeric>]

Transforms a stream of duples (weight and number) into a stream of duples containing the sum of weights and sum of weighted numbers.

#### Examples

Assuming we have a gradebook with the following grade distribution:

A (4 pts) | 4 |

B (3 pts) | 9 |

C (2 pts) | 15 |

D (1 pts) | 8 |

F (0 pts) | 2 |

then we can calculate the class average:

```
mean @ weighted-count-and-sum([<4, 4>, <9, 3>, <15, 2>, <8, 1>, <2, 0>])
= mean @ [ <4, 16>, <13, 43>, <28, 73>, <36, 81>, <38, 81> ]
= [ 4, 43/13, 73/28, 9/4, 81/38 ]
```

Dallycot uses rationals for all numbers, so the final average for the class is around 2.131 (the sequence in floating point numbers: [ 4, 3.307, 2.607, 2.250, 2.131] ).

#### Implementation

```
foldl(
<0,0>,
((pad, element) :>
<pad[1] + element[1], pad[2] + element[1] * element[2]>
),
_
)
```

## Streams

### evens

#### Implementation

```
make-evens()
```

### factorials

#### Implementation

```
factorial @ 1..
```

### fibonacci-sequence

#### Implementation

```
[ 1,
1,
y-combinator(
(self, a, b) :>
[ a + b, self(self, b, a + b) ]
)(1, 1)
]
```

### leonardo-sequence

#### Implementation

```
[ 1,
1,
y-combinator(
(self, a, b) :>
[ a + b + 1, self(self, b, a + b + 1) ]
)(1, 1)
]
```

### odds

#### Implementation

```
make-odds()
```

### primes

#### Implementation

```
[ 1,
2,
y-combinator(
(self, s) :>
[ s', self(self, ~divisible-by?(_, s') % s...) ]
)(make-odds()...)
]
```

### twin-primes

#### Implementation

```
{ #[2] - #[1] = 2 } % (primes Z primes...)
```