 LT4335 float instructions. Version of 8 July 2011. Home.

Fundamental is that a float consists of two full-fledged integers, one for the mantissa, and one for the exponent. A float is null if the mantissa or exponent or both are null. In this regard, the LT4335 differs from most other CPUs.

Register notation like "#0 exp, #1 man" or "#0.1" indicates a float whose exponent is in #0 and mantissa is in #1. To make the float operations work, if an exponent is in #n, the corresponding mantissa must be in #(n+1). A convenient consequence is that an integer in #0 may be converted to a float in #0.1 simply by pushing an integer zero.

There is no need to inform the CPU that two registers combine to make a float, as the CPU does not enforce data types in registers or genspace. At all times may integer or string operations be performed on the exponent's and mantissa's respective contents. Example: to multiply a float by 2, simply perform the integer operation of adding 1 to its exponent, leaving the mantissa untouched. The programmer is cautioned, however, that tinkering with the mantissa and exponent separately is error prone.

To normalize a float is to do this:

• If the mantissa is null:
• If the exponent is null, do nothing.
• If the exponent has a value, change it to null.
• If the mantissa has a value:
• If the exponent is null, change the mantissa to null.
• If the exponent has a value:
• If the mantissa is zero, change the exponent to zero.
• If the mantissa is nonzero, perform this step…
• Divide the mantissa by two, and add 1 to the exponent
…until either the mantissa is an odd number, or the exponent attains the maximum integer value.

To trim a float is to perform integer trimming on each of its mantissa and exponent. When a float is an input to an instruction, there is no requirement that it be normalized or trimmed. If a programmer does desire to both normalize a float and trim its component integers, the normalization should normally be done first.

The first three tables contain instructions that will get or put the mantissa and exponent of a float. The address within genspace for a float is specifically the address of its mantissa, its exponent immediately following.

Because a float is built of two integers, the programmer could use two integer instructions to get or put a float. If this is preferred, the mantissa and exponent need not adjoin in genspace, but can be widely separated. However, with two separate instructions the operation will no longer be atomic and hence will risk fouling an environment where data is shared among tasks. If this is a concern, a branch uninterruptable operation can be invoked.

With the size-embedded versions of the get, put, and get-and-put instructions a tradeoff in the instruction design was necessary: the size of each of the mantissa and exponent cannot be freely chosen from 0…255, but rather must be a multiple of 17, which is the word size of the LT4335. In an opcode like that of FGAE, m4_e4_00_000_1111, there is first an unsigned four-bit integer (m4) giving the size of the mantissa, in words — not bits. That is followed by another unsigned four-bit integer (e4), this one giving the size of the exponent in words. Therefore, B1000 means one word = 17 bits, B0100 = 34 bits, B1010 = 85 bits, et cetera. A likely popular choice is the sequence B1100_1000 which gives a mantissa of 51 bits and an exponent of 17 bits. The reason for employing word-size, and not bit-size, granularity is that an opcode is only 17 bits long, and two 8-bit size specifiers would leave only one bit, which is hardly enough to distinguish several instructions.

When the size operands are in registers, the limitations of the previous paragraph do not apply; the mantissa and exponent can be of arbitrary sizes, and those sizes need not be calculated until run time. Similarly, there is no size restriction when separate integer instructions are used to get or put the mantissa and exponent.

In the descriptions below:

• m8 is a signed 8-bit integer (−127…+127 or null) for the mantissa of a tiny float (FG_E instruction only)
• e4 is either:
• a signed 4-bit integer (−7…+7 or null) for the exponent of a tiny float (FG_E instruction only)
• an unsigned 4-bit integer (0…15) for the size (in words) of the exponent of a float
• m4 is an unsigned 4-bit integer (0…15) for the size (in words) of the mantissa of a float.
• u8 is an unsigned 8-bit integer (0…255)
• s9 is a signed 9-bit integer (−255…+255 or null).
Sometimes the size of a mantissa or exponent is represented by a signed integer; an exception will be thrown in response to a requested size greater than 255, less than 0, or null.

