//// Functions for working with integers. //// //// ## Division by zero //// //// In Erlang division by zero results in a crash, however Gleam does not have //// partial functions and operators in core so instead division by zero returns //// zero, a behaviour taken from Pony, Coq, and Lean. //// //// This may seem unexpected at first, but it is no less mathematically valid //// than crashing or returning a special value. Division by zero is undefined //// in mathematics. import gleam/float import gleam/order.{type Order} /// Returns the absolute value of the input. /// /// ## Examples /// /// ```gleam /// assert absolute_value(-12) == 12 /// ``` /// /// ```gleam /// assert absolute_value(10) == 10 /// ``` /// pub fn absolute_value(x: Int) -> Int { case x >= 0 { True -> x False -> x * -1 } } /// Returns the result of the base being raised to the power of the /// exponent, as a `Float`. /// /// ## Examples /// /// ```gleam /// assert power(2, -1.0) == Ok(0.5) /// ``` /// /// ```gleam /// assert power(2, 2.0) == Ok(4.0) /// ``` /// /// ```gleam /// assert power(8, 1.5) == Ok(22.627416997969522) /// ``` /// /// ```gleam /// assert 4 |> power(of: 2.0) == Ok(16.0) /// ``` /// /// ```gleam /// assert power(-1, 0.5) == Error(Nil) /// ``` /// pub fn power(base: Int, of exponent: Float) -> Result(Float, Nil) { base |> to_float |> float.power(exponent) } /// Returns the square root of the input as a `Float`. /// /// ## Examples /// /// ```gleam /// assert square_root(4) == Ok(2.0) /// ``` /// /// ```gleam /// assert square_root(-16) == Error(Nil) /// ``` /// pub fn square_root(x: Int) -> Result(Float, Nil) { x |> to_float |> float.square_root() } /// Parses a given string as an int if possible. /// /// ## Examples /// /// ```gleam /// assert parse("2") == Ok(2) /// ``` /// /// ```gleam /// assert parse("ABC") == Error(Nil) /// ``` /// @external(erlang, "gleam_stdlib", "parse_int") @external(javascript, "../gleam_stdlib.mjs", "parse_int") pub fn parse(string: String) -> Result(Int, Nil) /// Parses a given string as an int in a given base if possible. /// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. /// /// ## Examples /// /// ```gleam /// assert base_parse("10", 2) == Ok(2) /// ``` /// /// ```gleam /// assert base_parse("30", 16) == Ok(48) /// ``` /// /// ```gleam /// assert base_parse("1C", 36) == Ok(48) /// ``` /// /// ```gleam /// assert base_parse("48", 1) == Error(Nil) /// ``` /// /// ```gleam /// assert base_parse("48", 37) == Error(Nil) /// ``` /// pub fn base_parse(string: String, base: Int) -> Result(Int, Nil) { case base >= 2 && base <= 36 { True -> do_base_parse(string, base) False -> Error(Nil) } } @external(erlang, "gleam_stdlib", "int_from_base_string") @external(javascript, "../gleam_stdlib.mjs", "int_from_base_string") fn do_base_parse(a: String, b: Int) -> Result(Int, Nil) /// Prints a given int to a string. /// /// ## Examples /// /// ```gleam /// assert to_string(2) == "2" /// ``` /// @external(erlang, "erlang", "integer_to_binary") @external(javascript, "../gleam_stdlib.mjs", "to_string") pub fn to_string(x: Int) -> String /// Prints a given int to a string using the base number provided. /// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. /// For common bases (2, 8, 16, 36), use the `to_baseN` functions. /// /// ## Examples /// /// ```gleam /// assert to_base_string(2, 2) == Ok("10") /// ``` /// /// ```gleam /// assert to_base_string(48, 16) == Ok("30") /// ``` /// /// ```gleam /// assert to_base_string(48, 36) == Ok("1C") /// ``` /// /// ```gleam /// assert to_base_string(48, 1) == Error(Nil) /// ``` /// /// ```gleam /// assert to_base_string(48, 37) == Error(Nil) /// ``` /// pub fn to_base_string(x: Int, base: Int) -> Result(String, Nil) { case base >= 2 && base <= 36 { True -> Ok(do_to_base_string(x, base)) False -> Error(Nil) } } @external(erlang, "erlang", "integer_to_binary") @external(javascript, "../gleam_stdlib.mjs", "int_to_base_string") fn do_to_base_string(a: Int, b: Int) -> String /// Prints a given int to a string using base-2. /// /// ## Examples /// /// ```gleam /// assert to_base2(2) == "10" /// ``` /// pub fn to_base2(x: Int) -> String { do_to_base_string(x, 2) } /// Prints a given int to a string using base-8. /// /// ## Examples /// /// ```gleam /// assert to_base8(15) == "17" /// ``` /// pub fn to_base8(x: Int) -> String { do_to_base_string(x, 8) } /// Prints a given int to a string using base-16. /// /// ## Examples /// /// ```gleam /// assert to_base16(48) == "30" /// ``` /// pub fn to_base16(x: Int) -> String { do_to_base_string(x, 16) } /// Prints a given int to a string using base-36. /// /// ## Examples /// /// ```gleam /// assert to_base36(48) == "1C" /// ``` /// pub fn to_base36(x: Int) -> String { do_to_base_string(x, 36) } /// Takes an int and returns its value as a float. /// /// ## Examples /// /// ```gleam /// assert to_float(5) == 5.0 /// ``` /// /// ```gleam /// assert to_float(0) == 0.0 /// ``` /// /// ```gleam /// assert to_float(-3) == -3.0 /// ``` /// @external(erlang, "erlang", "float") @external(javascript, "../gleam_stdlib.mjs", "identity") pub fn to_float(x: Int) -> Float /// Restricts an int between two bounds. /// /// Note: If the `min` argument is larger than the `max` argument then they /// will be swapped, so the minimum bound is always lower than the maximum /// bound. /// /// ## Examples /// /// ```gleam /// assert clamp(40, min: 50, max: 60) == 50 /// ``` /// /// ```gleam /// assert clamp(40, min: 50, max: 30) == 40 /// ``` /// pub fn clamp(x: Int, min min_bound: Int, max max_bound: Int) -> Int { case min_bound >= max_bound { True -> x |> min(min_bound) |> max(max_bound) False -> x |> min(max_bound) |> max(min_bound) } } /// Compares two ints, returning an order. /// /// ## Examples /// /// ```gleam /// assert compare(2, 3) == Lt /// ``` /// /// ```gleam /// assert compare(4, 3) == Gt /// ``` /// /// ```gleam /// assert compare(3, 3) == Eq /// ``` /// pub fn compare(a: Int, with b: Int) -> Order { case a == b { True -> order.Eq False -> case a < b { True -> order.Lt False -> order.Gt } } } /// Compares two ints, returning the smaller of the two. /// /// ## Examples /// /// ```gleam /// assert min(2, 3) == 2 /// ``` /// pub fn min(a: Int, b: Int) -> Int { case a < b { True -> a False -> b } } /// Compares two ints, returning the larger of the two. /// /// ## Examples /// /// ```gleam /// assert max(2, 3) == 3 /// ``` /// pub fn max(a: Int, b: Int) -> Int { case a > b { True -> a False -> b } } /// Returns whether the value provided is even. /// /// ## Examples /// /// ```gleam /// assert is_even(2) /// ``` /// /// ```gleam /// assert !is_even(3) /// ``` /// pub fn is_even(x: Int) -> Bool { x % 2 == 0 } /// Returns whether the value provided is odd. /// /// ## Examples /// /// ```gleam /// assert is_odd(3) /// ``` /// /// ```gleam /// assert !is_odd(2) /// ``` /// pub fn is_odd(x: Int) -> Bool { x % 2 != 0 } /// Returns the negative of the value provided. /// /// ## Examples /// /// ```gleam /// assert negate(1) == -1 /// ``` /// pub fn negate(x: Int) -> Int { -1 * x } /// Sums a list of ints. /// /// ## Example /// /// ```gleam /// assert sum([1, 2, 3]) == 6 /// ``` /// pub fn sum(numbers: List(Int)) -> Int { sum_loop(numbers, 0) } fn sum_loop(numbers: List(Int), initial: Int) -> Int { case numbers { [first, ..rest] -> sum_loop(rest, first + initial) [] -> initial } } /// Multiplies a list of ints and returns the product. /// /// ## Example /// /// ```gleam /// assert product([2, 3, 4]) == 24 /// ``` /// pub fn product(numbers: List(Int)) -> Int { product_loop(numbers, 1) } fn product_loop(numbers: List(Int), initial: Int) -> Int { case numbers { [first, ..rest] -> product_loop(rest, first * initial) [] -> initial } } /// Generates a random int between zero and the given maximum. /// /// The lower number is inclusive, the upper number is exclusive. /// /// ## Examples /// /// ```gleam /// random(10) /// // -> 4 /// ``` /// /// ```gleam /// random(1) /// // -> 0 /// ``` /// /// ```gleam /// random(-1) /// // -> -1 /// ``` /// pub fn random(max: Int) -> Int { { float.random() *. to_float(max) } |> float.floor |> float.round } /// Performs a truncated integer division. /// /// Returns division of the inputs as a `Result`: If the given divisor equals /// `0`, this function returns an `Error`. /// /// ## Examples /// /// ```gleam /// assert divide(0, 1) == Ok(0) /// ``` /// /// ```gleam /// assert divide(1, 0) == Error(Nil) /// ``` /// /// ```gleam /// assert divide(5, 2) == Ok(2) /// ``` /// /// ```gleam /// assert divide(-99, 2) == Ok(-49) /// ``` /// pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { case divisor { 0 -> Error(Nil) divisor -> Ok(dividend / divisor) } } /// Computes the remainder of an integer division of inputs as a `Result`. /// /// Returns division of the inputs as a `Result`: If the given divisor equals /// `0`, this function returns an `Error`. /// /// Most of the time you will want to use the `%` operator instead of this /// function. /// /// ## Examples /// /// ```gleam /// assert remainder(3, 2) == Ok(1) /// ``` /// /// ```gleam /// assert remainder(1, 0) == Error(Nil) /// ``` /// /// ```gleam /// assert remainder(10, -1) == Ok(0) /// ``` /// /// ```gleam /// assert remainder(13, by: 3) == Ok(1) /// ``` /// /// ```gleam /// assert remainder(-13, by: 3) == Ok(-1) /// ``` /// /// ```gleam /// assert remainder(13, by: -3) == Ok(1) /// ``` /// /// ```gleam /// assert remainder(-13, by: -3) == Ok(-1) /// ``` /// pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { case divisor { 0 -> Error(Nil) divisor -> Ok(dividend % divisor) } } /// Computes the modulo of an integer division of inputs as a `Result`. /// /// Returns division of the inputs as a `Result`: If the given divisor equals /// `0`, this function returns an `Error`. /// /// Note that this is different from `int.remainder` and `%` in that the /// computed value will always have the same sign as the `divisor`. /// /// ## Examples /// /// ```gleam /// assert modulo(3, 2) == Ok(1) /// ``` /// /// ```gleam /// assert modulo(1, 0) == Error(Nil) /// ``` /// /// ```gleam /// assert modulo(10, -1) == Ok(0) /// ``` /// /// ```gleam /// assert modulo(13, by: 3) == Ok(1) /// ``` /// /// ```gleam /// assert modulo(-13, by: 3) == Ok(2) /// ``` /// /// ```gleam /// assert modulo(13, by: -3) == Ok(-2) /// ``` /// pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { case divisor { 0 -> Error(Nil) _ -> { let remainder = dividend % divisor case remainder * divisor < 0 { True -> Ok(remainder + divisor) False -> Ok(remainder) } } } } /// Performs a *floored* integer division, which means that the result will /// always be rounded towards negative infinity. /// /// If you want to perform truncated integer division (rounding towards zero), /// use `int.divide()` or the `/` operator instead. /// /// Returns division of the inputs as a `Result`: If the given divisor equals /// `0`, this function returns an `Error`. /// /// ## Examples /// /// ```gleam /// assert floor_divide(1, 0) == Error(Nil) /// ``` /// /// ```gleam /// assert floor_divide(5, 2) == Ok(2) /// ``` /// /// ```gleam /// assert floor_divide(6, -4) == Ok(-2) /// ``` /// /// ```gleam /// assert floor_divide(-99, 2) == Ok(-50) /// ``` /// pub fn floor_divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { case divisor { 0 -> Error(Nil) divisor -> case dividend * divisor < 0 && dividend % divisor != 0 { True -> Ok(dividend / divisor - 1) False -> Ok(dividend / divisor) } } } /// Adds two integers together. /// /// It's the function equivalent of the `+` operator. /// This function is useful in higher order functions or pipes. /// /// ## Examples /// /// ```gleam /// assert add(1, 2) == 3 /// ``` /// /// ```gleam /// import gleam/list /// assert list.fold([1, 2, 3], 0, add) == 6 /// ``` /// /// ```gleam /// assert 3 |> add(2) == 5 /// ``` /// pub fn add(a: Int, b: Int) -> Int { a + b } /// Multiplies two integers together. /// /// It's the function equivalent of the `*` operator. /// This function is useful in higher order functions or pipes. /// /// ## Examples /// /// ```gleam /// assert multiply(2, 4) == 8 /// ``` /// /// ```gleam /// import gleam/list /// /// assert list.fold([2, 3, 4], 1, multiply) == 24 /// ``` /// /// ```gleam /// assert 3 |> multiply(2) == 6 /// ``` /// pub fn multiply(a: Int, b: Int) -> Int { a * b } /// Subtracts one int from another. /// /// It's the function equivalent of the `-` operator. /// This function is useful in higher order functions or pipes. /// /// ## Examples /// /// ```gleam /// assert subtract(3, 1) == 2 /// ``` /// /// ```gleam /// import gleam/list /// /// assert list.fold([1, 2, 3], 10, subtract) == 4 /// ``` /// /// ```gleam /// assert 3 |> subtract(2) == 1 /// ``` /// /// ```gleam /// assert 3 |> subtract(2, _) == -1 /// ``` /// pub fn subtract(a: Int, b: Int) -> Int { a - b } /// Calculates the bitwise AND of its arguments. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "band") @external(javascript, "../gleam_stdlib.mjs", "bitwise_and") pub fn bitwise_and(x: Int, y: Int) -> Int /// Calculates the bitwise NOT of its argument. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "bnot") @external(javascript, "../gleam_stdlib.mjs", "bitwise_not") pub fn bitwise_not(x: Int) -> Int /// Calculates the bitwise OR of its arguments. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "bor") @external(javascript, "../gleam_stdlib.mjs", "bitwise_or") pub fn bitwise_or(x: Int, y: Int) -> Int /// Calculates the bitwise XOR of its arguments. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "bxor") @external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or") pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int /// Calculates the result of an arithmetic left bitshift. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "bsl") @external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left") pub fn bitwise_shift_left(x: Int, y: Int) -> Int /// Calculates the result of an arithmetic right bitshift. /// /// Most the time you should use the bit array syntaxes instead of manipulating /// bits as ints with bitwise functions. /// /// ## Target specific behaviour /// /// The exact behaviour of this function depends on the target platform. /// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it /// is equivalent to bitwise operations on big-ints. If you need to avoid the /// overhead of big-ints on JavaScript use bit arrays or another package that /// provides faster bitwise operations. /// @external(erlang, "erlang", "bsr") @external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right") pub fn bitwise_shift_right(x: Int, y: Int) -> Int /// Run a function for each int between ints `from` and `to`. /// /// `from` is inclusive, and `to` is exclusive. /// /// ## Examples /// /// ```gleam /// assert /// range(from: 0, to: 3, with: "", run: fn(acc, i) { /// acc <> to_string(i) /// }) /// == "012" /// ``` /// /// ```gleam /// assert range(from: 1, to: -2, with: [], run: list.prepend) == [-1, 0, 1] /// ``` /// pub fn range( from start: Int, to stop: Int, with acc: acc, run reducer: fn(acc, Int) -> acc, ) -> acc { let increment = case start < stop { True -> 1 False -> -1 } range_loop(start, stop, increment, acc, reducer) } fn range_loop( current: Int, stop: Int, increment: Int, acc: acc, reducer: fn(acc, Int) -> acc, ) -> acc { case current == stop { True -> acc False -> { let acc = reducer(acc, current) let current = current + increment range_loop(current, stop, increment, acc, reducer) } } }