MartinSStewart / elm-uint64 / UInt64

64-bit unsigned integer using wrapping overflow.

Type


type UInt64

64-bit unsigned integer.

UInt64 is represented internally as three unsigned integers:

Constants

minValue : UInt64

Minimum possible UInt64 value.

Same as zero.

UInt64.minValue
    |> UInt64.toString
    --> "0"

maxValue : UInt64

Maximum possible UInt64 value.

2^64 - 1 = 18446744073709551615 = 0xFFFFFFFFFFFFFFFF

UInt64.maxValue
    |> UInt64.toString
    --> "18446744073709551615"

maxSafe : UInt64

Maximum safe integer as UInt64.

2^53 - 1 = 9007199254740991 = 0x001FFFFFFFFFFFFF

Equal to Number.MAX_SAFE_INTEGER in JavaScript.

See also isSafe.

maxSafeAsFloat : Basics.Float

maxSafe as Float

maxFloat : UInt64

Maximum UInt64 value that can be represented exactly as a Float.

2^64 - 2048 = 18446744073709549568 = 0xFFFFFFFFFFFFF800

Note: Float can't represent exactly all integers above maxSafe. For example integers maxFloat+ 1 <= x <=maxValue can't be represented exactly as Float, making this the maximum UInt64 value that can.

maxFloatAsFloat : Basics.Float

maxFloat as Float

zero : UInt64

Number 0

one : UInt64

Number 1

two : UInt64

Number 2

Argument handling

Every Int or Float argument of every UInt64 function is limited by one of the following three functions (or equivalent code):

Non-integer Int

Int arguments are expected to be integers and are not checked for non-integer values like NaN, -Infinity, +Infinity or 12.34.

Behavior of any UInt64 function is undefined if Int argument is not an integer.

Large Int

Behavior of Int for values above 2^31 - 1 is undefined in Elm. As of Elm 0.19.1, using Int as function parameter or return value works for full safe integer range up to maxSafe, but this could change in the future.

Note: This affects also limitSmallInt with n = 32.

String

String argument can be any valid Unicode String.

Behavior is undefined if String argument contains invalid Unicode. Such String:s can't be fuzz-tested with elm-test, so I can't make functions robust against invalid Unicode.

limitSmallInt : Basics.Int -> Basics.Bool -> Basics.Int -> Basics.Int

Limit Int to 0 <= x < 2 ^ bitSize or 1 <= x <= 2 ^ bitSize.

See argument handling.

Algorithm:

  1. If value is negative, convert it to positive by two's complement.
  2. Apply unsigned bitwise AND with bitmask 2 ^ bitSize - 1.
  3. If value is zero and not startFromZero, use 2 ^ bitSize as value.

Examples

-- `1234` limited to 6 bits, `0 <= x <= 63`
UInt64.limitSmallInt 6 True 1234
    --> 18

-- `-1` limited to 8 bits, `0 <= x <= 255`
UInt64.limitSmallInt 8 True -1
    --> 0xFF

-- `-1` limited to 32 bits, `0 <= x <= 2^32-1`
UInt64.limitSmallInt 32 True -1
    --> 0xFFFFFFFF

-- `0` limited to 6 bits, `1 <= x <= 64`
UInt64.limitSmallInt 6 False 0
    --> 64

limitLargeInt : Basics.Int -> Basics.Int

Limit Int to 0 <= value <=maxSafe.

See argument handling.

Algorithm:

Examples

-- negative value is replaced with zero
UInt64.limitLargeInt -1
    --> 0

-- value above `maxSafe` is replaced with `maxSafe`
UInt64.limitLargeInt 9007199254740992
    --> 9007199254740991

limitFloat : Basics.Float -> Basics.Float -> Basics.Float

Limit Float to 0 <= value <= max.

See argument handling.

Algorithm:

Examples

-- `-1` limited to 12 decimal digits
UInt64.limitFloat 999999999999 -1
    --> 0

-- `1e20` limited to 12 decimal digits
UInt64.limitFloat 999999999999 1e20
    --> 999999999999

-- `1e20` limited to `0 <= value <= maxFloat`
UInt64.limitFloat UInt64.maxFloatAsFloat 1.0e20
    --> 18446744073709549568.0

Conversion - Int

fromInt : Basics.Int -> UInt64

Convert Int to UInt64.

See argument handling.

UInt64.fromInt 123
    |> UInt64.toString
    --> "123"

