A decimal and a binary walk into a library: Two options for Solidity math šŸ”¢

Juan Xavier Valverde
CoinsBench
Published in
6 min readNov 27, 2023

--

This article is an attempt to understand and explain the differences between Soladyā€™s FixedPointMathLib library and ABDK Consultingā€™s ABDKMath64x64 library for Solidity, as well as their use cases. Join me on this exploration, and empower your Solidity development with insights into choosing the right library for your blockchain projects.

With a reasonable understanding of how the FixedPointMathLib math library works, itā€™s time to explore ABDKMath64x64, another powerful library for working with fixed-point numbers in Solidity. You can find the code for the library here in GitHub.

This library empowers developers to perform basic arithmetic operations as well as more advanced mathematical functions such as logarithms, averages, square roots, exponentiation, and more. It operates on two int128 fixed-point numbers and returns the result as an int256, eliminating the risk of overflow. However, if the outcome goes beyond the range of Ā±2Ā¹Ā²āø, it canā€™t fit within the 64.64-bit representation, and the operation will fail.

In this context, a signed 64.64-bit fixed-point number is essentially a fraction with a 128-bit signed integer as the numerator and a fixed denominator of 2ā¶ā“. As the denominator remains constant, thereā€™s no need to store it. Consequently, signed 64.64-bit fixed-point numbers are represented as int128, holding only the numerator. This is how a 64.64-bit number is conceptually structured:

- The 64 bits before the point represent the numerator.

- The 64 bits after the point represent the denominator.

These numbers offer a broad range with respectable precision, making them well-suited for applications that demand accurate real-number calculations. Using binary representation also allows for bit-shift operations, enabling extensive data manipulation at the cost of added complexity.

The entire int128 is used to represent the number, and the separator point is conceptual. The value is left shifted by 2ā¶ā“ in the code for actual calculations.

For instance, the value 5isnā€™t represented as the familiar decimal 5. Instead, it appears as 0x00000000000000050000000000000000, which is equivalent to 92233720368547758080 (5* 2ā¶ā“) in decimal format. The first 16 bytes (64 bits) comprise the numerator, while the remaining 16 bytes (64 bits) represent the denominator.

If we wanted to make sure to get the decimal value, we could use the toUint() function from the same library to convert it back.

  • Numbers exceeding 2ā¶ā“ cannot be directly represented as 64.64-bit fixed point.
  • Token amounts should be represented as `uint256`, not in the 64.64-bit fixed point format.

Use Cases

There are scenarios where fractional math is crucial when dealing with monetary or asset values. Some use cases may include:

- Interest rate calculations: When youā€™re working with interest rates, you often need to use fractional numbers. For example, if youā€™re calculating compound interest, you might need to multiply the principal amount by a fractional interest rate multiple times.

- Token economics: In general tokenomics, you often need to divide one monetary amount by another to calculate ratios or percentages. For example, you might need to calculate the percentage of total tokens that a certain account holds, which would involve dividing the number of tokens the account holds by the total number of tokens.

- Games: There may be games where precise mathematical calculations could make the difference between a winner and a loser. Games with a concept akin to NFTA.pl could find ABDKMath64x64 to be a valuable library to incorporate as it would help determine the player who is a closest to a price, either from above or below the price.

The ABDKMath64x64 library offers specific functions for these scenarios with functions like `muli` and `mulu` for multiplications, and `divi` and `divu` for divisions (with ā€œuā€ denoting `uint` and ā€œiā€ denoting `int` as the inputs for the function call).

Key Differences

The primary distinction between ABDKMath64x64 and FixedPointMathLib libraries lies in the number representations. The first one uses binary numbers with 2ā¶ā“ precision, while the latter uses decimal numbers.

Additionally, ABDKMath64x64 lacks functions that round up, but offers rounding towards zero beyond rounding down. Rounding towards zero is a method of rounding numbers where the fractional part of the number is removed, effectively rounding the number towards zero. For example, if you round 2.7 towards zero, you get 2, and if you round -2.7 towards zero, you get -2. On the other hand, if you round 2.7 up, you get 3, and if you round -2.7 up, you get -3.

This can be beneficial in certain situations where you want to avoid rounding errors that could result in a number being rounded up when it should be rounded down, or vice versa.

Some other notable distinctions between the libraries may include:

- Functions versatility: ABDKMath64x64 offers a broad range of mathematical functions, including addition, substraction, multiplication, division, absolute value, power, square root, and more. This versatility suits various mathematical operations for decentralized. Still, the FixedPointMathLib offers around double the amount of functions to execute so it has a wider range of use cases.

- Support for 64.64-bit Fixed Point: ABDKMath64x64 supports operations with signed 64.64-bit fixed-point numbers, combining a wide range with good precision and performance, making it ideal for applications dealing with real numbers. In contrast, the `FixedPointMathLib` is designed to work with decimal numbers.

  • Gas Efficiency: Due to the low-level manipulation of data and the frequent casting inside the library, the ABDKMath64x64 library is a bit less gas-efficient than the FixedPointMathLib. Here are the gas costs for the same basic multiplication done with each library:

As noted, the cost of the multiplication with ABDKMath64x64 is 78 gas-units more expensive than with FixedPointMathLib.

Conclusion

The choice between these libraries would depend on the specific needs of your use case. ABDKMath64x64 may be more gas-efficient than many other libraries out there, but is not a better choice when compared to FixedPointMathLib. This can be a significant advantage in situations where gas efficiency is a critical factor.

However, you also need to consider the kind of numbers youā€™re working with and the operations you need to perform. ABDKMath64x64 uses binary numbers, which may add unnecessary complexity to some projects. If your work involves mainly decimal numbers, FixedPointMathLib might be more suitable.

FixedPointMathLib, with its substantial set of functions and focus on decimal numbers, accommodate to a broad range of applications. ABDKMath64x64, with its binary number handling and precision, is tailored for projects where accuracy is paramount. The choice between these libraries ultimately boils down to the specific requirements of your project, underscoring the need for a deep understanding of both.

Now, if I had to choose between both, due to its wide range of use cases, user-friendly decimal notation, and cost-effectiveness, Iā€™d go with Soladyā€™s FixedPointMathLib.

If you found this article useful, feel free to show your support through a donation to my address or via Kofi:

Your contribution would be greatly appreciated!

--

--