dwayne / elm-natural / Natural

Compute with the natural numbers, ℕ = { 0, 1, 2, ... }.

Representation


type Natural

A representation of the natural numbers.

N.B. The size of the numbers you can compute with is only limited by the available memory.

Constants

The natural numbers from 0 to 10 inclusive are named.

zero : Natural

The natural number 0.

To be more precise, it is a representation of the natural number 0. However, I will not have any cause to make that distinction. A similar remark can be made about the other constants.

one : Natural

The natural number 1.

two : Natural

The natural number 2.

three : Natural

The natural number 3.

four : Natural

The natural number 4.

five : Natural

The natural number 5.

six : Natural

The natural number 6.

seven : Natural

The natural number 7.

eight : Natural

The natural number 8.

nine : Natural

The natural number 9.

ten : Natural

The natural number 10.

Limits

Let n : Int. If 0 <= n <= maxSafeInt then n is called a safe Int.

maxSafeInt : Basics.Int

The largest Int, currently 2^53 - 1 = 9007199254740991, which can be given as input to fromSafeInt and fromInt without causing problems.

Constructors

fromSafeInt : Basics.Int -> Natural

Use this function when you know the given Int is a safe Int.

fromSafeInt 0 == zero

fromSafeInt 1 == one

fromSafeInt maxSafeInt == fromSafeString "9007199254740991"

If the given Int isn't safe then zero is returned.

fromSafeInt -1 == zero

fromSafeInt (maxSafeInt + 1) == zero

This function is useful for establising small constants in a calculation. For e.g. to compute the first 100 digits of π using John Machin's formula the natural number 239 is needed.

twoThirtyNine : Natural
twoThirtyNine =
    fromSafeInt 239

fromInt : Basics.Int -> Maybe Natural

Create the natural number that represents the given Int.

fromInt 0 == Just zero

fromInt 1 == Just one

fromInt maxSafeInt == fromString "9007199254740991"

Unless the given Int is negative or greater than maxSafeInt.

fromInt -1 == Nothing

fromInt (maxSafeInt + 1) == Nothing

fromSafeString : String -> Natural

It's best to use this function when you can guarantee that the string you're dealing with is a valid input to the fromString function.

If the input is invalid then zero is returned.

N.B. Read the documentation of fromString to learn what's considered to be valid or invalid input to this function.

This function is useful for establishing large constants in a calculation.

oneGoogol : Natural
oneGoogol =
    -- 10 ^ 100
    fromSafeString "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

Learn more about a googol.

What's considered a large constant?

Let n : Int, since fromSafeInt n can be used for 0 <= n <= maxSafeInt then it makes sense to consider any natural number larger than maxSafeInt, a large constant.

fromString : String -> Maybe Natural

Create the natural number represented by the given string.

Syntax for fromString input

input    ::= unsigned
unsigned ::= ('0b' | '0B') binary
           | ('0o' | '0O') octal
           | ('0x' | '0X') hex
           | decimal
binary   ::= [0-1]+
octal    ::= [0-7]+
hex      ::= [0-9a-fA-F]+
decimal  ::= [0-9]+

For e.g.

fromString "0b10101101" == fromInt 173

fromString "0o255" == fromInt 173

fromString "0XaD" == fromInt 173

fromString "173" == fromInt 173

fromString "b10101101" == Nothing
-- Because the leading '0' is missing.

fromString "aD" == Nothing
-- Because 'a' is not a decimal digit.

fromString "0x" == Nothing
-- Because there must be at least one hexadecimal digit.

fromBinaryString : String -> Maybe Natural

Create the natural number represented by the given binary string.

binary ::= [0-1]+

For e.g.

fromBinaryString "0" == Just zero

fromBinaryString "1010" == Just ten

fromBinaryString "" == Nothing
-- Because the string is empty.

fromBinaryString "2" == Nothing
-- Because '2' is not a binary digit.

fromOctalString : String -> Maybe Natural

Create the natural number represented by the given octal string.

octal ::= [0-7]+

For e.g.

fromOctalString "0" == Just zero

fromOctalString "12" == Just ten

fromOctalString "" == Nothing
-- Because the string is empty.

fromOctalString "8" == Nothing
-- Because '8' is not an octal digit.

fromDecimalString : String -> Maybe Natural

Create the natural number represented by the given decimal string.

decimal ::= [0-9]+

For e.g.