toInt31 : UInt64 -> Maybe Basics.Int

Convert UInt64 to 31-bit unsigned integer.

If UInt64 is above 2^31 - 1, return Nothing.

UInt64.fromInt 0x7FFFFFFF
    |> UInt64.toInt31
    --> Just 0x7FFFFFFF

UInt64.fromInt 0x80000000
    |> UInt64.toInt31
    --> Nothing

toInt53 : UInt64 -> Maybe Basics.Int

Convert UInt64 to 53-bit unsigned integer.

If UInt64 is above maxSafe, return Nothing.

See large Int note.

UInt64.maxSafe
    |> UInt64.toInt53
    --> Just 9007199254740991

UInt64.maxSafe
    |> UInt64.increment
    |> UInt64.toInt53
    --> Nothing

Conversion - Float

floor : Basics.Float -> UInt64

Convert Float to UInt64, rounding down.

*) If value is above maxValue, return maxValue.

See argument handling.

Values above maxSafe

Conversion is exact for all possible Float integer values from 0 to maxFloat. However because Float can't represent all integers above maxSafe, it can sometimes seem like there is an error.

In the following example value 11222333444555666777.0 can't be represented exactly as a Float. Nearest value that can be represented exactly as a Float is 11222333444555667456.0, and that is what UInt64.floor gets as its argument. This argument is then converted exactly to UInt64.

UInt64.floor 11222333444555666777.0
    |> UInt64.toString
    --> "11222333444555667456"

fromDecimal12s can be used instead to convert decimal literals above maxSafe to UInt64:

UInt64.fromDecimal12s 11222333 444555666777
    |> UInt64.toString
    --> "11222333444555666777"

toFloat : UInt64 -> Basics.Float

Convert UInt64 to Float.

Conversion is exact for any value from 0 to maxSafe, but above maxSafe value is rounded if it can't be represented exactly as Float.

Example

9007199254740993 can't be represented exactly as Float, so it's rounded to 9007199254740992.

UInt64.fromDecimal12s 9007 199254740993
    |> UInt64.toFloat
    --> 9007199254740992

Conversion - Parts

fromInt32s : Basics.Int -> Basics.Int -> UInt64

Convert 64-bit unsigned integer represented as two 32-bit unsigned integers to UInt64.

See argument handling.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.toHexString
    --> "11223344AABBCCDD"

UInt64.fromInt32s 1 2
    |> UInt64.toHexString
    --> "0000000100000002"

toInt32s : UInt64 -> ( Basics.Int, Basics.Int )

Convert UInt64 to 64-bit unsigned integer represented as two 32-bit unsigned integers.

See large Int note.

UInt64.floor 1e15
    |> UInt64.toInt32s
    --> ( 0x00038D7E, 0xA4C68000 )

fromInt24s : Basics.Int -> Basics.Int -> Basics.Int -> UInt64

Convert 64-bit unsigned integer represented as three 24-bit unsigned integers to UInt64.

This is the internal format of UInt64 and so fromInt24s is the fastest way to create UInt64 value.

See argument handling.

UInt64.fromInt24s 0x1122 0x334455 0x667788
    |> UInt64.toHexString
    --> "1122334455667788"

UInt64.fromInt24s 1 2 3
    |> UInt64.toHexString
    --> "0001000002000003"

toInt24s : UInt64 -> ( Basics.Int, Basics.Int, Basics.Int )

Convert UInt64 to 64-bit unsigned integer represented as three 24-bit unsigned integers.

This is the internal format of UInt64 and so toInt24s is the fastest way to extract value out of UInt64.

Example

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.toInt24s
    --> ( 0x1122, 0x3344AA, 0xBBCCDD )

fromDecimal12s : Basics.Float -> Basics.Float -> UInt64

Convert 64-bit unsigned integer represented as two 12-decimal-digit unsigned integers to UInt64.

*) If high is 18446745, return maxValue.

See argument handling.

UInt64.fromDecimal12s 111222 333444555666
    |> UInt64.toString
    --> "111222333444555666"

UInt64.fromDecimal12s 1 2
    |> UInt64.toString
    --> "1000000000002"

fromBigEndianBytes : List Basics.Int -> UInt64

Convert list of bytes in big-endian order to UInt64.

See argument handling.

UInt64.fromBigEndianBytes [ 0xAB, 0, 0xCD ]
    |> UInt64.toHexString
    --> "0000000000AB00CD"

