Parse a vector of float values representing IBM 8 byte floats into native 8 byte floats.
(vec)
| 177 | |
| 178 | |
| 179 | def _parse_float_vec(vec): |
| 180 | """ |
| 181 | Parse a vector of float values representing IBM 8 byte floats into |
| 182 | native 8 byte floats. |
| 183 | """ |
| 184 | dtype = np.dtype(">u4,>u4") |
| 185 | vec1 = vec.view(dtype=dtype) |
| 186 | xport1 = vec1["f0"] |
| 187 | xport2 = vec1["f1"] |
| 188 | |
| 189 | # Start by setting first half of ieee number to first half of IBM |
| 190 | # number sans exponent |
| 191 | ieee1 = xport1 & 0x00FFFFFF |
| 192 | |
| 193 | # The fraction bit to the left of the binary point in the ieee |
| 194 | # format was set and the number was shifted 0, 1, 2, or 3 |
| 195 | # places. This will tell us how to adjust the ibm exponent to be a |
| 196 | # power of 2 ieee exponent and how to shift the fraction bits to |
| 197 | # restore the correct magnitude. |
| 198 | shift = np.zeros(len(vec), dtype=np.uint8) |
| 199 | shift[np.where(xport1 & 0x00200000)] = 1 |
| 200 | shift[np.where(xport1 & 0x00400000)] = 2 |
| 201 | shift[np.where(xport1 & 0x00800000)] = 3 |
| 202 | |
| 203 | # shift the ieee number down the correct number of places then |
| 204 | # set the second half of the ieee number to be the second half |
| 205 | # of the ibm number shifted appropriately, ored with the bits |
| 206 | # from the first half that would have been shifted in if we |
| 207 | # could shift a double. All we are worried about are the low |
| 208 | # order 3 bits of the first half since we're only shifting by |
| 209 | # 1, 2, or 3. |
| 210 | ieee1 >>= shift |
| 211 | ieee2 = (xport2 >> shift) | ((xport1 & 0x00000007) << (29 + (3 - shift))) |
| 212 | |
| 213 | # clear the 1 bit to the left of the binary point |
| 214 | ieee1 &= 0xFFEFFFFF |
| 215 | |
| 216 | # set the exponent of the ieee number to be the actual exponent |
| 217 | # plus the shift count + 1023. Or this into the first half of the |
| 218 | # ieee number. The ibm exponent is excess 64 but is adjusted by 65 |
| 219 | # since during conversion to ibm format the exponent is |
| 220 | # incremented by 1 and the fraction bits left 4 positions to the |
| 221 | # right of the radix point. (had to add >> 24 because C treats & |
| 222 | # 0x7f as 0x7f000000 and Python doesn't) |
| 223 | ieee1 |= ((((((xport1 >> 24) & 0x7F) - 65) << 2) + shift + 1023) << 20) | ( |
| 224 | xport1 & 0x80000000 |
| 225 | ) |
| 226 | |
| 227 | ieee = np.empty((len(ieee1),), dtype=">u4,>u4") |
| 228 | ieee["f0"] = ieee1 |
| 229 | ieee["f1"] = ieee2 |
| 230 | ieee = ieee.view(dtype=">f8") |
| 231 | ieee = ieee.astype("f8") |
| 232 | |
| 233 | return ieee |
| 234 | |
| 235 | |
| 236 | class XportReader(SASReader): |