Many of the get, put, and get-and-put instructions involve an offset. This number, when added to the address of the next physical instruction (which equals the address of the current instruction plus 17), gives the address in genspace whence to read data, or whither to write it. If the offset is null, an exception is thrown.

Get. (see also integer and string) All the float get instructions normalize and trim the result as it is placed into registers. If an unnormalized or untrimmed float is preferred, the programmer should use string get instructions.

The first get instruction pushes a float embedded in the opcode, while the rest get the float from genspace.

Intentionally omitted is an option to embed an 8-bit mantissa size but place the exponent size in a register, and vice versa.

Put. (see also integer and string) The next instructions pull an float from the stack and write it into genspace. They attempt to convert each of the mantissa and exponent from the size it assumed in its register to the size requested for genspace, which is likely different from the trimmed size. Rounding-nearest-half-even may be necessary, and a reduction in digits may incur a null.

Get-and-(conditional)-put. (see also integer and string) The machine compares the float in genspace to the "old value" float:

• If they both have values, and they are equal: the "new value" float is written to genspace in place of the old value, and the one-bit string 1 is pushed.
• If either is null, or they are unequal: genspace is not changed, and the one-bit string 0 is pushed.

It is not necessary that the numbers have been normalized or trimmed. For example, here are two numbers that would test as equal:

• mantissa 01110000 = 14 and exponent 0011111 = −4; this number is 14 ÷16 = 0.875
• mantissa 11100 = 7 and exponent 101111 = −3; this number is 7÷8 = 0.875

The two floats must be of exactly the same value; there is no provision for a tolerance. (If an exact match of bit patterns is desired, the string version of get-and-put should be used.) If the "new value" float is of such large or small magnitude that its exponent will not fit into the indicated region of genspace, a null will be written instead.

Versus. (see also integer, string, and branch) Two floats may be compared with each other. The result is a string at #0, which contains 32 bits. Its contents are:

Address of bit within #0new With FV_E and FV_R, this bit equals 1 when … Comments
0#0.1old and #2.3old both have values, and #0.1old > #2.3old never both 1exact comparison, analogous to integer and string
1#0.1old and #2.3old both have values, and #0.1old ≤ #2.3old
2#0.1old and #2.3old both have values, and #0.1old ≠ #2.3old never both 1
3#0.1old and #2.3old both have values, and #0.1old = #2.3old
4#0.1old and #2.3old both have values, and #0.1old < #2.3old never both 1
5#0.1old and #2.3old both have values, and #0.1old ≥ #2.3old
6#0.1old is null never the sameanalogous to integer
7#0.1old has a value
8#2.3old is null never the same
9#2.3old has a value
10#0.1old and #2.3old are similar never the same
11#0.1old and #2.3old are dissimilar
12#0.1old has a value, and #2.3old is null never the same
13#0.1old is null, or #2.3old has a value
14#0.1old is null, and #2.3old has a value never the same
15#0.1old has a value, or #2.3old is null
16#0.1old has a value, and #2.3old has a value never the same
17#0.1old is null, or #2.3old is null
18#0.1old is null, and #2.3old is null never the same
19#0.1old has a value, or #2.3old has a value
20#0.1old and #2.3old both have values, and #0.1old > #2.3old never both 1absolute tolerance
21#0.1old and #2.3old both have values, and #0.1old ≤ #2.3old
22#0.1old and #2.3old both have values, and #0.1old ≠ #2.3old never both 1
23#0.1old and #2.3old both have values, and #0.1old = #2.3old
24#0.1old and #2.3old both have values, and #0.1old < #2.3old never both 1
25#0.1old and #2.3old both have values, and #0.1old ≥ #2.3old
26#0.1old and #2.3old both have values, and #0.1old > #2.3old never both 1relative tolerance
27#0.1old and #2.3old both have values, and #0.1old ≤ #2.3old
28#0.1old and #2.3old both have values, and #0.1old ≠ #2.3old never both 1
29#0.1old and #2.3old both have values, and #0.1old = #2.3old
30#0.1old and #2.3old both have values, and #0.1old < #2.3old never both 1
31#0.1old and #2.3old both have values, and #0.1old ≥ #2.3old

