dwayne/elm-natural/1.1.1

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.

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.

The natural number 1.

The natural number 2.

The natural number 3.

The natural number 4.

The natural number 5.

The natural number 6.

The natural number 7.

The natural number 8.

The natural number 9.

The natural number 10.

Limits

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

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

Constructors

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 : 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

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 : 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:

  • "+2", because '+' is not part of the allowed syntax,
  • "5g", because 'g' is not a hexdecimal digit.

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 -> Order

Compare any two natural numbers.

compare three four == LT


compare four four == EQ


compare five four == GT

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

(two |> isLessThan eight) == True


(two |> isLessThan two) == False


(eight |> isLessThan two) == False

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

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

(two |> isGreaterThan eight) == False


(two |> isGreaterThan two) == False


(eight |> isGreaterThan two) == True

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

Find the larger of two natural numbers.

max five ten == ten


max ten five == ten

Find the smaller of two natural numbers.

min five ten == five


min ten five == five

Predicates

isZero : Natural -> Bool

Determine if the natural number is 0.

isZero zero == True


isZero one == False
isOne : Natural -> Bool

Determine if the natural number is 1.

isOne zero == False


isOne one == True

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

isPositive five == True


isPositive zero == False
isEven : Natural -> 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 -> 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 two natural numbers.

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

Multiply two natural numbers.

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

  • d * q is the greatest multiple of d less than or equal to D, and
  • r = D - d * q such that 0 <= r < d.

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

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.

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.

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 -> 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.

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"

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"

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 : 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.