---
title: Floating Point Numbers (XFL)
description: High precision calculations are native to Hooks.
---
import { Aside } from '@astrojs/starlight/components';

### Background

[Floating point numbers](https://en.wikipedia.org/wiki/Floating-point_arithmetic) are widely used in computer science to do calculation of finite precision but arbitrary scale numbers.

Most modern CPUs are capable of performing fast floating point operations using the [IEEE binary floating point standard](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) however `xahaud` does **not** use this format. Instead Xahau uses a [bespoke decimal floating point standard](/docs/protocol-reference/binary-format).

This custom format has three basic properties:

1. The format is inherently decimal, expressed as a decimal `mantissa` multipled by `10` to the power of an `exponent`.
2. All values expressed have 16 significant (decimal) figures.
3. The range of exponents is `-96` to `+80`

When serialized the mantissa is 54 bits, and the exponent is 8 bits, with a final sign bit bringing the total size of the serialized floating point to 63 bits.

### What is XFL?

[XLS-17d](https://github.com/XRPLF/XRPL-Standards/discussions/39) is an XRPL standards proposal that defines an efficient way to pack and store xrpld floating point numbers (as described above).

XFLs store the bits of the floating point number within an _enclosing number_. This is always an `int64_t`. Negative enclosing numbers represent invalid XFLs (for example as a result of division by zero.)

<Aside type="tip">
  Use the XFL-tool <a href="https://richardah.github.io/xfl-tools/" target="_blank" rel="noopener">here</a> to compose and decompose XFLs in your browser!
</Aside>

Some example XFLs follow

| loating Point Value | Enclosing Number    | Representation                |
| ------------------- | ------------------- | ----------------------------- |
| -1                  | 1478180677777522688 | -1000000000000000 \* 10^(-15) |
| 0                   | 0                   | 0 (_canonical zero_)          |
| 1                   | 6089866696204910592 | +1000000000000000 \* 10^(-15) |
| _PI_                | 6092008288858500385 | +3141592653589793 \* 10^(-15) |
| -_PI_               | 1480322270431112481 | -3141592653589793 \* 10^(-15) |

This format is very convenient for Hooks, as Hooks can only exchange _integer_ values with xrpld. By enclosing the floating point inside an integer in a well defined way it becomes possible to do complex floating point computations from a Hook. This is useful for computing exchange rates.

### Canonical Zero

Floating point regimes typically have a number of different ways to express zero, which can be a problem for testing for zero. For example `0 x 10 ^ 1` is zero and `0 x 10 ^ 2` is also zero. For this reason there is a canonical zero enforced by the standard and the Hook API. The canonical zero is also enclosing number zero (`0`).

### Hook Float API

Once you have an XFL you can use the Float API to do various computations. The Float API appears in the table below. Each API takes one or more XFL enclosing numbers and returns an XFL enclosing number. Negative return values _always_ represent a computational error (such as division by zero). There are no valid negative enclosing numbers.

| Hook API                                                                | What it does                                                          |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [float_set](/docs/hooks/functions/float/float_set)           | Create a float from an exponent and mantissa                          |
| [float_multiply](/docs/hooks/functions/float/float_multiply) | Multiply two XFL numbers together                                     |
| [float_mulratio](/docs/hooks/functions/float/float_mulratio) | Multiply an XFL floating point by a non-XFL numerator and denominator |
| [float_negate](/docs/hooks/functions/float/float_negate)     | Negate an XFL floating point number                                   |
| [float_compare](/docs/hooks/functions/float/float_compare)   | Perform a comparison on two XFL floating point numbers                |
| [float_sum](/docs/hooks/functions/float/float_sum)           | Add two XFL numbers together                                          |
| [float_sto](/docs/hooks/functions/float/float_sto)           | Output an XFL as a serialized object                                  |
| [float_sto_set](/docs/hooks/functions/float/float_sto_set)  | Read a serialized amount into an XFL                                  |
| [float_invert](/docs/hooks/functions/float/float_invert)     | Divide one by an XFL floating point number                            |
| [float_divide](/docs/hooks/functions/float/float_divide)     | Divide an XFL by another XFL floating point number                    |
| [float_one](/docs/hooks/functions/float/float_one)           | Return the number 1 represented in an XFL enclosing number            |
| [float_exponent](/docs/hooks/functions/float/float_exponent) | Get the exponent of an XFL enclosing number                           |
| [float_mantissa](/docs/hooks/functions/float/float_mantissa) | Get the mantissa of an XFL enclosing number                           |
| [float_sign](/docs/hooks/functions/float/float_sign)         | Get the sign of an XFL enclosing number                               |
| float_exponent_set                                                    | Set the exponent of an XFL enclosing number                           |
| float_mantissa_set                                                    | Set the mantissa of an XFL enclosing number                           |
| float_sign_set                                                        | Set the sign of an XFL enclosing number                               |
| [float_int](/docs/hooks/functions/float/float_int)           | Convert an XFL floating point into an integer floor                 |
| [float_root](/docs/hooks/functions/float/float_root)         | Compute the nth root of an XFL                                        |
| [float_log](/docs/hooks/functions/float/float_log)           | Compute the decimal log of an XFL                                     |

<Aside type="caution">
  You should never do any direct math or comparison on the _enclosing number_. This will almost always result in incorrect computations.

  The _sole exception_ is checking for canonical zero.
</Aside>

### Example

In the below example an exchange rate conversion is performed, followed by a high precision fraction multiplication.

```c
int64_t max_vault_pusd =
    float_multiply(vault_xrp, exchange_rate);

max_vault_pusd = 
    float_mulratio(max_vault_pusd, 0,
        NEW_COLLATERALIZATION_NUMERATOR, NEW_COLLATERALIZATION_DENOMINATOR);
```

<Aside type="tip">
  If a float API returns a negative value and you do not check for negatives, then passing that negative value into another float API will also produce a negative value. In this way, errors are propagated much like `NaN` (not a number) is propagated in other languages.
  
  If you ever end up with a negative enclosing number, an error occurred somewhere in your floating point calculations.
</Aside>