A comparand is regarded as null if the mantissa, the exponent, or both are null. The programmer can investigate the component integers if greater detail is required.

 FV_E FV_R float versus, tolerance embedded s9_1111_0111 float versus, tolerance in register 081_1111_0111 Pulled: • #0 exp, #1 man: comparand • #2 exp, #3 man: comparand Pushed: • #0 32-bit string: result If s9 is null, FV_R is performed instead. Pulled: • #0 exp, #1 man: comparand • #2 exp, #3 man: comparand • #4 unsigned integer: tolerance Pushed: • #0 32-bit string: result

The absolute and relative tolerances are most easily described by reference to the number produced by the FIL instruction, namely the base-two logarithm of a float's absolute value, rounded to an integer, rounded toward negative infinity.

• For absolute tolerance, the instruction subtracts one comparand from the other. If the FIL of that difference is less than or equal to the tolerance, the numbers are deemed equal, not greater-than, and not less-than.
• For relative tolerance, define the anchor to be the comparand of greater absolute value. The instruction subtracts the other comparand from the anchor to obtain the deviation. Next the FIL of the deviation is subtracted from the FIL of the anchor; and if that difference is greater than or equal to the tolerance, the numbers are deemed equal, not greater-than, and not less-than.
• Whether tolerance is absolute or relative, in the case where both comparands happen to be exactly equal they are of course regarded as equal, not greater-than, and not less-than.

The absolute and relative tolerance comparisons are not intended to be a comprehensive error-management system. Rather, they are a quick and easy way to determine whether two floats are "very nearly" equal, and can be beneficial to iterative numerical routines that must frequently test for a termination condition.

Arithmetic. (see also integer) Float arithmetic offers the usual operations. The output will be null on overflow, null input, or division by zero. Null or not, the float will be normalized, and each component integer trimmed.

The precision is the number of bits that the mantissa will have before normalization or trimming, and all those bits are guaranteed accurate according to the round-nearest-half-even rule; this is a relative precision, not an absolute. If the requested precision is not in 0…255, an exception will be thrown. When the precision is embedded in the opcode, it is the first eight bits.

Integer-style division of floats. The remaining division operations are similar to those for integers. They involves two inputs (numerator N and denominator D) and two outputs (quotient Q and remainder R).

Here are the specifications:

• If D = 0, the operation will fail.
• NR will equal Q × D.
• The magnitude of R will be less than the magnitude of D.
• R will be of the same sign (positive, negative, zero) as D.
• N, D and R are floats, but Q is an integer.

Whatever the signs of N and D, Q is rounded toward negative infinity; no attempt is made to round Q to the nearest integer. Not observed is the usual float rounding rule, round-nearest-half-even.

Q will be trimmed as any other integer. The requested precision affects only R.

Another way to look at the operation is this:

• If the exponents of N and D are both nonnegative, then they are both mathematical integers, and the definition of Q are R is exactly as that of integers. Although R will be a mathematical integer, it will be stored as a float.
• If N or D has a negative exponent, both of them are multiplied by such a power of two as to make the exponents nonnegative. Then Q are R are figured as for integers. While Q will need no adjustment, R must be divided by the power of two that was earlier used for multiplication.

A result is null if either input is null, or if there is division by zero.

