Vyper’s decimal
data type is a vital tool for managing fixed-point decimal numbers when building Ethereum smart contracts. Here are a few examples:
@public
@constant
def multiply_decimals(a: decimal, b: decimal) -> decimal:
return a * b
@public
@constant
def add_decimals(a: decimal, b: decimal) -> decimal:
return a + b
stored_amount: decimal
@external
def store_amount(_amount: decimal):
self.stored_amount = _amount
@external
@constant
def get_stored_amount() -> decimal:
return self.stored_amount
@external
@constant
def get_double_amount() -> decimal:
return self.stored_amount * 2
pi: decimal = 3.1415926535
@external
@constant
def calculate_area(radius: decimal) -> decimal:
return self.pi * radius * radius
Overview of Decimals
In Vyper, the decimal
data type is a fixed-point decimal value. The precision is up to 10 decimal places, ranging from -1.871 x 10^37 to 1.871 x 10^37 but not reaching +/- 2^168.
Value literals can be interpreted as decimals by including a decimal point. For example, 123.45
is a decimal
value, while 123
would be interpreted as an integer.
Interestingly, one of the striking differences between Vyper and Solidity (another popular language for writing Ethereum smart contracts) is in the handling of fixed-point numbers. Currently, Solidity does not support fixed-point numbers, whereas Vyper allows the use of decimal fixed-point numbers. This was a deliberate design choice made by the creators of Vyper to provide safer and more accessible financial computations within smart contracts.
Therefore, understanding, using, and being comfortable with decimals is critical for any Vyper developer. Whether you’re writing a finance smart contract dealing with monetary values or creating formulas requiring higher precision, Vyper’s decimal
is what you need.
Arithmetic with Decimals
Arithmetic operations including addition (+
), subtraction (-
), multiplication (*
), division (/
), and modulo (%
) can be performed on decimals in Vyper. The arithmetic operations involving decimal types will require two decimal inputs and the resulting type will also be a decimal
. Also, remember that dividing by zero will throw an error.
Example 1: Basic Operations with Decimals
Let’s look at some simple Vyper code performing basic arithmetic operations using decimals
.
@public
@constant
def multiply_decimals(a: decimal, b: decimal) -> decimal:
# Multiplies two decimal values and returns the result
return a * b
@public
@constant
def add_decimals(a: decimal, b: decimal) -> decimal:
# Adds two decimal values and returns the sum
return a + b
In the code above, we have two functions – multiply_decimals
and add_decimals
which performs multiplication and addition on decimal variables respectively.
Example 2: Handling Ether Amounts as Decimals
Often smart contract developers must handle ether amounts that require decimal precision. The following contract stores a specified Ether amount in a decimal variable and provides functionality to retrieve the stored value and its double.
stored_amount: decimal
@external
def store_amount(_amount: decimal):
# Store the ether amount in the contract.
self.stored_amount = _amount
@external
@constant
def get_stored_amount() -> decimal:
# Retrieve the stored ether amount.
return self.stored_amount
@external
@constant
def get_double_amount() -> decimal:
# Return the double of the stored ether amount
return self.stored_amount * 2
In the contract above, we first declare a decimal variable stored_amount
, then define a function store_amount()
that takes a decimal argument and stores it. get_stored_amount()
retrieves the stored ether amount, and get_double_amount()
returns its double.
Example 3: Calculating Area using Decimals
Suppose we’re making a smart contract to calculate the area of a circle. The precision offered by decimals
would make it ideal for this task.
pi: decimal = 3.1415926535
@external
@constant
def calculate_area(radius: decimal) -> decimal:
# Calculate the area of a circle with the provided radius using the formula Pi*r^2
return self.pi * radius * radius
In this contract, we store the value of pi in a decimal variable and define a method calculate_area()
to calculate the area of a circle of a given radius.
Best Practices and Trouble Spots
Here are few best practices and potential trouble spots to watch for when working with decimals in Vyper:
- Beware of Overflow and Underflow: Vyper’s
decimal
type has a maximum and minimum value. Ensure your operations do not result in a value outside of this range, which would cause an overflow or underflow error. - Mind your Precision: Remember that the
decimal
datatype allows up to 10 decimal places of precision. - Correct use of Modulo: Modulo operation with decimals will return the same type as the operands but do note that it will follow the floor division convention which might lead to unexpected results.
- Know Your Types: When working with other numerical types like
integers
, know their types, and convert other numerical types to decimal before performing operations if decimal precision is required. - Avoid Division By Zero Errors: Ensure that the divisor is not zero before performing the division operation to avoid a runtime error.
By carefully considering these nuances and capitalizing on the precise mathematical capabilities that decimal
provides, developers can unlock a vast spectrum of possibilities for their Vyper smart contracts. Now, it’s your turn to put these decimals to work – happy coding!