Apa v0.6.9 Apa View Source

APA : Arbitrary Precision Arithmetic - pure Elixir implementation.

For arbitrary precision mathematics - which supports numbers of any size and precision up to nearly unlimited of decimals (internal Elixir integer math), represented as strings. This is especially useful when working with floating-point numbers, as these introduce small but in some case significant rounding errors. Inspired by BCMath/PHP. I started this project to learn for myself - so the focus was on learning and have fun! You could use it if you like - there are some test coverage - but for production I would recomend the Decimal (https://github.com/ericmj/decimal) package!

The 'precision' of a ApaNumber is the total count of significant digits in the whole number, that is, the number of digits to both sides of the decimal point. The 'scale' of a ApaNumber is the count of decimal digits in the fractional part, to the right of the decimal point

You are welcome to read the code and if you find something that could be done better, please let me know.

Link to this section Summary

Functions

APA : Arbitrary Precision Arithmetic - absolut value

APA : Arbitrary Precision Arithmetic - Addition

APA : Arbitrary Precision Arithmetic - Homage to Douglas Adams

Creates a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. cast/1 will returns {:ok, tuple} or {:error, term} - in contrast to new/1 See specific functions for documentation: from_string/1 from_float/1 from_integer/1

APA : Arbitrary Precision Arithmetic - Comparison - ApaComp

APA : Arbitrary Precision Arithmetic - Division

Creates a new ApaNumber tuple from an float. Float first converted via Float.to_string/1 and then parsed. Thats includes a precision limit during Float.to_string/1 - please look at docs there.

Creates a new ApaNumber tuple from an integer. Signed integer are parsed correctly.

Parses a binary (number string) into an ApaNumber tuple.

APA : Arbitrary Precision Arithmetic - Multiplication

Creates a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. See specific functions for documentation: from_string/1 from_float/1 from_integer/1

Parses a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. See specific functions for documentation: from_string/1 from_float/1 from_integer/1

APA : Arbitrary Precision Arithmetic - Subtraction

Output an ApaNumber tuple as a binary (number string). Precision and scale can be used to format or limit the output string.

Link to this section Functions

Link to this function

abs(value)

View Source
abs({integer(), integer()}) :: {integer(), integer()}
abs(integer()) :: integer()
abs(float()) :: float()

APA : Arbitrary Precision Arithmetic - absolut value

Examples

iex> Apa.abs({3, 0}) {3, 0}

iex> Apa.abs({-3, 0}) {3, 0}

iex> Apa.abs({-3, -3}) {3, -3}

iex> Apa.abs({+3, -3}) {3, -3}

iex> abs(-3) 3

Link to this function

add(left, right, precision \\ -1, scale \\ -1)

View Source
add(String.t(), String.t(), integer(), integer()) :: String.t()

APA : Arbitrary Precision Arithmetic - Addition

Examples

iex> Apa.add("1", "2") "3"

iex> Apa.add("1", "-2") "-1"

iex> Apa.add("-1", "2") "1"

iex> Apa.add("-1", "-2") "-3"

iex> Apa.add("999989", "222222") "1222211"

iex> Apa.add("222222", "999989") "1222211"

iex> Apa.add("999", "999989") "1000988"

iex> Apa.add("000000999", "0999989") "1000988"

iex> "1" |> Apa.add("2") |> Apa.add("3.3") |> Apa.add("-3") "3.3"

Compared to standard Elixir - wrong value 6.6! iex> 3.30000000000000004 + 3.30000000000000003 6.6

Correct with APA: iex> Apa.add("3.30000000000000004", "3.30000000000000003") "6.60000000000000007"

iex> Apa.add("3.304","3.300003") "6.604003"

iex> Apa.add("-3.304","-3.300003") "-6.604003"

iex> Apa.add("-3.304","3.300003") "-0.003997"

iex> Apa.add("3.304","-3.300003") "0.003997"

iex> Apa.add("3","3.303") "6.303"

iex> Apa.add("3.303","3") "6.303"

iex> Apa.add("3.303","+003") "6.303"

iex> Apa.add("1","+00120.000") "121"

iex> Apa.add("1.0e2", "1.1") "101.1"

APA : Arbitrary Precision Arithmetic - Homage to Douglas Adams

The Answer to the Ultimate Question of Life, the Universe, and Everything

Examples

iex> Apa.answer("Ultimate Question of Life, the Universe, and Everything") "42"

iex> Apa.answer("Das Leben, das Universum und der ganze Rest") "42"

iex> Apa.answer("six by nine") "forty two"

Link to this function

cast(number)

View Source
cast(binary()) :: {:ok, {integer(), integer()}} | {:error, term()}

Creates a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. cast/1 will returns {:ok, tuple} or {:error, term} - in contrast to new/1 See specific functions for documentation: from_string/1 from_float/1 from_integer/1

Examples

iex> Apa.cast("3") {:ok, {3, 0}}

iex> Apa.cast("test_error")

Link to this function

comp(left, right, precision \\ -1, scale \\ -1)

View Source
comp(String.t(), String.t(), integer(), integer()) :: integer() | Exception

APA : Arbitrary Precision Arithmetic - Comparison - ApaComp

Compares the left_operand to the right_operand and returns the result as an integer.

left - the left operand, as a string. right - the right operand, as a string.

The 'precision' of a ApaNumber is the total count of significant digits in the whole number, that is, the number of digits to both sides of the decimal point. The 'scale' of a ApaNumber is the count of decimal digits in the fractional part, to the right of the decimal point

Returns: 0 if the two operands are equal, 1 if the left_operand is larger than the right_operand, -1 otherwise.

Examples

iex> Apa.comp("9", "3") 1

iex> Apa.comp("3", "9") -1

iex> Apa.comp("999999999999999999999999999","999999999999999999999999999") 0

iex> Apa.comp("0","0") 0

iex> Apa.comp("+0","-0") 0

iex> Apa.comp("-0","-0") 0

iex> Apa.comp("+1","-1") 1

iex> Apa.comp("1.0","1.0") 0

iex> Apa.comp("-1","-1.0") 0

Compared to standard Elixir this is fixed with APA - it is -1 !!! iex> Apa.comp("12","12.0000000000000001") -1

Compared to standard Elixir this is fixed with APA - it is 1 !!! iex> Apa.comp("3.30000000000000004", "3.30000000000000003") 1

iex> Apa.comp("1.1", "1.0") 1

iex> Apa.comp("1.0", "1.1") -1

iex> Apa.comp("1.0", "1.1", 0, 1) -1

iex> Apa.comp("1.0", "1.1", 0, 0) 0

Link to this function

div(left, right, precision \\ -1, scale \\ -1)

View Source
div(String.t(), String.t(), integer(), integer()) :: String.t()

APA : Arbitrary Precision Arithmetic - Division

Examples

iex> Apa.div("6", "2") "3"

iex> Apa.div("6", "3") "2"

iex> Apa.div("6", "-3") "-2"

iex> Apa.div("-6", "3") "-2"

iex> Apa.div("-6", "-3") "2"

iex> "18" |> Apa.div("2") |> Apa.div("3") "3"

iex> Apa.div("222.2001", "2222.001") "0.1"

Link to this function

from_float(float)

View Source
from_float(float()) :: {integer(), integer()} | :error

Creates a new ApaNumber tuple from an float. Float first converted via Float.to_string/1 and then parsed. Thats includes a precision limit during Float.to_string/1 - please look at docs there.

Examples

iex> Apa.from_float(-3.21) {-321, -2}

Link to this function

from_integer(int)

View Source
from_integer(integer()) :: {integer(), 0} | :error

Creates a new ApaNumber tuple from an integer. Signed integer are parsed correctly.

Examples

iex> Apa.parse(3) {3, 0}

iex> Apa.parse(-3) {-3, 0}

Link to this function

from_string(binary)

View Source
from_string(binary()) :: {integer(), integer()} | :error

Parses a binary (number string) into an ApaNumber tuple.

It works with signs, leading and trailing zeros and additional chars will be ignored. If successful, returns a tuple in the form of {integer_value, exponent}:

Apa.from_string("+0003.00e+00000 Dollar") {3, 0}

When the binary cannot be parsed, the atom :error will be returned.

The limit only depends on the internal integers - because of Elixir "unlimited" integers I would say "arbitrary".

Used elixir source from Float module for parsing - nice source of inspiration! Thank you José!

Examples

iex> Apa.from_string("0003") {3, 0}

iex> Apa.from_string("+0003") {3, 0}

iex> Apa.from_string("-0003") {-3, 0}

iex> Apa.from_string("-0000120.1200") {-12012, -2}

iex> Apa.from_string("-0000120.1200") {-12012, -2}

iex> Apa.from_string("-03 Euro") {-3, 0}

iex> Apa.from_string("-0003e-2") {-3, -2}

iex> Apa.from_string("-3e-0002") {-3, -2}

iex> Apa.from_string("3e-12") {3, -12}

iex> Apa.from_string("+0003e+12") {3, 12}

iex> Apa.from_string("+0003e+00000") {3, 0}

iex> Apa.from_string("+0003.00e+00000 Dollar") {3, 0}

Link to this function

mul(left, right, precision \\ -1, scale \\ -1)

View Source
mul(String.t(), String.t(), integer(), integer()) :: String.t()

APA : Arbitrary Precision Arithmetic - Multiplication

Examples

iex> Apa.mul("3", "2") "6"

iex> Apa.mul("2", "3") "6"

iex> Apa.mul("2", "-3") "-6"

iex> Apa.mul("-2", "3") "-6"

iex> Apa.mul("-2", "-3") "6"

iex> "1" |> Apa.mul("2") |> Apa.mul("3") "6"

Link to this function

new(number)

View Source
new(term()) :: {integer(), integer()} | :error

Creates a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. See specific functions for documentation: from_string/1 from_float/1 from_integer/1

Examples

iex> Apa.new("3") {3, 0}

Link to this function

parse(number)

View Source
parse(binary()) :: {integer(), integer()} | :error

Parses a new ApaNumber tuple from an integer, string, float, or existing ApaNumber. See specific functions for documentation: from_string/1 from_float/1 from_integer/1

Examples

iex> Apa.parse("3") {3, 0}

Link to this function

sub(left, right, precision \\ -1, scale \\ -1)

View Source
sub(String.t(), String.t(), integer(), integer()) :: String.t()

APA : Arbitrary Precision Arithmetic - Subtraction

Examples

iex> Apa.sub("3", "2") "1"

iex> Apa.sub("2", "3") "-1"

iex> Apa.sub("2", "+3") "-1"

iex> Apa.sub("2", "-3") "5"

iex> Apa.sub("-2", "3") "-5"

iex> "1" |> Apa.sub("2") |> Apa.add("3.30") |> Apa.sub("2.40") "-0.1"

Compared to standard Elixir - wrong value 0.0! iex> 3.30000000000000004 - 3.30000000000000003 0.0

this is fixed with APA: iex> Apa.sub("3.30000000000000004", "3.30000000000000003") "0.00000000000000001"

Link to this function

to_string(number_tuple, precision \\ -1, scale \\ -1)

View Source
to_string({integer(), integer()}, integer(), integer()) :: binary() | :error

Output an ApaNumber tuple as a binary (number string). Precision and scale can be used to format or limit the output string.

Examples

iex> Apa.to_string({3, 0}) "3"

iex> Apa.to_string({-3, -1}) "-0.3"

iex> Apa.to_string({-3, 0}) "-3"

iex> Apa.to_string({3, 3}) "3000"

iex> Apa.to_string({-12012, -2}) "-120.12"

iex> Apa.to_string({-3997, -6}) "-0.003997"