FIL is a rough guide to the magnitude of a float. The result is signed integer n if the float's absolute value is at least 2**n, but less than 2**(n + 1). It is easy for the machine to calculate. Define the leader of a positive integer as the address (within the register) of its rightmost nonzero bit. The leader of a negative integer is the leader of its absolute value, and the leader of zero or null is undefined. Then, for a float that is neither null nor zero, the result is obtained by adding the exponent to the mantissa's leader.

FR_E FR_R FQ_RE FQ_RR float remainder, precision embedded u8_00010_0111 float remainder, precision in register 08_00010_0111 Pulled: • #0 exp, #1 man: numerator • #2 exp, #3 man: denominator Pushed: • #0 exp, #1 man = remainder of #0.1old ÷ #2.3old If u8 is zero, FR_R is performed instead. Pulled: • #0 exp, #1 man: numerator • #2 exp, #3 man: denominator • #4 signed integer: precision Pushed: • #0 exp, #1 man = remainder of #0.1old ÷ #2.3old float quotient and remainder, precision embedded u8_10010_0111 float quotient and remainder, precision in register 08_10010_0111 Pulled: • #0 exp, #1 man: numerator • #2 exp, #3 man: denominator Pushed: • #0 exp, #1 man = remainder of #0.1old ÷ #2.3old • #2 signed integer = quotient of #0.1old ÷ #2.3old If u8 is zero, FQ_RR is performed instead. Pulled: • #0 exp, #1 man: numerator • #2 exp, #3 man: denominator • #4 signed integer in 0…255: precision Pushed: • #0 exp, #1 man = remainder of #0.1old ÷ #2.3old • #2 signed integer = quotient of #0.1old ÷ #2.3old float quotient ?_x_10111_0111 float integer logarithm ?_x_10111_0111 Pulled: • #0 exp, #1 man: numerator • #2 exp, #3 man: denominator Pushed: • #0 signed integer = quotient of #0.1old ÷ #2.3old Pulled: • #0 exp, #1 man: operand Pushed: • #0 signed integer: base-2 logarithm of absolute value of #0.1old, rounded toward negative infinity #0new is null if #0.1old is null or zero.

Format. (see also integer) The first instructions round-nearest-half-even the operand to a requested precision. The result is normalized and trimmed.

The last two instructions change the formatting of a float, but not its value. A programmer who desires the mantissa or exponent to be trimmed to a non-minimal size will need to invoke the integer instructions directly.

FF_RE FF_RR FF_N FF_T float format round, precision embedded u8_01010_0111 float format round, precision in register 08_01010_0111 Pulled: • #0 exp, #1 man: operand Pushed: • #0 exp, #1 man = #0.1old rounded If u8 is zero, FF_RR is performed instead. Pulled: • #0 exp, #1 man: operand • #3 signed integer in 0…255: precision Pushed: • #0 exp, #1 man: = #0.1old rounded float format normalize ?_x_10111_0111 float format trim ?_x_10111_0111 Pulled: • #0 exp, #1 man: operand Pushed: • #0 exp, #1 man: #0.1old normalized Pulled: • #0 exp, #1 man: operand Pushed: • #0 exp, #1 man: each of #0old and #1old trimmed to its minimum size

Transcendental. The standard mathematical functions in the table below can be included on LT4335 implementations intended for scientific purposes. As compared to the other instruction tables, a condensed format has been used, because most of the operations are very similar to one another; the top row explains.

As usual, any null input ensures a null output.