List.range 0x01 0x0F
    |> UInt64.fromBigEndianBytes
    |> UInt64.toHexString
    --> "08090A0B0C0D0E0F"

toBigEndianBytes : UInt64 -> List Basics.Int

Convert UInt64 to list of 8 bytes in big-endian order.

UInt64.fromInt 0xABCDEF
    |> UInt64.toBigEndianBytes
    --> [ 0, 0, 0, 0, 0, 0xAB, 0xCD, 0xEF ]

Conversion - String

fromString : String -> Maybe UInt64

Convert String to UInt64.

String can be

Return Nothing if String isn't valid for any of the above formats, or if the value would be above maxValue.

See String at argument handling.

UInt64.fromString "12345"
    |> Maybe.andThen UInt64.toInt31
    --> Just 12345

UInt64.fromString "0x11223344AABBCCDD"
    |> Maybe.map UInt64.toInt32s
    --> Just ( 0x11223344, 0xAABBCCDD )

UInt64.fromString "0o777"
    |> Maybe.map UInt64.toHexString
    --> Just "00000000000001FF"

UInt64.fromString "0b1111000011110000"
    |> Maybe.map UInt64.toHexString
    --> Just "000000000000F0F0"

-- `e` is not valid without `0x` prefix
UInt64.fromString "1e10"
    --> Nothing

-- value would be above `maxValue`
UInt64.fromString "111222333444555666777"
    --> Nothing

toString : UInt64 -> String

Convert UInt64 to decimal String.

UInt64.fromInt 0xFFFFFF
    |> UInt64.toString
    --> "16777215"

Note: See Conversion - Digits for more options converting UInt64 toString.

toHexString : UInt64 -> String

Convert UInt64 to uppercase hexadecimal String of 16 characters.

UInt64.floor 1e15
    |> UInt64.toHexString
    --> "00038D7EA4C68000"

UInt64.zero
    |> UInt64.toHexString
    --> "0000000000000000"

Note: See Conversion - Digits for more options converting UInt64 toString.

Conversion - Digits

These functions convert UInt64 to Digits, which offers options like different bases, digits padding and digits grouping.

toDigits : Internal.Base -> UInt64 -> Internal.Digits Char

Convert UInt64 to Digits of Char using given Base.

This is intended as first step in converting UInt64 to String.

import UInt64
import UInt64.Digits as Digits

UInt64.maxValue
    |> UInt64.toDigits Digits.octal
    |> Digits.toString
    --> "1777777777777777777777"

UInt64.floor 1e15
    |> UInt64.toDigits Digits.hexLower
    |> Digits.padToMultipleOf 4 '0'
    |> Digits.groupToString 4 ' '
    --> "0003 8d7e a4c6 8000"

toIntDigits : Internal.Base -> UInt64 -> Internal.Digits Basics.Int

Convert UInt64 to Digits of Int using given Base.

This is like toDigits except that each digit will be Int instead of Char.

import UInt64
import UInt64.Digits as Digits

UInt64.fromInt 0xABC
    |> UInt64.toIntDigits Digits.hex
    |> Digits.toList
    --> [ 10, 11, 12 ]

-- digit sum of 1234 is `1+2+3+4 = 10`
UInt64.fromInt 1234
    |> UInt64.toIntDigits Digits.decimal
    |> Digits.toList
    |> List.sum
    --> 10

Math

add : UInt64 -> UInt64 -> UInt64

Addition with wrapping overflow.

-- `123 + 456`
UInt64.add (UInt64.fromInt 123) (UInt64.fromInt 456)
    |> UInt64.toString
    --> "579"

-- `maxValue + 100`
UInt64.add UInt64.maxValue (UInt64.fromInt 100)
    |> UInt64.toString
    --> "99"

sub : UInt64 -> UInt64 -> UInt64

Subtraction with wrapping overflow.

-- `456 - 123`
UInt64.sub (UInt64.fromInt 456) (UInt64.fromInt 123)
    |> UInt64.toString
    --> "333"

-- `0 - 0xFF`
UInt64.sub UInt64.zero (UInt64.fromInt 0xFF)
    |> UInt64.toHexString
    --> "FFFFFFFFFFFFFF01"

mul : UInt64 -> UInt64 -> UInt64

Multiplication with wrapping overflow.

