Utility function to split a double-precision float (F64) into a pair of F32s. For a p-bit number, and a splitting point (p/2) <= s <= (p - 1), the algorithm produces a (p - s)-bit value 'hi' and a non-overlapping (s - 1)-bit value 'lo'. See Theorem 4 in [1] (attributed to Dekker) or [2] for the original theorem by Dekker. For double-precision F64s, which contain a 53 bit mantissa (52 of them expl
| 330 | // [2] T. J. Dekker, A floating point technique for extending the available |
| 331 | // precision, Numerische Mathematik, vol. 18, pp. 224–242, 1971. |
| 332 | std::pair<float, float> SplitF64ToF32(double x) { |
| 333 | const float x_f32 = static_cast<float>(x); |
| 334 | // Early return if x is an infinity or NaN. |
| 335 | if (!std::isfinite(x)) { |
| 336 | return std::make_pair(x_f32, 0.0f); |
| 337 | } |
| 338 | |
| 339 | // Only values within the range of F32 are supported, unless it is infinity. |
| 340 | // Small values with large negative exponents would be rounded to zero. |
| 341 | CHECK(std::isfinite(x_f32)) << x; |
| 342 | |
| 343 | // The high float is simply the double rounded to the nearest float. Because |
| 344 | // we are rounding to nearest with ties to even, the error introduced in |
| 345 | // rounding is less than half an ULP in the high ULP. |
| 346 | const float hi = x_f32; |
| 347 | // We can compute the low term using Sterbenz' lemma: If a and b are two |
| 348 | // positive floating point numbers and a/2 ≤ b ≤ 2a, then their difference can |
| 349 | // be computed exactly. |
| 350 | // Note: the difference is computed exactly but is rounded to the nearest |
| 351 | // float which will introduce additional error. |
| 352 | const float lo = static_cast<float>(x - static_cast<double>(hi)); |
| 353 | return std::make_pair(hi, lo); |
| 354 | } |
| 355 | |
| 356 | } // namespace xla |