# Day 18: Floating-Point Arithmetic

We have already covered using fixed-point for fractional numbers, but there may be times when you absolutely require true floating-point, so guess what we’re gonna look at now.

## OP Registers

A bit of a misnomer, since the OP registers are really sections of RAM. There are six OP RAM registers: OP1 to OP6. They are used mainly for two things:

• Storing floating-point numbers.
• Holding variable names.

Each OP register is eleven bytes in length. This is because variable names and floating-point numbers are formatted to be 9 bytes in size. Bytes 10 and 11 are used for extra precision in floating-point numbers when doing math.

## Floating-Point Numbers

Well, we are dealing with a calculator after all :).

TI stores floating point numbers according to this structure:

``````struct FP {
byte  sign;           // Whether the number is positive or negative
byte  exponent;       // Locates the decimal point
byte  significand; // The number itself
byte  guard;       // Guard digits for mathematics
};``````

The magnitude of every real number except zero can be represented as m × 10exp, where exp is an integer designating the exponent and m is a real number designating the significand such that 1 <= m < 10.

### Sign

This byte determines if the number evaluates as positive or negative, and also if it is real or complex. For the uninitiated, a complex number is one of the form a+bi, where i is the square root of -1.

• %00000000 — Positive and real.
• %10000000 — Negative and real.
• %00001100 — Positive and complex.
• %10001100 — Negative and complex.

### Exponent

The exponent field reports the power of ten that the mantissa is to be raised. The number format is not the usual two’s complement, but rather biased to \$80. A value of \$80 translates as 100. \$81 is 101. \$7F is 10-1.

### Significand

These are the digits of the number. Each nibble specifies one decimal digit, so you can have a floating-point number with 14 digits. The first digit, and only the first digit, is the characteristic (the whole part) with the remainder being the mantissa (the decimal part).

Examples:

• `\$00, \$9E, \$23, \$91, \$80, \$55, \$75, \$00, \$00`: 2.391805575 × 1030
• `\$80, \$AC, \$46, \$19, \$18, \$45, \$80, \$00, \$00`: -4.61918458 × 1044
• `\$80, \$77, \$75, \$16, \$99, \$60, \$94, \$17, \$87`: -7.5169960941787 × 10-7
• `\$00, \$89, \$19, \$80, \$61, \$22, \$02, \$65, \$10`: 1980612202.6510

If the number is complex, then this number is the real part (a). The imaginary part (b) is held in the next consecutive OP register, which also has bits 2 and 3 of its sign byte set.

Example:

`\$0C, \$7E, \$22, \$09, \$78, \$47, \$30, \$00, \$00`
`\$8C, \$7D, \$12, \$56, \$55, \$62, \$00, \$00, \$00`

0.0220978473 - 0.0012565562i

To load floating-point (hereafter, ‘FP’) numbers into the OP registers, you use the `Mov9ToOPx` system routine.

`_Mov9ToOP1`: Moves the nine bytes at `HL` to `OP1`.
Input
`HL`
Pointer to start of the nine bytes.
Destroys
all but `A`

For complex numbers, use `_Mov9OP1OP2`, which moves the 18 bytes at `HL` to `OP1` and `OP2`.

`_Mov9ToOP2`: Same as _Mov9ToOP1, but moves to `OP2`.

This is what you do:
Example: Store e into OP1.

``````    LD     HL, exp
bcall(_Mov9ToOP1)
RET

exp:       .DB    \$00, \$80, \$27, \$18, \$28, \$18, \$28, \$45, \$94    ;2.7182818284594
``````

## FP Math

What can I say…there are a lot of ROM calls for FP math. Here is just a sampling.

All registers are destroyed. Result returned to OP1.

`_FPAdd`: Adds `OP2` to `OP1`.
`_FPDiv`: Divides `OP1` by `OP2`.
`_FPMult`: Multiplies `OP1` by `OP2`.
`_FPRecip`: Reciprocal of `OP1`. `OP2` = input `OP1`.
`_FPSub`: Subtracts `OP2` from `OP1`.
`_SqRoot`: Square root of `OP1`.
`_Random`: Gets a random number. 0.0 > `OP1` > 1.0

## Manipulating OP Registers

`_OPxToOPy`: Stores 11 bytes at `OPx` to `OPy`.
Destroys
`BC DE HL`

These combinations are available:

`x` \ `y` OP1 OP2 OP3 OP4 OP5 OP6
OP1 x x x x x
OP2 x x x x x
OP3 x x x x
OP4 x x x x x
OP5 x x x x x
OP6 x x x
`_OPxExOPy`: Swaps 11 bytes at `OPx` with 11 bytes at `OPy`.
Destroys
`A BC DE HL`

These combinations are available:

`x` \ `y` OP2 OP3 OP4 OP5 OP6
OP1 x x x x
OP2 x x x
OP5 x

## Displaying FP Numbers

`_DispOP1A`: Displays the floating-point number in `OP1` using the small font, formatted using the current FIX setting.
Input
`OP1`
Number
`A`
Maximum number of characters (not digits) to display.
Destroys
All
`_FormReal`: Converts the number in `OP1` into a string.
Input
`OP1`
Number
`A`
Maximum number of characters (not digits) to display, minimum of six.
Output
`BC`
Length of string
`OP3`
Start of string, null-terminated.
Destroys
All

SCI, ENG, and FIX settings affect the string conversion. To ignore all format settings, use `FormEReal`.

`_ConvOP1`: Converts the number in `OP1` into a two-byte integer.
Input
`OP1`
Number
Output
`DE`
Converted number.

Generates an error if the exponent is greater than 3.