prelude.Int

Part of prelude.

let Int.abs (a: Int): Int

The absolute value.

Int.abs of the most negative Int cannot be represented and overflows, which stops the program rather than returning a negative \"absolute\" value.

let Int.min (a: Int) (b: Int): Int

The smaller of two.

let Int.max (a: Int) (b: Int): Int

The larger of two.

let Int.clamp (x: Int) (lo: Int) (hi: Int): Int

x held between lo and hi inclusive. A lo above hi gives hi, since the upper bound is applied last.

let Int.shr_logical (x: Int) (n: Int): Int

An UNSIGNED right shift: zeros are shifted in, never the sign bit. >> is arithmetic, because Int is signed and -8 >> 1 should be -4; hashing wants the other one, and writing it by hand is exactly the sort of thing that is wrong at n = 0 and n = 64 in every codebase that tries.

The mask is ~(-1 << (64 - n)) and NOT (1 << (64 - n)) - 1, which is the spelling everyone reaches for first and which traps here: at n = 1 that is (1 << 63) - 1, and 1 << 63 is Int's most negative value, so subtracting one from it is an integer overflow. The complement builds the same mask out of a shift and a NOT, neither of which can overflow.

The two ends are handled before the mask because the mask cannot express them: at n = 0 it would need all 64 bits, and 64 - 0 is a shift of 64, which this language defines as zero.

let Int.count_ones (x: Int): Int

The number of one bits. Counted a nibble at a time through a lookup rather than bit by bit, so it is 16 steps and not 64.

let Int.to_radix (n: Int) (radix: Int): String

--- Radix ---

SIGNED, and reversible: Int.to_radix(-255, 16) is "-ff", which String.parse_int would read back. That is the opposite of what C and Rust print for %x on a negative, and it is the choice that keeps to_radix a number conversion rather than a bit dump. For the bit pattern, Int.to_bits says so in its name.

Radix is clamped to 2..36: one digit per character, 0-9a-z.

let Int.to_hex (n: Int): String

Lowercase hex, SIGNED: -255 is -ff, not a two's-complement bit pattern. Int.to_hex_bits is the one that shows the bits.

let Int.to_binary (n: Int): String

Binary, SIGNED: -1 is -1. Int.to_bits shows all 64 bits.

let Int.to_octal (n: Int): String

Octal, signed. See Int.to_radix for other bases.

let Int.to_bits (n: Int): String

The BIT PATTERN: all 64 bits, two's complement, most significant first. This is the one to reach for with a bit field, where a signed reading is not what is wanted. Int.to_bits(-1) is sixty-four ones, while Int.to_binary(-1) is "-1". Both are right about different questions.

let Int.to_hex_bits (n: Int): String

The same, in hex: sixteen digits, two's complement, zero padded.