Skip to content
On this page

Numbers

SmartPy has several types for integers:

  • sp.nat for non-negative integers (zero and above), known as natural numbers or nats
  • sp.int for all integers
  • sp.mutez for non-negative amounts of micro-tez or mutez, which is one-millionth of a tez, the token of the Tezos blockchain

The types for integers and nats are not compatible with sp.mutez, which means that you can't compare integers and nats with sp.mutez types or use mathematical operations that combine them. However, you can use functions in the standard libraries to convert between nat and mutez.

SmartPy does not support floating-point numbers because Tezos does not.

Integers and natural numbers

A literal integer such as 2 is either of type sp.nat or sp.int, depending on how it is used. To be explicit about the type, you can write sp.nat(2) or sp.int(2).

Basic arithmetic

The operators +, -, * and / perform addition, subtraction, multiplication, and division, respectively. They are homogeneous, meaning that both arguments must be of the same type (either both sp.nat or both sp.int).

The type of the result is the same as the arguments, except for -, which always returns an sp.int.

Examples:

smartpy
assert sp.nat(2) + sp.nat(3) == sp.nat(5)
assert sp.int(2) + sp.int(3) == sp.int(5)
assert sp.nat(2) - sp.nat(3) == sp.int(-1)
assert sp.int(2) - sp.int(3) == sp.int(-1)

The unary negation operator - can take either sp.nat or sp.int and always returns an sp.int. For example, - sp.nat(2) == sp.int(-2).

Mixing different types yields an error. For example, adding an integer to a nat is invalid, as in sp.nat(2) + sp.int(3).

To manipulate different types, SmartPy provides the functions sp.add, sp.sub, and sp.mul, as in this example:

smartpy
a = sp.nat(2)
b = sp.int(3)
assert sp.add(a, b) == sp.int(5)

Division

sp.ediv(a: sp.nat, b: sp.nat) → sp.option[sp.pair[sp.nat, sp.nat]]
sp.ediv(a: sp.int, b: sp.nat) → sp.option[sp.pair[sp.int, sp.nat]]
sp.ediv(a: sp.nat, b: sp.int) → sp.option[sp.pair[sp.int, sp.nat]]
sp.ediv(a: sp.int, b: sp.int) → sp.option[sp.pair[sp.int, sp.nat]]

sp.ediv performs Euclidean division, which returns the quotient and the remainder within an sp.option type. Note that the quotient type depends on the types of the arguments.

If both of the arguments are nats, the function returns an option with a nat for the quotient and a nat for the remainder, as in this example:

smartpy
assert sp.ediv(sp.nat(14), sp.nat(3)) == sp.Some((sp.nat(4), sp.nat(2))) # 14 == 4 * 3 + 2

In any other combination of integers and nats, sp.ediv returns an option with an integer for the quotient and a nat for the remainder, as in these examples:

smartpy
assert sp.ediv(sp.int(-14), sp.nat(3)) == sp.Some((sp.int(-5), sp.nat(1)))  # -14 == -5 *  3 + 1
assert sp.ediv(sp.nat(14), sp.int(-3)) == sp.Some((sp.int(-4), sp.nat(2)))  #  14 == -4 * -3 + 2
assert sp.ediv(sp.int(-14), sp.int(-3)) == sp.Some(( sp.int(5), sp.nat(1)))  # -14 ==  5 * -3 + 1

If you try to divide by zero, the option type contains None, as in this example:

smartpy
result_opt = sp.ediv(sp.nat(14), 0)
with sp.match(result_opt):
    with sp.case.Some as result:
        (quotient, remainder) = result
        sp.trace(quotient)
        sp.trace(remainder)
    with None:
        sp.trace("Division by zero")

If the option type contains Some, then sp.ediv(a, b) = sp.Some(q, r), where q (the quotient) and r (the remainder) are the unique integers such that a == q * b + r and both 0 <= r and r < b.

To get only the quotient or remainder of two integers or two nats, you can use a / b and sp.mod(a, b), respectively. In either case, dividing by zero causes a Division_by_zero.

WARNING

For negative denominators the result of division differs between SmartPy and Python. SmartPy follows the Michelson semantics, whereas Python rounds the quotient towards negative infinity (yielding negative remainders!). To avoid confusion between the two, the SmartPy syntax uses / and sp.mod instead of // and %.

Comparison

You can compare two integers of the same type (either sp.nat or sp.int) with the operators ==, !=, <, <=, >, >=. The result is of type sp.bool. For example, 2 == 3 is False.

Conversions

sp.to_int(x: sp.nat) → sp.int

The function sp.to_int converts an sp.nat to an sp.int. For example sp.to_int(sp.nat(2)) == sp.to_int(2), or (thanks to type inference) sp.to_int(2) == 2.

sp.is_nat(a: sp.int) → sp.option[sp.nat]

The function sp.is_nat converts an sp.int to an sp.option[sp.nat]:

  • If a variable a is greater than or equal to zero, sp.is_nat(a) returns sp.Some(b), where sp.to_int(b) == a
  • If a variable a is less than zero, sp.is_nat(a) returns None

For example:

smartpy
assert sp.is_nat( 2) == sp.Some(2)
assert sp.is_nat(-2) == None
sp.as_nat(x: sp.int) → sp.nat

The function sp.as_nat performs the same conversion as sp.is_nat, but instead of returning an option, it raises an error on negative numbers. Thus sp.as_nat(2) == 2, whereas sp.as_nat(-2) yields an error.

Bitwise arithmetic

Bitwise and, or and xor operations are available as &, | and ^ on sp.nat:

smartpy
assert 42 & 1 == 0
assert 42 | 1 == 43
assert 42 ^ 1 == 43

Furthermore, ~x computes the two's complement of x (of type sp.int):

smartpy
assert ~100 == -101

Shifting

Left and right shifts are also available as << and >> on sp.nat:

smartpy
assert 42 << 1 == 84
assert 42 >> 1 == 21

Token amounts

The type sp.mutez represents micro-tez, or one-millionth of one tez, so sp.mutez(42) denotes 42 micro-tez or 0.000042 tez.

As shorthand, you can use sp.tez() to create sp.mutez types. For example, sp.tez(a) is equivalent to sp.mutez(a * 1_000_000).

You can add and subtract mutez values with the + and - operators but you cannot multiply them directly. Negative results raise errors. For example, sp.mutez(5) - sp.mutez(2) == sp.mutez(3), but sp.mutez(5) - sp.mutez(10) raises an error.

sp.split_tokens(amount: sp.mutez, quantity: sp.nat, division: sp.nat) → sp.mutez

The sp.split_tokens function helps multiply and divide tokens. It takes three sp.mutez parameters and calculates the value a * b / c. Its result is in sp.mutez.

This function enables the computation of mutez percentages. This example calculates 5% of 200 mutez:

smartpy
sp.split_tokens(sp.mutez(200), 5, 100) == sp.mutez(10) # 5% of 200 mutez

This function rounds the result to the closest whole mutez or sp.mutez(0) if the result is closer to zero.