FT…E FT…R Comments FT_R2E FT_R2R float transcendental , precision embedded u8_b5_0111 float transcendental , precision in register 08_b5_0111 Pulled: • #0 exp, #1 man: operand Pushed: • of #0.1old If u8 is zero, FT…R is performed instead. Pulled: • #0 exp, #1 man: operand • #3 signed integer in 0…255: precision Pushed: • of #0.1old flo tra square root, prec emb u8_00110_0111 flo tra square root, prec reg 08_00110_0111 If operand is less than zero, result will be null. flo tra cube root, prec emb u8_10110_0111 flo tra cube root, prec reg 08_10110_0111 flo tra exponential, prec emb u8_01110_0111 flo tra exponential, prec reg 08_01110_0111 flo tra logarithm, prec emb u8_11110_0111 flo tra logarithm, prec reg 08_11110_0111 If operand is not greater than zero, result will be null. flo tra circular sine, prec emb u8_00001_0111 flo tra circular sine, prec reg 08_00001_0111 flo tra hyperbolic sine, prec emb u8_10001_0111 flo tra hyperbolic sine, prec reg 08_10001_0111 flo tra inverse circular sine, prec emb u8_01001_0111 flo tra inverse circular sine, prec reg 08_01001_0111 If absolute value of operand is greater than one, result will be null. Otherwise, −π ÷ 2 ≤ result ≤ +π ÷ 2. flo tra inverse hyperbolic sine, prec emb u8_11001_0111 flo tra inverse hyperbolic sine, prec reg 08_11001_0111 flo tra circular cosine, prec emb u8_00101_0111 flo tra circular cosine, prec reg 08_00101_0111 flo tra hyperbolic cosine, prec emb u8_10101_0111 flo tra hyperbolic cosine, prec reg 08_10101_0111 flo tra inverse circular cosine, prec emb u8_01101_0111 flo tra inverse circular cosine, prec reg 08_01101_0111 If absolute value of operand is greater than one, result will be null. Otherwise, 0 ≤ result ≤ π. flo tra inverse hyperbolic cosine, prec emb u8_11101_0111 flo tra inverse hyperbolic cosine, prec reg 08_11101_0111 If operand is less than one, result will be null. flo tra circular tangent, prec emb u8_00011_0111 flo tra circular tangent, prec reg 08_00011_0111 If operand approximates an odd multiple of π ÷ 2, result will be null because of overflow. flo tra hyperbolic tangent, prec emb u8_10011_0111 flo tra hyperbolic tangent, prec reg 08_10011_0111 flo tra inverse circular tangent, one argument, prec emb u8_01011_0111 flo tra inverse circular tangent, one argument, prec reg 08_01011_0111 −π ÷ 2 < result < +π ÷ 2. flo tra inverse hyperbolic tangent, prec emb u8_11011_0111 flo tra inverse hyperbolic tangent, prec reg 08_11011_0111 If absolute value of operand is not less than one, result will be null. flo tra inverse circular tangent, two arguments, prec emb u8_00111_0111 flo tra inverse circular tangent, two arguments, prec reg 08_00111_0111 see note below Pulled: • #0 exp, #1 man: abscissa • #2 exp, #3 man: ordinate Pushed: • #0 exp, #1 man: result If u8 is zero, FA_ICT_2R is performed instead. Pulled: • #0 exp, #1 man: abscissa • #2 exp, #3 man: ordinate • #4 signed integer in 0…255: precision Pushed: • #0 exp, #1 man: result

Generally, FT_ICT_2E and FT_ICT_2R return the inverse circular tangent of ordinate ÷ abscissa. According to the signs of ordinate and abscissa, however, the result may be increased or decreased by 2 × π. Also, a nonnull result is obtained when the abscissa is zero if the ordinate is not zero. The effect is that of the widely used atan2 function found in many computer languages, with an overall range of −π < result ≤ +π. Here are the details:

if…then…
ordinate < 0 and abscissa < 0−π < result < −π ÷ 2
ordinate < 0 and abscissa = 0result = −π ÷ 2
ordinate < 0 and abscissa > 0−π ÷ 2 < result < 0
ordinate = 0 and abscissa > 0result = 0
ordinate > 0 and abscissa > 00 < result < +π ÷ 2
ordinate > 0 and abscissa = 0result = +π ÷ 2
ordinate > 0 and abscissa < 0+π ÷ 2 < result < +π
ordinate = 0 and abscissa < 0result = +π
ordinate = 0 and abscissa = 0result is null