fromDecimalString "0" == Just zero

fromDecimalString "10" == Just ten

fromDecimalString "" == Nothing
-- Because the string is empty.

fromDecimalString "A" == Nothing
-- Because 'A' is not a decimal digit.

fromHexString : String -> Maybe Natural

Create the natural number represented by the given hexadecimal string.

hex ::= [0-9a-fA-F]+

For e.g.

fromHexString "0" == Just zero

fromHexString "a" == Just ten

fromHexString "A" == Just ten

fromHexString "FE" == fromInt 254

fromHexString "" == Nothing
-- Because the string is empty.

fromHexString "5g" == Nothing
-- Because 'g' is not a hexadecimal digit.

fromBaseBString : Basics.Int -> String -> Maybe Natural

Create the natural number represented by the given base-b string.

b must be between 2 and 36 inclusive and each character in the string must be a valid base-b digit.

About base-b digits

A valid base-b digit is any digit d such that 0 <= d <= b - 1.

For bases larger than 10, we use case-insensitive letters from the Latin alphabet to represent the base-b digits that are 10 or larger. So,

A or a represents 10
B or b represents 11
C or c represents 12
...
Z or z represents 35

For e.g.

If b = 16 then the valid base-16 digits are [0-9a-fA-F].

If b = 36 then the valid base-36 digits are [0-9a-zA-Z].

Syntax for fromBaseBString input

input ::= [digit]+
digit ::= [0-9a-zA-Z]

Valid strings when b = 16:

"0", "123", and "Ff".

Invalid strings when b = 16:

For e.g.

fromBaseBString 2 "1010" == Just ten

fromBaseBString 16 "aD" == fromInt 173

fromBaseBString 36 "z" == fromInt 35

fromBaseBString 2 "" == Nothing
-- Because the string is empty.

fromBaseBString 10 "A" == Nothing
-- Because 'A' is not a decimal digit.

Comparison

To test for equality between two natural numbers you can use == and /=.

add two two == four

mul three three /= six

For all other comparisons you will have to use the functions below.

compare : Natural -> Natural -> Basics.Order

Compare any two natural numbers.

compare three four == LT

compare four four == EQ

compare five four == GT

isLessThan : Natural -> Natural -> Basics.Bool

Determine if the second natural number is less than the first.

(two |> isLessThan eight) == True

(two |> isLessThan two) == False

(eight |> isLessThan two) == False

isLessThanOrEqual : Natural -> Natural -> Basics.Bool

Determine if the second natural number is less than or equal to the first.

(two |> isLessThanOrEqual eight) == True

(two |> isLessThanOrEqual two) == True

(eight |> isLessThanOrEqual two) == False

isGreaterThan : Natural -> Natural -> Basics.Bool

Determine if the second natural number is greater than the first.

(two |> isGreaterThan eight) == False

(two |> isGreaterThan two) == False

(eight |> isGreaterThan two) == True

isGreaterThanOrEqual : Natural -> Natural -> Basics.Bool

Determine if the second natural number is greater than or equal to the first.

(two |> isGreaterThanOrEqual eight) == False

(two |> isGreaterThanOrEqual two) == True

(eight |> isGreaterThanOrEqual two) == True

max : Natural -> Natural -> Natural

Find the larger of two natural numbers.

max five ten == ten

max ten five == ten

min : Natural -> Natural -> Natural

Find the smaller of two natural numbers.

min five ten == five

min ten five == five

Predicates

isZero : Natural -> Basics.Bool

Determine if the natural number is 0.

isZero zero == True

isZero one == False

isOne : Natural -> Basics.Bool

Determine if the natural number is 1.

isOne zero == False

isOne one == True

isPositive : Natural -> Basics.Bool

Determine if the natural number is positive (i.e. greater than 0).

isPositive five == True

isPositive zero == False

isEven : Natural -> Basics.Bool

Determine if the natural number is even (i.e. divisible by 2).

isEven zero == True

isEven one == False

isEven two == True

isEven three == False

isOdd : Natural -> Basics.Bool

Determine if the natural number is odd (i.e. not even, so not divisible by 2).

isOdd zero == False

isOdd one == True

isOdd two == False

isOdd three == True

Arithmetic

add : Natural -> Natural -> Natural

Add two natural numbers.

sub : Natural -> Natural -> Natural

Subtract the second natural number from the first.

sub ten four == six
-- 10 - 4 = 6

