Day 18

Floating-Point Arithmetic

Difficulty:
novice · intermediate · advanced · expert


· Previous · Lesson Index · Next ·

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:

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[7]; // The number itself
    byte  guard[2];       // 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.

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 trasnslates 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       0.0220978473 - 0.0012565562i
    $8C, $7D, $12, $56, $55, $62, $00, $00, $00

Loading Floating-Point Numbers

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

_Mov9ToOP1
_Mov9ToOP2

Moves the nine bytes at HL to OP1 or OP2.

Input

HL
Pointer to start of the nine bytes.
Destroys
all but A
Remarks
For complex numbers, use _Mov9OP1OP2, which moves the 18 bytes at HL to OP1 and OP2.

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

    LD     HL, exp
    b_call(_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
Muliplies 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
Remarks

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
Remarks

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
Remarks
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.
Remarks
Generates an error if the exponent is greater than 3.