Version: 0.25.0

Math, Numbers & Tez

LIGO offers three built-in numerical types: int, nat and tez. Values of type int are integers; values of type nat are natural numbers (integral numbers greater than or equal to zero); values of type tez are units of measure of Tezos tokens.

  • Integer literals are the same found in mainstream programming languages, for example, 10, -6 and 0, but there is only one canonical zero: 0 (so, for instance, -0 and 00 are invalid).
  • Natural numbers are written as digits followed by the annotation as nat, like so: 12 as nat, 0 as nat, and the same restriction on zero as integers applies: 0 as nat is the only way to specify the natural zero.

  • Tezos tokens can be specified using literals of three kinds:

    • units of millionth of tez, using the annotation as mutez after a natural literal, like 10000 as mutez or 0 as mutez;
    • units of tez, using the annotation as tez, like 3 as tez;
    • decimal amounts of tez are not supported by JsLIGO, instead the amount should be written as mutez.

Note that large integral values can be expressed using underscores to separate groups of digits, like 1_000 as mutez.

Addition#

Addition in LIGO is accomplished by means of the + infix operator. Some type constraints apply, for example you cannot add a value of type tez to a value of type nat.

In the following example you can find a series of arithmetic operations, including various numerical types. However, some bits remain in comments as they would otherwise not compile, for example, adding a value of type int to a value of type tez is invalid. Note that adding an integer to a natural number produces an integer.

// int + int yields int
let a: int = 5 + 10;
// nat + int yields int
let b: int = (5 as nat) + 10;
// tez + tez yields tez
let c: tez = (5 as mutez) + (1 as tez);
// tez + int or tez + nat is invalid:
// let d : tez = (5 as mutez) + (10 as nat);
// two nats yield a nat
let e: nat = (5 as nat) + (10 as nat);
// nat + int yields an int: invalid
// let f : nat = (5 as nat) + 10;
let g: int = 1_000_000;

Pro tip: you can use underscores for readability when defining large numbers:

let sum : tez = 100_000 as mutez;

Subtraction#

Subtraction looks as follows.

⚠️ Even when subtracting two nats, the result is an int

let a: int = 5 - 10;
// Subtraction of two nats yields an int
let b: int = (5 as nat) - (2 as nat);
// Therefore the following is invalid
// let c : nat = (5 as nat) - (2 as nat);
let d: tez = (5 as mutez) - (1 as mutez);

Multiplication#

You can multiply values of the same type, such as:

let a: int = 5 * 5;
let b: nat = (5 as nat) * (5 as nat);
// You can also multiply `nat` and `tez`
let c: tez = (5 as nat) * (5 as mutez);

Euclidean Division#

In LIGO you can divide int, nat, and tez. Here is how:

⚠️ Division of two tez values results into a nat

let a: int = 10 / 3;
let b: nat = (10 as nat) / (3 as nat);
let c: nat = (10 as mutez) / (3 as mutez);

LIGO also allows you to compute the remainder of the Euclidean division. In LIGO, it is a natural number.

The behaviour of the % operator in JsLIGO is different from JavaScript. In JsLIGO, % is a modulus operator and in JavaScript it's a remainder operator. In the case of positive numbers everything is the same, but not with negative numbers.

let a: int = 120;
let b: int = 9;
let rem1: nat = a % b; // 3
let c: nat = 120 as nat;
let rem2: nat = c % b; // 3
let d: nat = 9 as nat;
let rem3: nat = c % d; // 3
let rem4: nat = a % d; // 3

For cases when you need both the quotient and the remainder, LIGO provides the ediv operation. ediv x y returns Some (quotient, remainder), unless y is zero, in which case it returns None

let a: int = 37;
let b: int = 5;
let ediv1 : option<[int , nat]> = ediv(a, b); // Some (7, 2)
let c: nat = 37 as nat;
let ediv2: option<[int , nat]> = ediv(c, b); // Some (7, 2)
let d: nat = 5 as nat;
let ediv3: option<[nat , nat]> = ediv(c, d); // Some (7, 2)
let ediv4: option<[int , nat]> = ediv(a, d); // Some (7, 2)

From int to nat and back#

You can cast an int to a nat and vice versa. Here is how:

let a: int = int(1 as nat);
let b: nat = abs(1);

Checking a nat#

You can check if a value is a nat by using a predefined cast function which accepts an int and returns an optional nat: if the result is not None, then the provided integer was indeed a natural number, and not otherwise.

let is_a_nat: option<nat> = Michelson.is_nat(1);