-- `1e9 * 1e9`
UInt64.mul (UInt64.floor 1e9) (UInt64.floor 1e9)
    |> UInt64.toString
    --> "1000000000000000000"

-- `(1e10 * 1e10) % 2^64`
UInt64.mul (UInt64.floor 1e10) (UInt64.floor 1e10)
    |> UInt64.toString
    --> "7766279631452241920"

pow : UInt64 -> UInt64 -> UInt64

Power aka exponentiation. 0 ^ 0 = 1

-- `3 ^ 7`
UInt64.pow (UInt64.fromInt 3) (UInt64.fromInt 7)
    |> UInt64.toString
    --> "2187"

-- `10 ^ 19`
UInt64.pow (UInt64.fromInt 10) (UInt64.fromInt 19)
    |> UInt64.toString
    --> "10000000000000000000"

-- `(3 ^ 10000000000000000000) % 2^64`
UInt64.pow (UInt64.fromInt 10) (UInt64.fromInt 19)
    |> UInt64.pow (UInt64.fromInt 3)
    |> UInt64.toString
    --> "12038004833498693633"

Note: Uses fast algorithms: Bases 0-2 are special-cased, exponents 0-16 use addition-chain exponentiation🢅 and exponents over 16 use exponentiation by squaring🢅.

increment : UInt64 -> UInt64

Increment by one with wrapping overflow.

-- `42 + 1`
UInt64.increment (UInt64.fromInt 42)
    |> UInt64.toString
    --> "43"

-- `maxValue + 1`
UInt64.increment UInt64.maxValue
    |> UInt64.toString
    --> "0"

decrement : UInt64 -> UInt64

Decrement by one with wrapping overflow.

-- `42 - 1`
UInt64.decrement (UInt64.fromInt 42)
    |> UInt64.toString
    --> "41"

-- `0 - 1`
UInt64.decrement UInt64.zero
    |> UInt64.toHexString
    --> "FFFFFFFFFFFFFFFF"

square : UInt64 -> UInt64

Squaring with wrapping overflow.

square a is same as mul a a or pow a two but faster.

-- `1e9 * 1e9`
UInt64.square (UInt64.floor 1e9)
    |> UInt64.toString
    --> "1000000000000000000"

Division

Note: I would prefer to cause runtime exception on division-by-zero, but that can't be tested, so I'll settle for returning zero which can be tested.

div : UInt64 -> UInt64 -> UInt64

Integer division.

Examples

UInt64.div (UInt64.fromInt 1234) (UInt64.fromInt 100)
    |> UInt64.toFloat
    --> 12

-- 0xFFFFFFFFFFFFFFFF / 1e10
UInt64.div UInt64.maxValue (UInt64.floor 1e10)
    |> UInt64.toFloat
    --> 1844674407

mod : UInt64 -> UInt64 -> UInt64

Remainder after div.

Examples

UInt64.mod (UInt64.fromInt 1234) (UInt64.fromInt 100)
    |> UInt64.toFloat
    --> 34

-- 0xFFFFFFFFFFFFFFFF % 1e10
UInt64.mod UInt64.maxValue (UInt64.floor 1e10)
    |> UInt64.toFloat
    --> 3709551615

divMod : UInt64 -> UInt64 -> ( UInt64, UInt64 )

Integer division with modulo.

divMod a b is same as ( div a b, mod a b ) but faster.

Examples

UInt64.divMod (UInt64.fromInt 1234) (UInt64.fromInt 100)
    |> Tuple.mapBoth UInt64.toFloat UInt64.toFloat
    --> ( 12, 34 )

-- ( 0xFFFFFFFFFFFFFFFF / 1e10, 0xFFFFFFFFFFFFFFFF % 1e10 )
UInt64.divMod UInt64.maxValue (UInt64.floor 1e10)
    |> Tuple.mapBoth UInt64.toFloat UInt64.toFloat
    --> ( 1844674407, 3709551615 )

Bitwise

and : UInt64 -> UInt64 -> UInt64

Bitwise AND.

UInt64.and
    (UInt64.fromInt32s 0x11223344 0xAABBCCDD)
    (UInt64.fromInt32s 0x0000FFFF 0xFFFF0000)
    |> UInt64.toHexString
    --> "00003344AABB0000"

or : UInt64 -> UInt64 -> UInt64

Bitwise OR.

UInt64.or
    (UInt64.fromInt32s 0x11223344 0xAABBCCDD)
    (UInt64.fromInt32s 0x0000FFFF 0xFFFF0000)
    |> UInt64.toHexString
    --> "1122FFFFFFFFCCDD"

