Chapter 17:
Conversions for Floating–Point Formats
This chapter discusses conversion to and from the IBM floating point format. Specifically, the chapter covers the following four topics.
1. Conversion
of data in 32–bit fullword to a an equivalent value in
single–precision
floating–point format.
2. Conversion
of data in single–precision floating–point to a an equivalent value in
32–bit fullword format.
3. Conversion
of data in the Packed Decimal format to an equivalent value in
double–precision
floating–point format. We shall discuss
the problem of locating
the decimal point, which is
implicit in the Packed Decimal format.
4. Conversion
of data in double–precision floating–point to an equivalent value in
Packed Decimal format. This discussion may be a bit general, as the
detailed
assembler code is somewhat
difficult to design.
The true purpose of this chapter is to focus the reader’s attention on one of the many services provided by the RTS (Run–Time System) of a modern compiled high–level language. This is more of the text’s focus on assembler language as a tool to understanding the workings of a modern computer as opposed to being a language in which the reader is likely to program.
The IBM Mainframe Floating–Point Formats
The first thing to do in this presentation is to give a short review of the IBM Mainframe format for floating–point numbers. We might note that the modern Series Z machines, such as the z/10 running z/OS, support three floating–point formats: binary floating–point (the IEEE standard), decimal floating–point, and hexadecimal floating–point. The older S/370 series supported only what is called “hexadecimal” format. This format is so named because the exponent is stored as a power of 16. This chapter will use only two of the standard floating–point formats for the S/370: single–precision (E) and double–precision (D).
Each floating point number in this standard is specified by three fields: the sign bit, the exponent, and the fraction. The IBM standard allocates the same number of bits for the exponent of each of its formats. The bit numbers for each of the fields are shown below.
Format |
Sign bit |
Bits for exponent |
Bits for fraction |
Single precision |
0 |
1 – 7 |
8 – 31 |
Double precision |
0 |
1 – 7 |
8 – 63 |
In IBM terminology, the field used to store the representation of the exponent is called the “characteristic field”. This is a 7–bit field, used to store the exponent in excess–64 format; if the exponent is E, then the value (E + 64) is stored as an unsigned 7–bit number. This field is prefixed by a sign bit, which is 1 for negative and 0 for non–negative. These two fields together will be represented by two hexadecimal digits in a one–byte field.
Recalling
that the range for integers stored in 7–bit unsigned format is 0 £ N £ 127,
we have 0 £
(E + 64) £
127, or –64 £
E £
63. The size of the fraction field does
depend on the format.
Single precision 24 bits 6 hexadecimal digits,
Double precision 56 bits 14
hexadecimal digits.
The Sign Bit and
Characteristic Field
We now discuss the first two hexadecimal digits in the representation of a
floating–point number in these two IBM formats.
In IBM nomenclature, the bits are allocated as follows.
Bit 0 the sign bit
Bits 1 – 7 the seven–bit number storing the
characteristic.
Bit Number |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Hex digit |
0 |
1 |
||||||
Use |
Sign bit |
Characteristic (Exponent + 64) |
Consider the four bits that comprise hexadecimal digit 0. The sign bit in the floating–point representation is the “8 bit” in that hexadecimal digit. This leads to a simple rule.
If the number is not negative, bit 0 is 0, and hex digit 0 is one of 0, 1, 2,
3, 4, 5, 6, or 7.
If the number is negative, bit 0 is
1, and hex digit 0 is one of 8, 9, A, B, C, D, E, or F.
Some Single Precision
Examples
We now examine a number of examples, using the IBM single–precision
floating–point format. The reader will
note that the methods for conversion from decimal to hexadecimal formats are
somewhat informal, and should check previous notes for a more formal
method. Note that the first step in each
conversion is to represent the magnitude
of the number in the required form X·16E, after which we determine the sign and
build the first two hex digits.
Example 1: Positive
exponent and positive fraction.
The decimal number is
128.50. The format demands a
representation in the form X·16E, with 0.625 £ X < 1.0. As 128 £ X < 256, the number is
converted to the form X·162.
Note that 128 = (1/2)·162 = (8/16)·162 , and 0.5 =
(1/512)·162
= (8/4096)·162.
Hence, the value is 128.50 = (8/16 + 0/256 + 8/4096)·162; it is 162·0x0.808.
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first two hexadecimal digits in the eight digit representation are formed as follows.
Field |
Sign |
Characteristic |
||||||
Value |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
Hex value |
4 |
2 |
The fractional part comprises six hexadecimal digits, the
first three of which are 808.
The number 128.50 is represented as 4280
8000.
Example 2: Positive
exponent and negative fraction.
The decimal number is the negative number –128.50. At this point, we would normally convert the magnitude of the number to hexadecimal representation. This number has the same magnitude as the previous example, so we just copy the answer; it is 162·0x0.808.
We now build the first two hexadecimal digits, noting that the sign bit is 1.
Field |
Sign |
Characteristic |
||||||
Value |
1 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
Hex value |
C |
2 |
The number 128.50 is represented as C280 8000.
Note that we could have obtained this value just by adding 8 to the first hex
digit.
Example 3: Negative
exponent and positive fraction.
The decimal number is 0.375. As a fraction, this is 3/8 = 6/16. Put another way, it is 160·0.375 = 160·(6/16). This is in the required format X·16E, with 0.625 £ X < 1.0.
The exponent value is 0, so the characteristic value is either 64 or 0x40 = 100 0000. The first two hexadecimal digits in the eight digit representation are formed as follows.
Field |
Sign |
Characteristic |
||||||
Value |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
Hex value |
4 |
0 |
The fractional part comprises six hexadecimal digits, the
first of which is a 6.
The number 0.375 is represented in single precision as 4060 0000.
The number 0.375 is represented in double precision as 4060 0000 0000 0000.
Example 4: A Full
Conversion
The number to be converted is 123.45. As
we have hinted, this is a non–terminator.
Convert the integer part.
123 / 16 = 7 with remainder 11 this
is hexadecimal digit B.
7 / 16 = 0 with remainder 7 this
is hexadecimal digit 7.
Reading bottom to top, the integer part converts as 0x7B.
Convert the fractional part.
0.45 · 16 = 7.20 Extract the 7,
0.20 · 16 = 3.20 Extract the 3,
0.20 · 16 = 3.20 Extract the 3,
0.20 · 16 = 3.20 Extract the 3, and so on.
In the standard format, this number is 162·0x0.7B33333333…...
The exponent value is 2, so the characteristic value is either 66 or 0x42 = 100 0010. The first two hexadecimal digits in the eight digit representation are formed as follows.
Field |
Sign |
Characteristic |
||||||
Value |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
0 |
Hex value |
4 |
2 |
The number 123.45 is represented in single precision as 427B
3333.
The number 0.375 is represented in double precision as 427B 3333 3333 3333.
Example 5: True 0
The number 0.0,
called “true 0” by IBM, is stored as all zeroes [R_15, page 41].
In single precision it would be 0000
0000.
In double precision it would be 0000
0000 0000 0000.
The format of this “true zero” will be important when we consider conversions to and from the fullword format used for 32–bit integers. In particular, note that the bit field interpreted as a single–precision true zero will be interpreted as a 32–bit integer zero.
The structure of the formats facilitates conversion among them. For example, consider the positive decimal number 80.0, which in hexadecimal is X‘50’. Conversion of this to floating–point format involves noting that 80 = 64 + 16 = 256·(0/2 + 1/4 + 0/8 + 1/16). Thus the exponent of 16 is 2 and the characteristic field stores X‘42’. The fraction field for this number is 0101, which is hexadecimal 5. The representation of the number in the two standard IBM floating–point formats chosen for this chapter’s discussion is as follows.
Single precision (E) format 42 50 00 00
Double precision (D) format 42 50 00 00 00 00 00 00
Conversion from single precision to double precision format is quite easy. Just add 8 hexadecimal zeroes. Conversion from double precision to single precision is either easy or a bit trickier, depending on whether one truncates or attempts to round.
Convert the double precision value 42 50 00 00 11 10 00 00
Simple truncation will yield 42 50 00 00
A
reasonable rounding will yield 42
50 00 01
The Floating–Point Registers
In addition to the sixteen general–purpose registers (used for binary integer arithmetic), the S/360 architecture provides four registers dedicated for floating–point arithmetic. These registers are numbered 0, 2, 4, and 6. Each is a 64–bit register. It is possible that the use of even numbers to denote these registers is to emphasize that they are not 32–bit registers.
The use of
the registers by the floating–point operations depends on the precision:
Single precision formats use the
leftmost 32 bits of a floating–point register.
Double precision formats use all 64
bits of the register.
To illustrate this idea consider the two data declarations.
EFLOAT DS E
Declare a 32–bit single precision
DFLOAT DS D
Declare a 64-bit double precision
Consider the following instructions that use floating–point register 0. Remember that this register holds 64 bits, which is enough for a double–precision (D) floating–point value.
LD 0,DFLOAT
Load the full 64-bit register from
the double precision
64-bit value.
LE
0,EFLOAT Load the leftmost 32
bits of the register
from the single
precision 32-bit value.
The rightmost 32 bits
of the register are
not changed [R_15,
page 43].
STD
0,DFLOAT Store the 64 bits from
the register into
the 64-bit double
precision target.
STE
0,EFLOAT Store the leftmost 32
bits of the register
into the 32-bit single precision target.
Another Look at Two’s–Complement Integers
In order to develop the algorithms for converting between two’s–complement integers and floating–point formats, we must examine the structure of positive integers from a slightly different viewpoint, one that is of little view in the “pure integer” world.
We shall focus on conversions for positive fullword integers. As we shall see, handling negative integers is a simple extension of the above. Handling halfword integers is even easier, as we shall use the LH (Load Halfword) instruction to load them into a register. All of our conversions from integer format to floating–point format will assume that the integer argument is found in a general–purpose register.
The fullword
conversion code will begin with an instruction such as
L R9,FW
Load the fullword into register 9
The
halfword conversion code will begin with an instruction such as
LH R9,HW Load the halfword into register 9,
extending the sign to
make a fullword.
The handling of negative numbers is quite simple. We first declare a single–character (one byte) area called THESIGN, to hold a representation of the sign in a format that will assist the processing of the resulting floating point number.
For a
negative number, THESIGN will be set to X‘80’.
For a non–negative number, its value will be set to X‘00’.
In the
code, the location THESIGN would be declared as
follows [R_17, page 41].
THESIGN DS X1
One byte of storage
Here is a fragment of the code, assuming that the signed integer value is in R9. Note the use of the MVI instruction with the hexadecimal equivalent of a character [R_17, page 41].
MVC
THESIGN,=X‘00’ Initialize the sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVC
THESIGN,=X‘80’ Yes, it is negative.
LCR R9,R9
Get the absolute value
NOTNEG Now process the positive number in R9.
For ease of illustration I shall discuss the structure of a signed 16–bit halfword. As seen above, we may assume that the halfword represents a positive integer.
Hex digit |
|
0 |
1 |
2 |
3 |
||||||||||||
Power of 16 |
4 |
|
|
|
3 |
|
|
|
2 |
|
|
|
1 |
|
|
|
0 |
Power of 2 |
16 |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|
A0 |
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
A8 |
A9 |
A10 |
A11 |
A12 |
A13 |
A14 |
A15 |
In a signed halfword, the bits A0 through A15 would represent the binary bits of the 16–bit integer. As we have specified that we have a positive integer, we know that A0 = 0 and that at least one of the other bits is equal to 1.
The value of the halfword is A0·215 + A1·214 + A2·213 + A3·212 + … + A15·20.
Another way to write this would be as follows:
216·(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/216), which can also be written as
164·(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/216). This seems to be in a form that is ready for translation into the IBM floating–point representation. If one of A1, A2, or A3 is nonzero, this will work. The exponent will be 4 and the fraction A0A1A2A3…A15.
Please note that the IBM Single–Precision Floating–Point format is a 32–bit format, so the above should not be taken literally. It is just an indicator of where we need to go.
The above method, as extended to 32 bits, might work if it were not for the issue of normalization. All IBM floating point standards require that the first two bytes (four hex digits) of the representation be of the following format.
Digit |
0 |
1 |
2 |
3 |
Contents |
Sign
bit and 7–bit characteristic field holding the exponent. |
High
order bits of the fraction. At
least one non-zero bit. |
Next
four bits of the fraction. |
In other words, the value of hexadecimal digit 2 cannot be a zero. This is a requirement of the normalized representation, which calls for representing the floating–point value in the form 16E · F, where 1/16 £ F < 1.
In our 16–bit example, suppose that the four high order bits are all zero, but that at least one of the next four bits is not zero. What we have is of the following form.
Hex digit |
|
0 |
1 |
2 |
3 |
||||||||||||
Power of 16 |
4 |
|
|
|
3 |
|
|
|
2 |
|
|
|
1 |
|
|
|
0 |
Power of 2 |
16 |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|
0 |
0 |
0 |
0 |
A0 |
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
A8 |
A9 |
A10 |
A11 |
The value of the halfword is A0·211 + A1·210 + A2·29 + A3·28 + … + A11·20.
Another way to write this would be as follows:
212·(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/212), which can also be written as
163·(A0/2 + A1/4 + A2/8 + A3/16 + … + A15/212). This seems to be in a form that is ready for translation into the IBM floating–point representation. If one of A1, A2, or A3 is nonzero, this will work. The exponent will be 3 and the fraction A0A1A2A3…A11.
Before continuing our discussion, let us reflect on a method to detect whether or not the four high–order bits in a register are all zero. For this, we need to turn to the logical AND, which was covered in the last pages of Chapter 12 of this textbook.
The type of instruction I choose to use is the type RX logical AND instruction, N.
LR R8,R9 COPY R9 INTO R8 SO THAT THE FOUR
* HIGH ORDER
BITS CAN BE TESTED
* WITHOUT
LOSING THE VALUE.
* THE MASK
IS F0 00 00 00.
BNZ HAVE1 FOUND A 1 BIT.
Note that the block above is that to be used for 32–bit integers. The logical AND will raise the zero condition flag only when all bits in R8 become 0 after the operation.
The
The first thing to do is predict the largest exponent that can arise from converting a 32–bit fullword. The magnitude of such an integer cannot exceed 231 = 2,147,483,648, which is the same as 232 · 1/2. This value can be represented as 168 · 1/2, indicating that the largest exponent for a floating–point number converted from a fullword is 8.
The smallest positive integer is 1 = 161 · 1/16, indicating that the smallest exponent for a floating–point number converted from a fullword is 1. Recall that the characteristic field part of the floating–point representation contains the exponent stored in excess–64 format; the value stored is (Exponent + 64). The range of possible characteristics is from 72 down to 65.
In our example and in our code, we shall manipulate the characteristic directly.
A Fullword Example
The algorithm to be developed for fullwords will be inspired by the halfword example above. It will involve multiple shifts and logical operations to locate the most significant 1 bit and use the information obtained to generate the characteristic field and fraction. But first, let’s do a computation “by hand”. Our example is 32,685.
As a 16–bit integer, this can be represented as 0111 1111 1010 1101. In 32 bits it would be 0000 0000 0000 0000 0111 1111 1010 1101. To avoid this mess of ones and zeroes, this chapter will use hexadecimal notation; the value is 0000 7FAD.
This algorithm functions by testing the leftmost hexadecimal digit in the value, which represents the four high–order bits in the representation. If the digit is zero, the value is shifted left by four bits, equivalent to shifting one hexadecimal digit. The SLL (Shift Left Logical) instruction will be used for this task, as it pads the right with zeroes.
1. Start Characteristic = 72, Value = 0000 7FAD
The most significant digit is
0, so shift left and reduce the characteristic by 1.
2. Characteristic
= 71, Value = 0007 FAD0
The most significant digit is
0, so shift left and reduce the characteristic by 1.
3. Characteristic
= 70, Value = 007F AD00
The most significant digit is
0, so shift left and reduce the characteristic by 1.
4. Characteristic
= 69, Value = 07FA D000
The most significant digit is
0, so shift left and reduce the characteristic by 1.
5. Characteristic
= 68, Value = 7FAD 0000
The most significant digit is
not 0, so we have both our fraction and our characteristic
with value 68 or X‘44’. The fraction is X ‘7FAD00’.
The representation of this value in the 32–bit single–precision floating–point format is:
44 7F AD 00. Just for fun, let’s reverse engineer this value.
The
characteristic field is X‘44’, indicating an exponent of
4. The value represented is
164 ·
(7/16 + 15/162 + 10/163 + 13/164) = 7·163
+ 15·162
+ 10·16
+ 13 =
7·4096
+ 15·256
+ 160 + 13 = 28,672 + 3,840 + 173 = 32,685.
Why Convert to Single–Precision Floating–Point?
The topic of this section is the conversion of 32–bit fullword integer values into equivalent floating–point values. One might wonder why we have selected the single–precision format as the target, in preference to the double–precision floating–point (D) format.
One reason for the choice is simplicity; it is easier to discuss single–precision format in this context. Another reason is precision. The single–precision floating–point format has a precision of seven digits. A fullword has at most 10 digits, with the most significant digit being restricted to 0, 1, or 2; one might stay that the format has only nine digits. In other words, for most cases, conversion to the single–precision format does not lose accuracy.
Two Unusual Cases
There are two cases in which the above “shift left to find the most significant 1 bit” strategy does not work. In each of these cases, one finds that one of the bits in the leftmost byte of the 32–bit integer is not zero. Recall that the format of the single–precision floating–point format may be expressed as C C | F F F F F F, where the first byte (denoted C C) holds the sign bit and the characteristic field.
Consider the case illustrated below, in which we assume that not all of A0, A1, A2, and A3 are zero. Since the number is positive, we do know that A0 = 0, but that is not significant here.
Hex
Digit |
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
||||||
Power
16 |
8 |
|
|
|
7 |
|
|
|
6 |
|
|
|
|
|
|
Power
2 |
32 |
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
|
|
|
|
|
|
|
|
A0 |
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
A8 through A31 |
The value of the fullword is A1·230 + A2·229 + A3·228 + A4·227 + … + A31·20.
Another way to write this would be as follows:
232·(A1/4 + A2/8 + A3/16 + … + A31/232), which can also be written as
168·(A1/4 + A2/8 + A3/16 + … + A31/232). The single–precision floating–point format calls for an 8–bit field holding the sign and characteristic, followed by a 24–bit fraction, which here would be A0 through A23. The characteristic field would hold X‘48’, indicating a positive number with an exponent field of 8.
The conversion for this case is to start with the 32–bit (8 hexadecimal digit) value.
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
A24-A27 |
A28-A31 |
This is logically right shifted by 8 bits (2 hexadecimal digits) to get the value:
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
0000 |
0000 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
The two hexadecimal digits for the characteristic field are then inserted to get the final value.
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
4 |
8 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
The Other
Case
Consider now the second case. Again we assume that not all of A0, A1, A2, and A3 are zero.
Hex
Digit |
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
||||||
Power
16 |
8 |
|
|
|
7 |
|
|
|
6 |
|
|
|
|
|
|
Power
2 |
32 |
31 |
30 |
29 |
28 |
27 |
26 |
25 |
24 |
|
|
|
|
|
|
|
|
0 |
0 |
0 |
0 |
A0 |
A1 |
A2 |
A3 |
A4 through A27 |
The value of the fullword is A0·227 + A1·226 + A2·225 + A3·224 + A4·223 + … + A27·20.
Another way to write this would be as follows:
228·(A0/2 + A1/4 + A2/8 + A3/16 + … + A27/228), which can also be written as
167·(A0/2 + A1/4 + A2/8 + A3/16 + … + A27/228). The characteristic field is X‘47’.
Remember that the single–precision format calls for a 24–bit fraction field.
The conversion for this case is to start with the 32–bit (8 hexadecimal digit) value.
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
0000 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
A24-A27 |
This is logically right shifted by 8 bits (2 hexadecimal digits) to get the value:
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
0000 |
0000 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
The two hexadecimal digits for the characteristic field are then inserted to get the final value.
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
4 |
7 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
The “Left
Shifter” Cases
In all other cases, the positive integer to be converted has the following format.
Digit |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
0000 |
0000 |
A0-A3 |
A4-A7 |
A8-A11 |
A12-A15 |
A16-A19 |
A20-A23 |
The two hexadecimal digits that will be occupied by the characteristic field are already clear, so we do not require any right shifting to move the most significant part of the fraction to its proper location. We are only assured that at least one of bits A0 through A23 is not zero. The procedure to follow is the test and shift left procedure sketched above for the halfword case.
The operation to be used in left shifting register R9 will be the SLL (Logical Left Shift), which will insert 4 binary zeroes on the right part of R9 every time it is left shifted by 4 bits. This usage is consistent with building a fraction with trailing zeroes; 0.4 = 0.400000.
At the end of the code to be developed, we shall store the integer contents of a the register R9 into a word declared to be in single–precision floating–point format. Note that both the fullword (F) format and single–precision (E) floating–point formats are 32–bit (four byte) formats, so that one value can be stored into another.
What we are doing here is manipulating each part of the formatted number as if it were an integer, and then creating a bit pattern that will bear interpretation as a floating–point value.
Here is the code developed as a result of the discussions so far. The assumption is that the integer value to be converted is found in general–purpose register R9 and that the result is to be deposited in an area of memory declared as EFLOAT DS E.
MVI
THESIGN,X‘00’ Initialize the
sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI
THESIGN,X‘80’ Yes, it is
negative.
LCR R9,R9 Get the absolute value
NOTNEG LR R8,R9 Get a copy into R8
* At this point, R9 will contain the
value as it is
* being transformed from 32–bit
integer format into
* Single-Precision Floating-Point
format.
* R8 is a work register used to
test values.
N
R8,=X‘F0000000’ Is the high-order
hex digit 0
BZ D0IS0 Yes, not this special case
SRL R9,8 Clear out the characteristic
O R9,=X’48000000’ Set the exponent
B SETSIGN Set the sign
D0IS0 LR
R8,R9 Get the value
back into R8
BZ D1IS0 Yes, not this special case
SRL R9,4
Clear out the
characteristic
O R9,=X‘47000000’ Set the exponent
B SETSIGN Set the sign
*
* Here we make sure that the two
high-order digits in
* R9 are zero, and test that we
have a positive value.
*
D1IS0 N R9,=X‘00FFFFFF’ Sanity check: is any bit = 1
BZ SETSIGN NO, the result is 0
LFTSHFT EQU *
* Here we do the left shifting of
the number to
* generate the proper
characteristic field and
* normalized fraction.
SETSIGN SR
R8,R8 Set R8 to zero
IC R8,THESIGN Get the sign byte into R8
CH R8,=H‘0’ Is it zero (non-negative)?
BZ DONE Yes, value is not negative
O R9,=X‘80000000’ Set the sign bit
DONE ST
R9,EFLOAT Store the result
into the
* 32-bit
field EFLOAT
Left Shifting
Having disposed of the two cases that are unusual due to the bit structure of the single–precision floating–point format, let us consider the “more general” case. In this case, the first two hexadecimal digits of the integer value are 0 and one (or more) of the other six is non–zero. From a magnitude consideration, this covers numbers with integer values at least 1 and less than 224 = 16,777,216. Many commonly used integer values easily fit within this range.
The preconditions for this section of the code are simple. Register R9 contains the absolute value of the integer, with the sign having been tested and recorded for use later. As noted above, this magnitude is not greater than 16,777,215, which in hexadecimal is X‘FFFFFF’.
LFTSHFT
ISD3A0 LR R8,R9 Copy value into R8
BNZ SETVAL Yes, it is non-zero.
SHL R9,4 No, it is not. Shift left by 4
* bits to
examine another digit
B ISD3A0 Try again
SETVAL EQU *
There is quite a bit missing from the above loop. What we need to do is begin with the characteristic field as X‘46’, or decimal 70, representing an exponent of +6. As each test reveals digit 3 to be zero, we need to count down the exponent and shift left. The lowest admissible exponent is 1, represented in the characteristic field as 65 or X‘41’.
The construct appropriate for this is BXH, which will branch on a value higher than X‘41’. Recall the format of the source code for this instruction.
BXH
Register,Register_Pair,Target_Address
Where Register denotes a register containing a count; here the characteristic field.
Register_Pair
contains the even register of an even–odd pair.
The even register
contains a value to be used in incrementing the count.
The odd register
contains a value to be used as a limit.
Target_Address contains the branch target.
The design here is to start the characteristic field at X‘46’, representing an exponent of +6. For each time the digit is found to be zero, we shift left by 4 bits (one hexadecimal digit), and decrement the exponent. This continues until the characteristic field is X‘41’, indicating the smallest characteristic field for a positive non–zero integer.
With R8 and
R9 in use, this design calls for the following.
R6 and R7 are selected as the
even–odd register pair.
R5 will be used to hold the
value of the characteristic field.
Here is an
example of the shift strategy. Let R9
contain X‘0000
2BAD’. (R5) = X‘46’.
Is digit 3 a 0? Yes. Shift left and decrement (R5). X‘0002 BAD0’. (R5) = X‘45’.
Is digit 3 a 0? Yes. Shift left and decrement (R5). X‘002B AD00’. (R5) = X‘44’.
Is digit 3 a 0? No, it is not. Keep (R9) = X‘002B AD00’ and (R5)
= X‘44’.
The answer is that the floating–point representation is X‘442B AD00’.
Here is the code.
MVI
THESIGN,X‘00’ Initialize the
sign field
CH R9,=H‘0’ Look at the integer value
BZ DONE It is zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI
THESIGN,X‘80’ Yes, it is
negative.
LCR R9,R9 Get the absolute value
NOTNEG LR R8,R9 Get a copy into R8
* At this point, R9 will contain the
value as it is
* being transformed from 32–bit
integer format into
* Single-Precision Floating-Point
format.
N
R8,=X‘F0000000’ Is the high-order
hex digit 0
BZ D0IS0 Yes, not this special case
SRL R9,8 Clear out the characteristic
O R9,=X’48000000’ Set the exponent
B SETSIGN Set the sign
D0IS0 LR
R8,R9 Get the value
back into R8
BZ D1IS0 Yes, not this special case
SRL R9,4 Clear out the characteristic
O R9,=X‘47000000’ Set the exponent
B SETSIGN Set the sign
D1IS0 N
R9,=X‘00FFFFFF’ Sanity check: is
any bit = 1
BZ SETSIGN NO, the result is 0
LFTSHFT LH
R5,=H‘70’ Start value for
characteristic
LH R6,=H‘-1’ Increment value.
LH R7,=H‘65’ Limit value
ISD3A0 LR
R8,R9 Copy value into R8
BNZ SETVAL Yes, it is non-zero.
SHL R9,4 No, it is not. Shift left by 4
BXH R5,R6,ISD3A0 Try again
SETVAL SHL R5,24 Move characteristic into place
OR R9,R5 Create the number
SETSIGN SR
R8,R8 Set R8 to zero
IC R8,THESIGN Get the sign byte into R8
CH R8,=H‘0’ Is it zero (non-negative)?
BZ DONE Yes, value is not negative
O R9,=X‘80000000’ Set the sign bit
DONE ST
R9,EFLOAT Store the result
into the
* 32-bit
field EFLOAT
Conversion of Single–Precision Floating–Point to Integer
Here again, the first step is to detect and note the sign of the number. We shall focus on converting positive values, with the sign added at the end of the conversion process. In this case the process of “adding the sign” will be that of taking the two’s complement.
The process
will begin with the floating–point value stored in location EFLOAT, declared
as:
EFLOAT DS E
A 32–bit (4 byte) storage allocation.
Note however that, throughout this conversion, EFLOAT will be treated as if it were a 32–bit fullword integer. Again, we are processing this bit by bit, and hexadecimal digit by hex digit. We are not really interested in its value when considered as a floating point number.
The first step is to access this four–byte location using an integer instruction.
L R9,EFLOAT
Now, we use a characteristic common to both integer and floating–point arithmetic. If bit 0 (the leftmost bit) of the 32–bit representation is 1, the number is negative. Otherwise, the number is non–negative, and might be zero. We immediately test for this.
Recall two
things when examining the code below.
1. The
value X‘00000000’,
viewed as a single–precision floating–point value is
what IBM calls a “true
zero”. It converts to integer zero.
2. The
value X‘7FFFFFFF’
represents a 32–bit number in which all bits, save bit 0
(the sign bit) are 1. We use this to mask out the sign bit and keep
in R9 a value
that would be interpreted as
the absolute value of the floating–point number.
MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH R9,=H‘0’
and examine the sign bit.
BZ
DONE The value is
zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
The next section of code reflects the fact that, if the fraction part of the representation is zero, then the value represented is 0 without regard to the characteristic field.
NOTNEG LR R8,R9 Copy the value into R8
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ EQU * Keep on processing.
We now check the range of the characteristic field to determine if the exponent is consistent with conversion to an fullword integer. If the characteristic is less than 65 (X‘41’), the value is less than 1 and will be converted to a 0. If the characteristic is greater than 72 (X‘48’), the magnitude is too large to be represented as a fullword. What the code should do in this situation is up to the designer; here we set the integer to the maximum value. This is probably a poor design choice, but for now it is as good as any. Here is this code.
LR R8,R9 Copy the value into R8
SRL R8,24 Shift to least significant byte
CH R8,=H‘64’ Is exponent big enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9 No, set result to zero
B DONE and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ Biggest positive number
B SETVAL Go adjust the sign.
CANDO EQU * Value can be converted.
Here is the code as it exists at this point.
MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH
R9,=H‘0’ and examine the sign bit.
BZ
DONE The value is
zero, nothing to do.
BNL NOTNEG Is the value negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
NOTNEG LR R8,R9 Copy the value into R8
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ LR R8,R9 Copy the value into R8
SRL R8,24 Shift to least significant byte
CH
R8,=H‘64’ Is exponent big
enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9 No, set result to zero
B DONE
and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ This is the biggest positive number
B SETVAL Go adjust the sign.
CANDO EQU * Value can be converted.
* Here is the code
for processing the values that
* can be converted into a
fullword 32–bit integer.
SETVAL SR R8,R8 Set R8 to 0.
IC R8,THESIGN Load the sign value
CH R8,=H‘0’ Is the sign bit set?
BZ
ISPOS No, we are OK
LCR R9,R9 Negate the absolute value
DONE EQU * We are done here.
Now we discuss the code for converting those floating point values that can be converted into positive fullword values. This code will use SLDL (Shift Left Double Logical).
We begin with another test to account for a case that cannot be converted. When the characteristic field is X‘48’ (decimal 72, representing an exponent of 8) and the most significant bit in the fraction is a 1, the absolute value will be not less than 231, which cannot be represented as a fullword integer. In other words, we are looking for this value.
Digit |
0 |
1 |
2 |
3 – 7 |
|
4 |
8 |
1 A1 A2 A3 |
A4-A23 |
We use the SLDL instruction on the register pair (8, 9). At first, we shall clear R8 and shift the two high–order hexadecimal digits of R9 into it (SLDL by 8 bits). If this value is not X‘48’, we proceed with the conversion. Otherwise one more SLDL will tell the tale.
CANDO SR
R8,R8 Set R8 to zero
SLDL R8,8 Shift two high-order digits into R8
CH R8,=H‘72’ Is the exponent an 8?
BL DOIT Yes, we can continue
*
* At this point, the most
significant fraction bit occupies
* the sign bit in R9. Check to see if R9 is negative.
*
CH
R9,=H‘0’ Is the sign bit
set?
BP DOIT No, the high-order fraction bit is
0
L R9,=X‘7FFFFFFF’ Set to the biggest positive integer
B SETVAL Go adjust the sign.
At this point, the register values are as
follows:
1. R8
contains the characteristic value, equal to (Exponent + 64).
2. R9
contains the fraction in which the most significant hex digit is not 0.
This is a result of the fact
that the number was stored in a normalized format.
3. The
low order eight bits (two hexadecimal digits) of R9 are all zero.
This is due to the execution
of the logical left shift SLDL.
The final processing of R9 to produce an
integer that contains the absolute value of the desired result is to shift it
right by a count related to the exponent.
This will shift some
1 bits off the right, thus truncating the value. The requirements are as follows.
Characteristic |
Exponent |
Shift right by |
72 |
8 |
0 bits |
71 |
7 |
4 bits (1 hexadecimal digit) |
70 |
6 |
8 bits (2 hexadecimal digits) |
69 |
5 |
12 bits (3 hexadecimal digits) |
68 |
4 |
16 bits (4 hexadecimal digits) |
67 |
3 |
20 bits (5 hexadecimal digits) |
66 |
2 |
24 bits (6 hexadecimal digits) |
65 |
1 |
28 bits (7 hexadecimal digits) |
The formula for the shift count is seen to be (72 – Characteristic)·4.
Here is the code to do that computation
and produce the absolute value of the integer.
Recall that the source code format of the logical right shift can be in the
following form.
SRL
R1,D2(B2) in which the shift amount is determined by adding the
value in D2
to the contents of the register indicated by B2. This is base/displacement form used to
compute a number and not an address.
DOIT SH R8,=H‘72’
Produce (Characteristic – 72)
LCR R8,R8
Produce (72 – Characteristic)
SLL R8,2
Multiply by 4
SRL R9,0(R8)
Shift R9 by the amount in R8
Let’s try a
few examples to see if this works.
1. A
large positive number. In hexadecimal,
it is represented as 46 7F 03 00.
Note immediately that the characteristic field is X‘46’, so that the
exponent is 6. We first compute the
value directly; it is 166·(7/16
+ 15/256 + 0/163 + 3/164) =
7·165
+ 15·164
+ 3·162
=
7·1048576
+ 15·65536
+ 3·256
=
7340032
+ 983040 + 768 = 8,323,840.
We now apply our algorithm. At the time that the characteristic is tested, R8 contains decimal 70 and R9 contains 7F 03 00 00. The algorithm calls for a logical right shift of R9 by 8 bits or 2 hexadecimal digits. The new value is X‘007F0300’, which represents the value 0·167 + 0·166 +7·165 + 15·164 + 0·163 + 3·162 + 0·16 + 0, the value above.
2. A
much smaller number related to the above.
It is represented as 42 7F 03 00. I have elected to keep
the same fraction to simplify my work in doing the calculations. We first compute the value directly; it is 162·(7/16 + 15/256 + 0/163
+ 3/164) =
7·16 +
15 + 3/256 =
112
+ 15 + 0.01171875 = 127.01171875.
We now apply our algorithm. At the time that the characteristic is tested, R8 contains decimal 66 and R9 contains 7F 03 00 00. The algorithm calls for a logical right shift of R9 by 24 bits or 6 hexadecimal digits. The new value is X‘0000007F’, which represents the value 0·167 + 0·166 +0·165 + 0·164 + 0·163 + 0·162 + 7·16 + 15, which is 127. Note that this integer conversion has simply dropped the fractional part. Writing code to round off is not very tricky; your author just elects not to do it.
Here is a sketch of one approach to the round–off question. This will be based on the use of the shift right logical double instruction SRDL. The value to be converted must be placed in the even register of an even–odd register pair and the odd register cleared. To illustrate, suppose that it is R8 that contains the value, represented as 43 7F 03 00.
1. Clear R9. The register pair contains 43 7F 03 00 | 00 00 00 00.
2. Shift
right double by 5 digits to get 00 00
04 37 | F0 03 00 00
3. The
bit pattern in R8 represents the integer 4·256 + 3·16 +
7 = 1079
The bit pattern in R9
represents a fraction (15/16 + 3/164), bigger than 0.50.
This is noted by detecting the
sign bit in R9.
4. Round off the value to 1080.
Packed Decimal Format to Floating–Point
Here we face a problem with no precise solution unless we give some additional input. Recall that a number in the packed decimal format is represented by a sequence of hexadecimal digits (all having decimal values in the range 0 through 9) followed by a single hexadecimal digit in the range X‘A’ through X‘F’. Such a number may have from 1 through 31 decimal digits, with the trailing sign digit being necessary.
The routine for this conversion will be based on selecting individual digits from the packed format, one at a time. For this purpose, the digits will be numbered left to right in a manner reminiscent of the bit numbering used in a register. Consider the following.
Digit
number 0 1 2 3 4 5 6 7 8 9 A
Value 3 1 4 1 5 9 2 6 5 3 6
The reason that this has no precise solution is that the decimal place is not explicitly specified in the packed format representation of the value. Since we recognize this value as an approximate representation of the value p, we know the number is 3.1415926536. There are ten digits to the right of the decimal point and just one before it. In our representation we shall specify the value as a pair: (packed value, digit position).
The value here would be (31415926536C, 10), indicating that we produce the floating point value corresponding to the integer value 31415926536 and then divide that by 1010. At this point, we do not care that the integer just given cannot be represented as either a halfword or fullword by the S/370; this is just a conceptual calculation. All of our arithmetic here will be done in double–precision floating–point format.
Design of the Algorithm:
Preconditions and Subprograms Used
The
algorithm and its implementation in assembly language are designed assuming
that:
1. The
packed decimal value is found at location PACKNUM, and is
validly formatted.
In particular, the number has
no more than 31 decimal digits and has a sign digit.
2. The
sign digit is either X‘B’ or X‘D’ for a negative
number or one of X‘A’, X‘C’,
X‘E’, or X‘F’
for a non–negative number.
3. The digits in the number will be indexed by a value from 0 possibly through 31.
4. One
subroutine and one array will be used to help the computation. The subroutine
accepts the digit index in R8
and returns the hexadecimal value of the digit in R9.
The array is an array of double–precision
floating–point values in which the
Kth entry, at offset K·4,
contains the equivalent of float(K).
5. The
digits are scanned left to right until a sign digit is found. The numeric digits
are processed very much as was
done for the EBCDIC to integer direct conversion,
except that floating–point
arithmetic is used.
6. The result will be found in floating–point register 0.
7. As
a precaution, the loop will be controlled by a BXLE instruction, to
guarantee
that no more than 32 hexadecimal
digits are processed.
8. Each addressable byte
contains two hexadecimal digits, each of which must be
retrieved individually to
compute the value of the Packed Decimal number.
Here is the subprogram used to return the hexadecimal value of a digit. The basic processing is first to convert the digit offset into a byte offset and then to move the digit into position.
The digit position is converted to a byte offset by division by 2. Consider the example:
PI DC
P ‘31415926536’
What is stored is shown in the following table.
Address |
PI |
PI+1 |
PI+2 |
PI+3 |
PI+4 |
PI+5 |
Value |
31 |
41 |
59 |
26 |
53 |
6C |
The goal of this routine is to get the hexadecimal value of the digit into the low–order four bits of the general–purpose register 9 and have all other hexadecimal digits equal to 0.
Consider the processing of the digit at
offset 2.
This is the digit 4.
1. The
digit index in R8 is forced to be in the range [0,31].
2. The
index is copied into R7 and converted to a byte offset. This offset is 1.
3. The
byte with value X‘41’ is loaded into R9.
4. The
digit index is tested for being odd. It
is not, so there is a logical right
shift to place the first digit
into the least significant place. R9 now
has X‘4’.
5. The
seven high–order hex digits in R9 are masked out, returning the value X‘4’.
Consider the processing of the digit at
offset 3.
This is the digit 1.
1. The
digit index in R8 is forced to be in the range [0,31].
2. The
index is copied into R7 and converted to a byte offset. This offset is 1.
3. The
byte with value X‘41’ is loaded into R9.
4. The
digit index is tested for being odd. It
is odd, so there is a logical right so no
right shifting is
required. R9 now has X‘41’.
5. The
seven high–order hex digits in R9 are masked out, returning the value X‘1’.
Here is the complete subroutine to get the digit. It is called “GETDIGIT”.
* Index of digit is in register R8. Value of
R8 is preserved
* The value of the digit is returned
in R9.
* R7 is used but not saved. R4 contains the return address.
*
GETDIGIT
LR R7,R8 COPY VALUE OF DIGIT INDEX INTO R7
SRL R7,1 CONVERT INTO BYTE OFFSET
SR R9,R9 SET R9 TO ZERO
IC R9,PACKNUM(R7) GET THE BYTE INTO R7
*
LR R7,R8 GET THE DIGIT INDEX BACK INTO R7
BNZ
ISODD IF UNIT BIT IS NOT
0, INDEX IS ODD
SRL R9,4 SHIFT TO GET DIGIT INTO POSITION
ISODD
*
* R9 NOW CONTAINS THE NUMERIC VALUE OF THE
DIGIT.
* IF VALUE > 9, THE
DIGIT IS THE SIGN DIGIT.
BR R4 R4 contains the return address.
The array in question is just a table holding the double–precision floating–point values equivalent to the first ten non–negative integers (0 through 9), as well as the value 10.0 (which will be used for multiplication in forming the number). This is just the easiest way to convert a single digit positive integer into its equivalent floating–point value.
* CONVERT SINGLE DIGIT
INTEGER TO FLOATING POINT.
*
* USE: PLACE VALUE INTO INDEX
REGISTER, THEN SLL 2
* LD 2,FPVALS(Index Register)
FPVALS DC D‘0.0’
FPV1 DC D‘1.0’
FPV2 DC D‘2.0’
FPV3 DC D‘3.0’
FPV4 DC D‘4.0’
FPV5 DC D‘5.0’
FPV6 DC D‘6.0’
FPV7 DC D‘7.0’
FPV8 DC D‘8.0’
FPV9 DC D‘9.0’
FPV10 DC D‘10.0’
Here is the code for the conversion routine.
PACKTOFP LD
0,FPVALS GET THE 0
ENTRY. CLEAR FP REG 0
* NOW SET UP FOR
THE BXLE INSTRUCTION
*
SR R8,R8
SET COUNT TO 0. THIS IS THE DIGIT
INDEX
LH R10,=H‘1’
LOOP INCREMENT IS 1, MOVE LEFT TO RIGHT
LH R11,=H’31’
LIMIT ON THE DIGIT INDEX
CONVERT BAL R4,GETDIGIT GET THE DIGIT AT INDEX = R8
CH R9,=H‘10’ DIGIT VALUE RETURNED IN R9
BNL DONE WE HAVE THE SIGN DIGIT
MD 0,FPV10
MULTIPLY CURRENT VALUE BY
10.0
SLL R9,2 MULTIPLY DIGIT VALUE BY 4
LD 2,FPVALS(R9) GET FP VALUE OF THE DIGIT
ADR 0,2 ADD TO ACCUMULATING RESULT
BXLE R8,R10,CONVERT GO GET ANOTHER DIGIT
DONE LH R8,DECPLACE GET THE DECIMAL PLACE INDICATOR
CH R8,=H‘0’ IS IT POSITIVE
BNH SETSIGN NO, JUST SET THE SIGN
ADJUST DD 0,FPV10 DIVIDE TO ADJUST TO DECIMAL POINT
BCT R8,ADJUST KEEP DIVIDING UNTIL VALUE IS RIGHT
SETSIGN CH
R9,=H‘11’ R9 HAS SIGN
DIGIT. IS IT X‘B’?
BE ISNEG YES, THE VALUE IS NEGATIVE
CH R9,=H‘13’ R9 HAS SIGN DIGIT. IS IT X‘D’?
BNE FINISH NO.
THE VALUE IS POSITIVE
ISNEG LDR 2,0 COPY VALUE TO FP REGISTER 2
SDR 0,0 SET FP REGISTER TO 0
SDR 0,2 NOW FP 0 HAS BEEN NEGATED
FINISH BR R3 ALL DONE.
Floating–Point to Packed Decimal Conversion
When considering this conversion, one is presented with a number of technical difficulties in handling the floating–point as well as issues due to the fundamental incompatibility of the two formats under consideration. All are difficult, but none are insurmountable.
Here are some of the issues that must be addressed.
1. How
to produce repeatedly the most significant decimal digit from a floating–point
representation, and when to
stop producing these digits. The floating–point
formats” call for
single–precision to have 7 digits significant, and double–precision to have
15 digits significant. Do we stop at these counts?
Consider the number 1.2345·107,
which of course will be represented in the IBM
formats using hexadecimal
notation. We want to extract the
exponent as 7, and then
extract the digits 1, 2, 3, 4,
and 5 in that order. The answer might be
012345000C.
2. As
a related issue, how at any time to determine the largest power of ten that is
not
larger than the absolute value
of the floating–point number being converted.
The
simple way to do this appears
to be quite verbose and tedious.
3. The
position of the decimal point in any floating–point representation is important
and almost explicitly
specified in the representation. The
position of the decimal
point for the Packed Decimal
format is assumed in the code and not stored in the
format. We got around this for the Packed Decimal to
Floating–Point conversion by
by specifying the position of
the decimal, but this not a part of the standard.
One obvious way to convert from floating–point to packed decimal is first to convert the value to a fullword integer and then to convert that value (using CVD) to Packed Format. This will work for floating–point values that represent integers within the proper range, but any fractional digits will be lost.
This issue of converting from Floating–Point to Packed Decimal is closely related to the problem of providing a print representation for floating–point values. As the author of your textbook, I intend to continue investigating these two conversion issues.
Any
solutions found that are suitable for publishing in a textbook will appear in
the
next revision.
Here is the complete code for the floating–point to integer conversion.
MVI THESIGN,X‘00’ Initialize the sign field
L R9,EFLOAT Load the floating-point value
CH R9,=H‘0’
and examine the sign bit.
BZ
DONE The value is
zero, nothing to do.
BNL
NOTNEG Is the value
negative?
MVI THESIGN,X‘80’ Yes, it is negative.
N R9,=X‘7FFFFFFF’ Zero out the sign bit.
NOTNEG LR R8,R9 Copy the value into R8
BNZ FRNZ No, keep on working
SR R9,R9 Yes, the value is zero. So set
B DONE the result as 0 and exit.
FRNZ LR R8,R9 Copy the value into R8
SRL R8,24 Shift to least significant byte
CH R8,=H‘64’ Is exponent big enough?
BH OVER1 Yes, number is not < 1.
SR R9,R9
No, set result to zero
B DONE and be done with it.
OVER1 CH R8,=H‘72’ Is the exponent too big?
BNH CANDO NO, it is fine.
L R9,=X‘7FFFFFFF’ This is the biggest positive number
B SETVAL Go adjust the sign.
CANDO SR R8,R8 Set R8 to zero
SLDL R8,8 Shift two high-order digits into R8
CH R8,=H‘72’ Is the exponent an 8?
BL DOIT Yes, we can continue
CH R9,=H‘0’ Is the sign bit set?
BP DOIT No, the high-order fraction bit is
0
L R9,=X‘7FFFFFFF’ Set to the biggest positive integer
B SETVAL Go adjust the sign.
DOIT SH R8,=H‘72’ Produce (Characteristic – 72)
LCR R8,R8 Produce (72 – Characteristic)
SLL R8,2 Multiply by 4
SRL R9,0(R8) Shift R9 by the amount in R8
SETVAL SR R8,R8
Set R8 to 0.
IC R8,THESIGN Load the sign value
CH R8,=H‘0’ Is the sign bit set?
BZ ISPOS No, we are OK
LCR R9,R9
Negate the absolute value
DONE EQU *
We are done here.