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
and0
, but there is only one canonical zero:0
(so, for instance,-0
and00
are invalid). -
Natural numbers are written as digits followed by the suffix
n
, like so:12n
,0n
, and the same restriction on zero as integers applies:0n
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 suffixmutez
after a natural literal, like10000mutez
or0mutez
; - units of
tez
, using the suffixtz
ortez
, like3tz
or3tez
; - decimal amounts of
tz
ortez
, like12.3tz
or12.4tez
.
- units of millionth of
Note that large integral values can be expressed using underscores to
separate groups of digits, like 1_000mutez
or 0.000_004tez
.
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
const a = 5 + 10;
// nat + int yields int
const b = 5n + 10;
// tez + tez yields tez
const c: tez = 5mutez + 1tez;
// tez + int or tez + nat is invalid:
// const d : tez = 5mutez + 10n;
// two nats yield a nat
const e: nat = 5n + 10n;
// nat + int yields an int: invalid
// const f : nat = 5n + 10;
const g = 1_000_000;
Tip: you can use underscores for readability when defining large numbers:
let sum : tez = 100_000mutez;
Subtraction
Subtraction looks as follows.
⚠️ Even when subtracting two
nats
, the result is anint
.
const a = 5 - 10;
// Subtraction of two nats yields an int
const b: int = 5n - 2n;
// Therefore the following is invalid
// const c : nat = 5n - 2n;
From protocol Ithaca
onwards subtracting values of type tez
yeilds an optional value (due to the Michelson instruction
SUB_MUTEZ
)
const d : option<tez> = 5mutez - 1mutez; /* Some (4mutez) */
const e : option<tez> = 1mutez - 5mutez; /* None */
Multiplication
You can multiply values of the same type, such as:
const a = 5 * 5;
const b: nat = 5n * 5n;
// You can also multiply `nat` and `tez`
const c: tez = 5n * 5mutez;
Euclidean Division
In LIGO you can divide int
, nat
, and tez
. Here is how:
⚠️ Division of two
tez
values results into anat
.
const a: int = 10 / 3;
const b: nat = 10n / 3n;
const c: nat = 10mutez / 3mutez;
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.
const a = 120;
const b = 9;
const rem1 = a % b; // 3
const c = 120n;
const rem2 = c % b; // 3
const d = 9n;
const rem3 = c % d; // 3
const rem4 = 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
const a = 37;
const b = 5;
const ediv1 : option<[int , nat]> = ediv(a, b); // Some (7, 2)
const c = 37n;
const ediv2: option<[int , nat]> = ediv(c, b); // Some (7, 2)
const d = 5n;
const ediv3: option<[nat , nat]> = ediv(c, d); // Some (7, 2)
const 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:
const a = int(1n);
const b = 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.
const is_a_nat = is_nat(1);
Increment operator
Increment opeator increments (adds one to) the value of the binder.
In the prefix position (++p
) the operator increments the value and returns
the latest incremented value.
In the postfix position (p++
) the operator increments the value but
returns the old value before the increment.
const testInc = (() => {
let inc = 0;
// Prefix increment operator
assert(++inc == 1);
assert(inc == 1);
// Postfix increment operator
assert(inc++ == 1);
assert(inc == 2);
})();
Decrement operator
Decrement opeator decrements (subtracts one from) the value of the binder.
In the prefix position (--p
) the operator decrements the value and returns
the latest decremented value.
In the postfix position (p--
) the operator decrements the value but
returns the old value before the decrement.
const testDec = (() => {
let v = 10;
// Prefix decrement operator
assert(--v == 9);
assert(v == 9);
// Postfix decrement operator
assert(v-- == 9);
assert(v == 8);
})();