## mapm

### Description

Binding to Mike's Arbitrary Precision Math Library.

### Author

### Requirements

None

### Download

### Installation

- Download the MAPM source package, using the link near the bottom of the MAPM home page. Get the file called
`mapm-X.Y.Z.tar.gz`,**not**the one labeled "COMPLEX Numbers". At the time of writing, I used`mapm-4.9.1.tar.gz`. - Unpack it and compile.

% tar zxf mapm-4.9.1.tar.gz % cd mapm_4.9.1 % make

- Install
`libmapm.a`and`m_apm.h`where your compiler can find them.

% cp libmapm.a /usr/local/lib % cp m_apm.h /usr/local/include

- Now install
`mapm.egg`.

% cd /tmp % chicken-setup mapm

### Documentation

The API provided by this egg is similar to MAPM for C. The main difference is that arbitrary precision value objects (MAPM values) feel more like native numbers -- once created, they are immutable. The following documentation is derived largely from MAPM's documentation. Note that MAPM is *not* thread-safe.

#### Precision

*[parameter]*

`apm-precision`

The desired precision for most operations is stored in this parameter; the only exception being `apm-round`. The default precision is 15 (arbitrarily chosen).

*[constant]*

`mm-0`

*[constant]*

`mm-1`

*[constant]*

`mm-2`

*[constant]*

`mm-3`

*[constant]*

`mm-4`

*[constant]*

`mm-5`

*[constant]*

`mm-10`

*[constant]*

`mm-pi`

*[constant]*

`mm-pi/2`

*[constant]*

`mm-2*pi`

*[constant]*

`mm-e`

*[constant]*

`mm-log-e-base-10`

*[constant]*

`mm-log-10-base-e`

*[constant]*

`mm-log-2-base-e`

*[constant]*

`mm-log-3-base-e`

Convenient predefined constants (each is a MAPM value).

#### Library version

*[procedure]*

`(mapm-lib-version)`

*[procedure]*

`(mapm-lib-short-version)`

These two functions return the version of the MAPM C library when it was compiled as a string.

#### Number object creation

*[procedure]*

`(apm NUMBER-or-STRING)`

Make a new *mapm-object*; an arbitrary precision value object from fixnum, flonum, or string.

#### String conversion procedures

*[procedure]*

`(apm->string NUM)`

This function will convert an MAPM value into a string and is meant to be used with floating point MAPM values. The output string will always be in scientific (exponential) notation. There will be a leading `'-'` sign for negative numbers. There will be `apm-precision` number of digits after the decimal point.

If `apm-precision` is >= 0, the value will be rounded to that number of digits and then the string will be filled, with trailing zero's appended if necessary to fill out the decimal place specification.

If `apm-precision` < 0, *all* the significant digits of the MAPM number will be output. In some applications, it is convienent to round the value yourself (see `apm-round`) and then display *all* the digits.

*[procedure]*

`(apm->fixpt-string NUM)`

This function will convert an MAPM value into a string and the output will be formatted in fixed point notation.

If `apm-precision` < 0, *all* the significant digits of the MAPM number will be output.

If `apm-precision` = 0, the output will be the MAPM value rounded to the nearest integer and the decimal point will be suppressed.

If `apm-precision` is > 0, the value will be rounded to that number of digits and then the string will be filled, with trailing zero's appended if necessary to fill out the decimal place specification.

In some applications, it is convienent to round the value yourself (see `apm-round`) and then display *all* the digits.

*[procedure]*

`(apm->fixpt-string-exp NUM RADIX SEPARATOR-CHAR SEPARATOR-COUNT)`

This function is an extended version of the previous function, there are three additional function parameters:

`radix`- Specify the radix character desired. For example, use
`#\,`to set the radix char to a comma. `separator-char``separator-count`- Specify a character separator every
*separator-count*characters. This is used to split up a large number with a 'delimiter' for easier readability. For example,

If `separator-char` = `','` and `separator-count` = `3`, there will be a comma inserted before every group of 3 digits in the output string.

`6123456789.098765321` will be formatted as `"6,123,456,789.098765321"`

Note that only digits before the radix char are separated.

`separator-char` = `(integer-char 0)` or `separator-count` = `0` is used to disable the 'char separator' feature. This would typically be used when it is only desired to change the radix character.

*[procedure]*

`(apm->integer-string NUM)`

This function will convert an MAPM value into a string and is meant to be used with integer values. If the MAPM number is not an integer, the function will truncate the value to the nearest integer and the output will be formatted as an integer, with a possible leading '`-`' sign.

#### Predicates

*[procedure]*

`(apm-zero? NUM)`

*[procedure]*

`(apm-positive? NUM)`

*[procedure]*

`(apm-negative? NUM)`

*[procedure]*

`(apm-integer? NUM)`

*[procedure]*

`(apm-even? NUM)`

