# A Little Bit More on Fixed-point Numbers

In this bonus chapter, I’d like to show you how to convert prices to ticks in Solidity. We don’t need to do this in the main contracts, but it’s helpful to have such function in tests so we don’t hardcode ticks and could write something like `tick(5000)`

–this makes code easier to read because it’s more convenient for us to think in prices, not tick indexes.

Recall that, to find ticks, we use the `TickMath.getTickAtSqrtRatio`

function, which takes $P $ as its argument, and the $P $ is a Q64.96 fixed-point number. In smart contract tests, we need to check $P $ many times in many different test cases: mostly after mints and swaps. Instead of hard-coding actual values, it might be cleaner to use a helper function like `sqrtP(5000)`

that converts prices to $P $.

So, what’s the problem?

The problem is that Solidity doesn’t natively support the square root operation, which means we need a third-party library. Another problem is that prices are often relatively small numbers, like 10, 5000, 0.01, etc., and we don’t want to lose precision when taking square root.

You probably remember that we used `PRBMath`

earlier in the book to implement a multiply-then-divide operation that doesn’t overflow during multiplication. If you check the `PRBMath.sol`

contract, you’ll notice the `sqrt`

function. However, the function doesn’t support fixed-point numbers, as the function description says. You can give it a try and see that `PRBMath.sqrt(5000)`

results in `70`

, which is an integer number with lost precision (without the fractional part).

If you check prb-math repo, you’ll see these contracts: `PRBMathSD59x18.sol`

and `PRBMathUD60x18.sol`

. Aha! These are fixed-point number implementations. Let’s pick the latter and see how it goes: `PRBMathUD60x18.sqrt(5000 * PRBMathUD60x18.SCALE)`

returns `70710678118654752440`

. This looks interesting! `PRBMathUD60x18`

is a library that implements fixed numbers with 18 decimal places in the fractional part. So the number we got is 70.710678118654752440 (use `cast --from-wei 70710678118654752440`

).

However, we cannot use this number!

There are fixed-point numbers and fixed-point numbers. The Q64.96 fixed-point number used by Uniswap V3 is a **binary** number–64 and 96 signify *binary places*. But `PRBMathUD60x18`

implements a *decimal* fixed-point number (UD in the contract name means “unsigned, decimal”), where 60 and 18 signify *decimal places*. This difference is quite significant.

Let’s see how to convert an arbitrary number (42) to either of the above fixed-point numbers:

- Q64.96: $42∗2_{96}$ or, using bitwise left shift,
`2 << 96`

. The result is 3327582825599102178928845914112. - UD60.18: $42∗10_{18}$. The result is 42000000000000000000.

Let’s now see how to convert numbers with the fractional part (42.1337):

- Q64.96: $421337∗2_{92}$ or
`421337 << 92`

. The result is 2086359769329537075540689212669952. - UD60.18: $421337∗10_{14}$. The result is 42133700000000000000.

The second variant makes more sense to us because it uses the decimal system, which we learned in our childhood. The first variant uses the binary system and it’s much harder for us to read.

But the biggest problem with different variants is that it’s hard to convert between them.

This all means that we need a different library, one that implements a binary fixed-point number and a `sqrt`

function for it. Luckily, there’s such a library: abdk-libraries-solidity. The library implemented Q64.64, not exactly what we need (not 96 bits in the fractional part) but this is not a problem.

Here’s how we can implement the price-to-tick function using the new library:

```
function tick(uint256 price) internal pure returns (int24 tick_) {
tick_ = TickMath.getTickAtSqrtRatio(
uint160(
int160(
ABDKMath64x64.sqrt(int128(int256(price << 64))) <<
(FixedPoint96.RESOLUTION - 64)
)
)
);
}
```

`ABDKMath64x64.sqrt`

takes Q64.64 numbers so we need to convert `price`

to such number. The price is expected to not have the fractional part, so we’re shifting it by 64 bits. The `sqrt`

function also returns a Q64.64 number but `TickMath.getTickAtSqrtRatio`

takes a Q64.96 number–this is why we need to shift the result of the square root operation by `96 - 64`

bits to the left.