It uses saturating subtraction. Thus, if the second natural number is larger than the first, 0 is returned.

sub four ten == zero
-- 4 - 10 = 0

mul : Natural -> Natural -> Natural

Multiply two natural numbers.

divModBy : Natural -> Natural -> Maybe ( Natural, Natural )

Find the quotient and remainder when the second natural number (the dividend) is divided by the first (the divisor).

This operation performs Euclidean division or division with remainder.

divModBy d D of two natural numbers D and d ≠ 0, is defined as producing two unique natural numbers q (the quotient) and r (the remainder) such that

For e.g.

(ten |> divModBy two) == Just (five, zero)
-- Because 2 * 5 = 10 is the greatest multiple of 2 less than or equal to 10, and
-- 0 = 10 - 2 * 5 such that 0 <= 0 < 10.

(ten |> divModBy three) == Just (three, one)
-- Because 3 * 3 = 9 is the greatest multiple of 3 less than or equal to 10, and
-- 1 = 10 - 3 *3 such that 0 <= 1 < 10.

Division by 0 is not allowed. So, for all n : Natural,

(n |> divModBy zero) == Nothing

divBy : Natural -> Natural -> Maybe Natural

Find the quotient when the second natural number is divided by the first.

N.B. Please see divModBy to understand how the quotient is computed.

modBy : Natural -> Natural -> Maybe Natural

Find the remainder when the second natural number is divided by the first.

N.B. Please see divModBy to understand how the remainder is computed.

exp : Natural -> Natural -> Natural

Find the power of the first natural number (the base) to the second natural number (the exponent).

exp two three == eight

For all n : Natural,

exp n zero == one

In particular,

exp zero zero == one

N.B. You can read "What is 0^0?" to learn more.

For all n : Natural, where n is positive,

exp zero n == zero

Conversion

toInt : Natural -> Basics.Int

Convert any natural number, n, to n mod (maxSafeInt + 1).

toInt zero == 0

toInt ten == 10

toInt (fromSafeInt maxSafeInt) == maxSafeInt

toInt (add (fromSafeInt maxSafeInt) one) == 0

toInt (add (fromSafeInt maxSafeInt) ten) == 9

toString : Natural -> String

An alias for toDecimalString.

toBinaryString : Natural -> String

Convert any natural number to its binary (base-2) representation.

toBinaryString zero == "0"

toBinaryString one == "1"

toBinaryString ten == "1010"

toBinaryString (fromSafeInt 1729) == "11011000001"

toBinaryString (add (fromSafeInt maxSafeInt) one) == "100000000000000000000000000000000000000000000000000000"

toOctalString : Natural -> String

Convert any natural number to its octal (base-8) representation.

toOctalString zero == "0"

toOctalString one == "1"

toOctalString ten == "12"

toOctalString (fromSafeInt 1729) == "3301"

toOctalString (add (fromSafeInt maxSafeInt) one) == "400000000000000000"

toDecimalString : Natural -> String

Convert any natural number to its decimal (base-10) representation.

toDecimalString zero == "0"

toDecimalString one == "1"

toDecimalString ten == "10"

toDecimalString (fromSafeInt 1729) == "1729"

toDecimalString (add (fromSafeInt maxSafeInt) one) == "9007199254740992"

toHexString : Natural -> String

Convert any natural number to its hexadecimal (base-16) representation.

toHexString zero == "0"

toHexString one == "1"

toHexString ten == "A"

toHexString (fromSafeInt 1729) == "6C1"

toHexString (add (fromSafeInt maxSafeInt) one) == "20000000000000"

toBaseBString : Basics.Int -> Natural -> Maybe String

Convert any natural number to its base-b representation.

b must be between 2 and 36 inclusive and each character in the resulting string will be a valid base-b digit.

All Latin letters in the base-b representation will be in uppercase.

For e.g.

toBaseBString 2 (fromSafeInt 1729) == Just "11011000001"

toBaseBString 8 (fromSafeInt 1729) == Just "3301"

toBaseBString 10 (fromSafeInt 1729) == Just "1729"

toBaseBString 16 (fromSafeInt 1729) == Just "6C1"

toBaseBString 36 (fromSafeInt 1729) == Just "1C1"

For any k : Int where k < 2 or k > 36, and any n : Natural,

toBaseBString k n == Nothing

N.B. Please refer to fromBaseBString to learn more about base-b digits.