*[procedure]*

`(apm-odd? NUM)`

These do what you think they do.

#### Other query procedures

*[procedure]*

`(apm-significant-digits NUM)`

This function will return the number of significant digits in NUM.

#### Comparison

*[procedure]*

`(apm= NUM1 NUM2)`

*[procedure]*

`(apm< NUM1 NUM2)`

*[procedure]*

`(apm> NUM1 NUM2)`

*[procedure]*

`(apm<= NUM1 NUM2)`

*[procedure]*

`(apm>= NUM1 NUM2)`

These do what you think they do.

The following are more low-level variants:

*[procedure]*

`(apm-compare NUM1 NUM2)`

This function will compare the value of NUM1 to NUM2. The function will return:

-1 : num1 < num2 0 : num1 = num2 1 : num1 > num2

*[procedure]*

`(apm-sign NUM)`

This function will return the sign of NUM. The function will return:

-1 : num < 0 0 : num = 0 1 : num > 0

#### Exponent and logarithmic procedures

*[procedure]*

`(apm-sqrt NUM)`

This function will return the square root of NUM.

An input less than zero returns a zero result and creates a warning on stderr.

*[procedure]*

`(apm-cbrt NUM)`

This function will return the cube root of NUM.

*[procedure]*

`(apm-log NUM)`

This function will return the natural log (base 2.718 ...) of NUM.

An input <= zero returns a zero result and creates a warning on stderr.

*[procedure]*

`(apm-log10 NUM)`

This function will return the common log (base 10) of NUM.

An input <= zero returns a zero result and creates a warning on stderr.

*[procedure]*

`(apm-exponent NUM)`

This function will return the exponent of NUM.

*[procedure]*

`(apm-exp NUM)`

This function will return e^{NUM} where 'e' is 2.718... (the exponential function).

If the input to this function is too large, there will be a warning on stderr and the result will be zero.

*[procedure]*

`(apm-expt X Y)`

This function will raise X to the Y power.

If Y is an integer value, `m_apm_integer_pow` -- the C function that underlies `apm-integer-expt` will be called automatically. (see the next function description).

>X must be >= zero.

*[procedure]*

`(apm-integer-expt X I)`

This function will raise X to the I power.

If calculating X^{Y}, this function should be used when 'Y' is an integer. This function is considerably faster than the generic `apm-expt` function (when I is not excessively large). X and/or I may be negative.

See the following function for a 'pow' function that does not perform any rounding operation and is more appropriate for integer only applications.

Note that I is an integer and not a MAPM number.

*[procedure]*

`(apm-integer-expt/unrounded X I)`

This function will raise X to the I power.

This function is similiar to the above function except the result is **not rounded**. This function would typically be used is an integer only application where the full precision of the result is desired.

Note that I is an integer and not a MAPM number.

I must be >= zero. I < 0 returns a zero result and creates a warning on stderr.

#### Arithmetic procedures

*[procedure]*

`(apm+ NUM1 NUM2)`

*[procedure]*

`(apm- NUM1 NUM2)`

*[procedure]*

`(apm* NUM1 NUM2)`

*[procedure]*

`(apm/ NUM1 NUM2)`

*[procedure]*

`(apm-reciprocal NUM)`

*[procedure]*

`(apm-quotient NUM1 NUM2)`

These do what you think they do.

*[procedure]*

`(apm-integer-div-rem NUM1 NUM2)`

This function will divide NUM1 by NUM2, truncating the result to an integer and returning the quotient and remainder as two values.

Note that the input numbers do not necessarily have to be integers. This function can be used to split up the integer portion and fractional portion of a floating point number by calling the function with `mm-1` as NUM2.

Division by zero returns a zero result and create a warning on stderr.

*[procedure]*

`(apm-remainder NUM1 NUM2)`

Shorthand for getting the remainder out of an `apm-integer-div-rem` call.

*[procedure]*

`(apm-abs NUM)`

Returns the absolute value of NUM.

*[procedure]*

`(apm-negate NUM)`

Returns the negated value of NUM.

*[procedure]*

`(apm-round N NUM)`

Rounds the value of NUM to the number of decimal places specified by N. The decimal places parameter is referenced to the number when the number is in scientific notation.

*[procedure]*

`(apm-factorial NUM)`

This function will return the factorial of NUM.

A non-integer input will yield nonsense. Actually, the algorithm simply multiplies: (although `0!` and `1!` return `1`)

N * (N - 1) * (N - 2) ... until N < 2

*[procedure]*

`(apm-floor NUM)`

This function will round NUM downwards to the nearest integer and return the result.

*[procedure]*

`(apm-ceiling NUM)`

This function will round NUM upwards to the nearest integer and return the result.

*[procedure]*

`(apm-gcd NUM1 NUM2)`

This function will return the GCD (greatest common divisor) of NUM1 and NUM2.

