Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1186 | savelij | 1 | /* ibmfloat.c */ |
2 | /*****************************************************************************/ |
||
3 | /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */ |
||
4 | /* */ |
||
5 | /* AS-Portierung */ |
||
6 | /* */ |
||
7 | /* IBM Floating Point Format */ |
||
8 | /* */ |
||
9 | /*****************************************************************************/ |
||
10 | |||
11 | /***************************************************************************** |
||
12 | * Includes |
||
13 | *****************************************************************************/ |
||
14 | |||
15 | #include "stdinc.h" |
||
16 | #include <math.h> |
||
17 | #include <string.h> |
||
18 | |||
19 | #include "as_float.h" |
||
20 | #include "errmsg.h" |
||
21 | #include "asmerr.h" |
||
22 | #include "ibmfloat.h" |
||
23 | |||
24 | /*!------------------------------------------------------------------------ |
||
25 | * \fn as_float_2_ibm_float(Word *pDest, as_float_t Src, Boolean ToDouble) |
||
26 | * \brief convert floating point number to IBM single precision format |
||
27 | * \param pDest where to write result (2 words) |
||
28 | * \param Src floating point number to store |
||
29 | * \param ToDouble convert to double precision (64 instead of 32 bits)? |
||
30 | * \return 0 or error code |
||
31 | * ------------------------------------------------------------------------ */ |
||
32 | |||
33 | int as_float_2_ibm_float(Word *pDest, as_float_t Src, Boolean ToDouble) |
||
34 | { |
||
35 | as_float_dissect_t dissect; |
||
36 | unsigned dest_num_bits; |
||
37 | |||
38 | /* (1) Dissect IEEE number */ |
||
39 | |||
40 | as_float_dissect(&dissect, Src); |
||
41 | |||
42 | /* NaN or infinity not representable: */ |
||
43 | |||
44 | if ((dissect.fp_class != AS_FP_NORMAL) |
||
45 | && (dissect.fp_class != AS_FP_SUBNORMAL)) |
||
46 | return -EINVAL; |
||
47 | |||
48 | /* IBM format mantissa is in range [0.5,1) instead of [1,2): */ |
||
49 | |||
50 | dissect.exponent++; |
||
51 | |||
52 | /* (2) Convert 2^n exponent to multiple of four since IBM float exponent is to the base of 16. |
||
53 | Note that before shifting, we ad a zero bit at the end to avoid losing precision: */ |
||
54 | |||
55 | while (dissect.exponent & 3) |
||
56 | { |
||
57 | as_float_append_mantissa_bits(&dissect, 0, 1); |
||
58 | as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits); |
||
59 | dissect.exponent++; |
||
60 | } |
||
61 | |||
62 | /* (3) make base-16 exponent explicit */ |
||
63 | |||
64 | dissect.exponent /= 4; |
||
65 | |||
66 | /* (4) Round to target precision. We cannot use as_float_round() for rounding |
||
67 | since the exponent is already base-16: */ |
||
68 | |||
69 | dest_num_bits = ToDouble ? 56 : 24; |
||
70 | if (dest_num_bits > dissect.mantissa_bits) |
||
71 | as_float_round(&dissect, dest_num_bits); |
||
72 | else if (dest_num_bits < dissect.mantissa_bits) |
||
73 | { |
||
74 | Boolean round_up; |
||
75 | |||
76 | if (as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, dest_num_bits)) |
||
77 | { |
||
78 | if (!as_float_mantissa_is_zero_from(&dissect, dest_num_bits + 1)) /* > 0.5 */ |
||
79 | round_up = True; |
||
80 | else |
||
81 | round_up = !!as_float_get_mantissa_bit(dissect.mantissa, dissect.mantissa_bits, dest_num_bits - 1); |
||
82 | } |
||
83 | else /* < 0.5 */ |
||
84 | round_up = False; |
||
85 | |||
86 | if (round_up) |
||
87 | { |
||
88 | as_float_mant_word_t carry; |
||
89 | as_float_mant_t sum; |
||
90 | |||
91 | carry = as_float_mantissa_add_bit(sum, dissect.mantissa, dest_num_bits, dissect.mantissa_bits); |
||
92 | if (carry) |
||
93 | { |
||
94 | as_float_mantissa_shift_right(sum, carry, dissect.mantissa_bits); |
||
95 | as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits); |
||
96 | as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits); |
||
97 | as_float_mantissa_shift_right(sum, 0, dissect.mantissa_bits); |
||
98 | dissect.exponent++; |
||
99 | } |
||
100 | memcpy(dissect.mantissa, sum, sizeof dissect.mantissa); |
||
101 | } |
||
102 | as_float_remove_mantissa_bits(&dissect, dissect.mantissa_bits - dest_num_bits); |
||
103 | } |
||
104 | |||
105 | /* Overrange? */ |
||
106 | |||
107 | if (dissect.exponent > 63) |
||
108 | return -E2BIG; |
||
109 | |||
110 | /* number that is too small may degenerate to 0: */ |
||
111 | |||
112 | while ((dissect.exponent < -64) && !as_float_mantissa_is_zero(&dissect)) |
||
113 | { |
||
114 | as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits); |
||
115 | as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits); |
||
116 | as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits); |
||
117 | as_float_mantissa_shift_right(dissect.mantissa, 0, dissect.mantissa_bits); |
||
118 | dissect.exponent++; |
||
119 | } |
||
120 | |||
121 | /* Zero shall get zero (-64) as exponent: */ |
||
122 | |||
123 | if (as_float_mantissa_is_zero(&dissect)) |
||
124 | dissect.exponent = -64; |
||
125 | |||
126 | if (dissect.exponent < -64) |
||
127 | dissect.exponent = -64; |
||
128 | |||
129 | /* add bias to exponent */ |
||
130 | |||
131 | dissect.exponent += 64; |
||
132 | |||
133 | /* store result: */ |
||
134 | |||
135 | pDest[0] = (dissect.negative << 15) |
||
136 | | ((dissect.exponent << 8) & 0x7f00) |
||
137 | | as_float_mantissa_extract(&dissect, 0, 8); |
||
138 | pDest[1] = as_float_mantissa_extract(&dissect, 8, 16); |
||
139 | if (ToDouble) |
||
140 | { |
||
141 | pDest[2] = as_float_mantissa_extract(&dissect, 24, 16); |
||
142 | pDest[3] = as_float_mantissa_extract(&dissect, 40, 16); |
||
143 | } |
||
144 | |||
145 | return 0; |
||
146 | } |