Have you ever wanted to use numbers that were bigger or smaller than the range you're given in PICO-8? Perhaps you want some more digits of precision for the fractional part of your numbers. Or maybe you're interested in doing math in a severely inefficient way...

Introducing, the Decimal Floating Point library for PICO-8!

(This example cart calculates the value of pi in all three "datatypes", using Viète's formula.)

### Wait, what? Doesn't Lua have floating point already?

Not PICO-8's Lua. It actually uses 16.16 fixed point numbers. Because of this lack of floating-point numbers on PICO-8, I decided to make this library to fill that void (not that anyone asked it to be filled, but still).

### What *are* floating point numbers?

Without getting too much into the nitty-gritty, floating point numbers are numbers that are represented in the following form:

sign * coefficient * (base ^ exponent)

where **sign** is either 1 or -1, and (in the case of this library) **base** is 10. Floating point numbers are meant to give a trade-off between range and precision.

### How do I start using this library?

In order to declare a new float, you can use any one of **df_single()**, **df_double()**, or **df_quad()**. "Single" is the lowest precision available, with 7 significant digits; "double" is the next-lowest precision, with 16 significant digits; and "quad" is the highest precision available, with 34 significant digits.

By default, the way to declare floats is by giving the sign, coefficient, and exponent to the constructors in a table. The sign can either be **"+"** or **"-"**, the coefficient is given as a string of decimal digits, and the exponent is a number representing the power of 10 to multiply the coefficient by.

For example, to create a single-precision float representing the number 256 (or equivalently, +256 * 10^0):

df_single({"+","256",0})

To create a double-precision float representing the number -3.14159 (or equivalently, -314159 * 10^-5):

df_double({"-","314159",-5})

To create a quad-precision float representing the number 116.9 billion (or equivalently, 1169 * 10^8):

df_quad({"+","1169",8})

Note: this means that a number with trailing zeros can have multiple representations (e.g. **{"+","1169",8}**, **{"+","11690",7}**, or **{"+","1169000",5}**), depending on how many digits of accuracy are given.

If you add a dash to the **--[[** comment in tab 2 to uncomment the tab, you can also supply strings (or anything that can be turned into a string with **tostr()**), like these:

df_single("12") df_double("-76") df_single("+3.14159") df_quad("0.003") df_single("4e9") df_double("0.73e-7") |

If you want to declare a value of Infinity, have the exponent be the string **"inf"** (the coefficient doesn't *really* matter). If string parsing is enabled, this can also be done by passing the single string **"inf"** or **"infinity"**.

If you want to declare a value of NaN, have the exponent be the string **"qnan"** (if you provide a coefficient, it can be retrieved via the **df_payload()** function). If string parsing is enabled, this can also be done by passing the single string **"nan"**, with optional "payload" digits at the end.

If you want to declare a value of sNaN ("signaling NaN", which will error out on most arithmetic operations), have the exponent be the string **"snan"** (if you provide a coefficient, it can be retrieved via the **df_payload()** function). If string parsing is enabled, this can also be done by passing the single string **"snan"**, with optional "payload" digits at the end.

### How do I display a float?

To convert a float to a string, use **df_tostr(val)**, where **val** is your float.

### How do I do mathematical operations to floats?

The following functions return a new float with the value of the result:

To add two floats, use **df_add(val1, val2)**.

To subtract two floats, use **df_subtract(val1, val2)**.

To multiply two floats, use **df_multiply(val1, val2)**.

To divide two floats, use **df_divide(val1, val2)**.

To integer-divide two floats, use **df_div(val1, val2)**.

To get the remainder of division of two floats, use **df_mod(val1, val2)**.

To get the integer-quotient and remainder simultaneously, use **df_divmod(val1, val2)**. *(Note: this returns two values - the integer-quotient, then the remainder.)*

To get the integer part of a float, use **df_ipart(val)**.

To get the fractional part of a float, use **df_fpart(val)**.

To reverse a float's sign, use **df_unm(val)**.

The following functions return a true or false value depending on the result of the comparison:

To check for equality between two floats, use **df_eq(val1, val2)**.

To check if one float is less than another float, use **df_lt(val1, val2)**.

To check if one float is less than or equal to another float, use **df_le(val1, val2)**.

Note: floats are represented as tables; thus, in order to copy the value of a float into another variable, the table will need to be cloned by value. Luckily, you can use the included function **clone(tbl)**, which returns a shallow copy of a table, to clone float values as well.

### Is there anything else I can do with floats?

Yes, there is!

To get the sign of a float, use **df_sign(val)**. *(Note: to return 0 for a float representing 0, use df_sign(val, true) instead. And yes, this implies that a "negative zero" is a possible value.)*

To check if a float is a finite number (i.e. not Infinity, NaN, or sNaN), use

**df_is_finite(val)**.

To check if a float is either NaN or sNaN, use

**df_is_nan(val)**.

To check if a float is sNaN, use

**df_is_snan(val)**.

To get the "payload" of a NaN or sNaN, use

**df_payload(val)**.

*(Note: returns*

**nil**if the number is not a NaN or sNaN; returns**"0"**if no payload has been provided.)To round a float to

**p**significant digits, use

**df_round(val, p)**.

*(Note: omit the*

**p**argument to round it to the given precision for the number.)To convert a float to a string, use

**df_tostr(val)**.

If you add a dash to the **--[[** comment in tab 1 to uncomment the tab, the following functions become available:

To convert a float to a table of byte values (4 for single-precision, 8 for double-precision, and 16 for quad-precision), use **df_tobytes(val)**.

To convert a table of byte values to a float, use **df_from(bytes)**. *(Note: the table will be assumed to contain the proper amount of bytes for the desired float precision: 4 for single-precision, 8 for double-precision, and 16 for quad-precision.)*

### I have a question/comment that isn't addressed here!

Good! Reply to this post to tell me about it (or tell me in the Discord server, my tag is JWinslow23#6531).

### How are you going to end this post?

I...um...

...shoot...I didn't think of that...I'm *terrible* at ending forum posts...

### Version History

**v1.0.1** (August 25, 2020)

- Token optimizations, fixed bug when dividing by infinity

**v1.0** (August 23, 2020)

- Initial release

@Trip "Installing" is really just as simple as copy-pasting the code of this cart into a new cart, or using the #include command to include it's code in your project (check the readme for PICO-8 for details). It's not really a "library" in the traditional sense.

[Please log in to post a comment]