Non-integer inputs will return a zero result and create a warning on stderr.

*[procedure]*

`(apm-lcm NUM1 NUM2)`

This function will return the LCM (least common multiple) of NUM1 and NUM2.

Non-integer inputs will return a zero result and create a warning on stderr.

#### Trigonometric procedures

*[procedure]*

`(apm-sin NUM)`

*[procedure]*

`(apm-cos NUM)`

These functions will return the sine/cosine of NUM. The input is in radians.

*[procedure]*

`(apm-sin-cos NUM)`

This function computes the sin and cos of NUM and it will be more efficient than calling each function separately.

*[procedure]*

`(apm-tan NUM)`

This function will return the tangent of NUM. The input is in radians.

*[procedure]*

`(apm-asin NUM)`

This function will return the arc sine of NUM. The angle returned is in the range -π/2 to +π/2.

|Input| > 1 returns a zero result and creates a warning on stderr.

*[procedure]*

`(apm-acos NUM)`

This function will return the arc cosine of NUM. The angle returned is in the range 0 to +π.

|Input| > 1 returns a zero result and creates a warning on stderr.

*[procedure]*

`(apm-atan NUM)`

This function will return the arc tangent of NUM. The angle returned is in the range -π/2 to +π/2.

*[procedure]*

`(apm-atan2 X Y)`

This function will return the 4 quadrant arc tangent of Y and X. The angle returned is in the range -π to

+π. The function will determine the quadrant based on the signs of the 2 inputs.

x, y both equal to zero will yield a zero result and a warning on stderr.

*[procedure]*

`(apm-sinh NUM)`

*[procedure]*

`(apm-cosh NUM)`

*[procedure]*

`(apm-tanh NUM)`

These functions will return the hyperbolic sine, cosine and tangent of NUM respectively.

*[procedure]*

`(apm-asinh NUM)`

This function will return the hyperbolic arc-sin of NUM.

*[procedure]*

`(apm-acosh NUM)`

This function will return the hyperbolic arc-cos of NUM.

Input < 1 creates a zero result and a warning on stderr.

*[procedure]*

`(apm-atanh NUM)`

This function will return the hyperbolic arc-tan of NUM.

|Input| > 1 creates a zero result and a warning on stderr.

#### Random number generation procedures

*[procedure]*

`(apm-set-random-seed! NUMBER-or-STRING)`

This function will set the randon number generator to a known starting value. The seed argument should correspond to any *integer* value between 0 and (1.0E+15 - 1). It may be a native chicken number or a string (**not** a MAPM value).

*[procedure]*

`(apm-get-random)`

This function will return a random floating point number between the values 0 and 1. The first time the function is called the generator is initialized with the system time. This generator will not repeat its pattern until 1.0E+15 numbers have been generated.

### Examples

Calculate Fibonacci numbers:

(require 'mapm) (define(fib n) (letlp ((i 0) (a mm-0) (b mm-1)) (if(= i n) (apm+ a b) (lp (+ i 1) (apm+ a b) a)))) (print (apm->integer-string (fib 10000)))

Calculate π:

(require 'mapm) ;;; Calculate PI using the Borwein's Quartically Convergent Algorithm ;;; Ported from PI_2.CPP of the MAPM distribution (define(compute-pi places) (let([dplaces (+ places 16)]) ; compute a few extra digits in the intermediate math (parameterize ([apm-precision dplaces]) (let([+ apm+] [- apm-] [* apm*] [/ apm/] [zero? apm-zero?] [sqrt apm-sqrt] [round apm-round] [mm-0.5 (apm 0.5)]) (round places (letlp ([u0 (sqrt mm-2)] [b0 mm-0] [p0 (+ mm-2 (sqrt mm-2))] [count 1] [last #f]) (let*([sqrt-u0 (sqrt u0)] [u1 (* mm-0.5 (+ sqrt-u0 (apm-reciprocal sqrt-u0)))] [b1 (/ (* sqrt-u0 (+ mm-1 b0)) (+ u0 b0))] [p1 (/ (* (* p0 b1) (+ mm-1 u1)) (+ mm-1 b1))]) (iflast p1 (let([diff (- p1 p0)]) ; compute the difference from this iteration to the last one. (if(and (fx>= count 4) (zero? diff)) ; if diff == 0, we're done. p1 (lp (round dplaces u1) (round dplaces b1) (round dplaces p1) (fx+ count 1) ;; if the exponent of the error term (small error like 2.47...E-65) ;; is small enough, break out after the *next* p1 is calculated. (fx>= (fx* -4 (apm-exponent diff)) dplaces)))))))))))) (let((p 200)) (apm-precision p) (print (apm->fixpt-string (compute-pi p))))

### Changelog

- 1.1 Adapted to new setup scheme
- 1.0 Initial release

### License

Do whatever you like with it.