xor : UInt64 -> UInt64 -> UInt64

Bitwise XOR.

UInt64.xor
    (UInt64.fromInt32s 0x11223344 0xAABBCCDD)
    (UInt64.fromInt32s 0x0000FFFF 0xFFFF0000)
    |> UInt64.toHexString
    --> "1122CCBB5544CCDD"

complement : UInt64 -> UInt64

Bitwise complement, aka bitwise NOT, aka one's complement.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.complement
    |> UInt64.toHexString
    --> "EEDDCCBB55443322"

shiftLeftBy : Basics.Int -> UInt64 -> UInt64

Bitwise shift left, filling with zeroes from right.

See argument handling.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.shiftLeftBy 20
    |> UInt64.toHexString
    --> "344AABBCCDD00000"

shiftRightZfBy : Basics.Int -> UInt64 -> UInt64

Bitwise shift right, filling with zeroes from left.

See argument handling.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.shiftRightZfBy 20
    |> UInt64.toHexString
    --> "0000011223344AAB"

rotateLeftBy : Basics.Int -> UInt64 -> UInt64

Bitwise rotate left.

See argument handling.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.rotateLeftBy 20
    |> UInt64.toHexString
    --> "344AABBCCDD11223"

rotateRightBy : Basics.Int -> UInt64 -> UInt64

Bitwise rotate right.

See argument handling.

UInt64.fromInt32s 0x11223344 0xAABBCCDD
    |> UInt64.rotateRightBy 20
    |> UInt64.toHexString
    --> "BCCDD11223344AAB"

shiftRightZfBy1 : UInt64 -> UInt64

Bitwise shift right by one bit, filling with zero from left.

shiftRightZfBy1 a is same as shiftRightZfBy 1 a but faster.

UInt64.fromInt32s 0xEECCAA88 0x66442200
    |> UInt64.shiftRightZfBy1
    |> UInt64.toHexString
    --> "7766554433221100"

getBit : Basics.Int -> UInt64 -> Basics.Int

Return a bit.

See argument handling.

UInt64.one
    |> UInt64.getBit 0
    --> 1

setBit : Basics.Int -> Basics.Int -> UInt64 -> UInt64

Set a bit to given value.

See argument handling.

UInt64.zero
    |> UInt64.setBit 30 1
    |> UInt64.toHexString
    --> "0000000040000000"

Comparison

compare : UInt64 -> UInt64 -> Basics.Order

Compare two UInt64:s.

UInt64.compare UInt64.zero UInt64.one
    --> LT

Check

isSafe : UInt64 -> Basics.Bool

Return True if argument is safe integer.

A safe integer is an integer that

Unsigned integers from 0 to maxSafe are safe integers.

Example

For example 2^53 is not a safe integer. While it can be represented exactly as Float, there exists another integer 2^53 + 1 which is rounded to 2^53:

-- 2^53 + 1 (9007199254740993) is rounded to
-- 2^53     (9007199254740992) when converted to Float
UInt64.fromDecimal12s 9007 199254740993
    |> UInt64.toFloat
    --> 9007199254740992

UInt64.fromDecimal12s 9007 199254740993
    |> UInt64.isSafe
    --> False

This happens because 2^53 + 1 can't be represented exactly as Float, so it is rounded to another integer.

isZero : UInt64 -> Basics.Bool

Return True if argument is zero.

This is same as (==)zero but much faster.

Note: See Performance Optimization🢅 for discussion about speed of == in Elm 0.19.1.

isEven : UInt64 -> Basics.Bool

Return True if argument is even.

isOdd : UInt64 -> Basics.Bool

Return True if argument is odd.

Extra

Extra functions which can be useful for some use cases, e.g. benchmarking and testing.

These are not intended to be useful generally.

divModFast : UInt64 -> UInt64 -> Result String ( UInt64, UInt64 )

Fast but complex algorithm for integer division with modulo.

You should usually use divMod instead because it will use even faster algorithms when dividend < 2^53 or divisor < 2^29, and will fall back to divModFast otherwise.

So divModFast is faster than divMod only when dividend >= 2^53 && divisor >= 2^29.

divModSlow : UInt64 -> UInt64 -> ( UInt64, UInt64 )

Simple but slow long division🢅 algorithm for integer division with modulo.

Intended use cases: