Commit 06cdd1c3 authored by Dominik Charousset's avatar Dominik Charousset

Fix packing/unpacking of NaN and infinite values

parent 47ebe211
......@@ -22,6 +22,7 @@
#include <cmath>
#include <cstdint>
#include <limits>
namespace caf::detail {
......@@ -34,6 +35,11 @@ struct ieee_754_trait<float> {
static constexpr uint32_t expbits = 8; // bits used for exponent
static constexpr float zero = 0.0f; // the value 0
static constexpr float p5 = 0.5f; // the value 0.5
static constexpr uint32_t packed_pzero = 0x00000000; // positive zero
static constexpr uint32_t packed_nzero = 0x80000000; // negative zero
static constexpr uint32_t packed_nan = 0xFFFFFFFF; // not-a-number
static constexpr uint32_t packed_pinf = 0xFF800000; // positive infinity
static constexpr uint32_t packed_ninf = 0x7F800000; // negative infinity
using packed_type = uint32_t; // unsigned integer type
using signed_packed_type = int32_t; // signed integer type
using float_type = float; // floating point type
......@@ -48,6 +54,11 @@ struct ieee_754_trait<double> {
static constexpr uint64_t expbits = 11;
static constexpr double zero = 0.0;
static constexpr double p5 = 0.5;
static constexpr uint64_t packed_pzero = 0x0000000000000000ull;
static constexpr uint64_t packed_nzero = 0x8000000000000000ull;
static constexpr uint64_t packed_nan = 0xFFFFFFFFFFFFFFFFull;
static constexpr uint64_t packed_pinf = 0xFFF0000000000000ull;
static constexpr uint64_t packed_ninf = 0x7FF0000000000000ull;
using packed_type = uint64_t;
using signed_packed_type = int64_t;
using float_type = double;
......@@ -60,9 +71,15 @@ template <class T>
typename ieee_754_trait<T>::packed_type pack754(T f) {
using trait = ieee_754_trait<T>;
using result_type = typename trait::packed_type;
// filter special type
if (std::fabs(f) <= trait::zero) {
return 0; // only true if f equals +0 or -0
// filter special cases
if (std::isnan(f)) {
return trait::packed_nan;
}
if (std::isinf(f)) {
return std::signbit(f) ? trait::packed_ninf : trait::packed_pinf;
}
if (std::fabs(f) <= trait::zero) { // only true if f equals +0 or -0
return std::signbit(f) ? trait::packed_nzero : trait::packed_pzero;
}
auto significandbits = trait::bits - trait::expbits - 1; // -1 for sign bit
// check sign and begin normalization
......@@ -102,8 +119,22 @@ typename ieee_754_trait<T>::float_type unpack754(T i) {
using trait = ieee_754_trait<T>;
using signed_type = typename trait::signed_packed_type;
using result_type = typename trait::float_type;
if (i == 0)
using limits = std::numeric_limits<result_type>;
switch (i) {
case trait::packed_pzero:
return trait::zero;
case trait::packed_nzero:
return -trait::zero;
case trait::packed_pinf:
return limits::infinity();
case trait::packed_ninf:
return -limits::infinity();
case trait::packed_nan:
return limits::quiet_NaN();
default:
// carry on
break;
}
auto significandbits = trait::bits - trait::expbits - 1; // -1 for sign bit
// pull the significand: mask, convert back to float + add the one back on
auto result = static_cast<result_type>(i & ((T{1} << significandbits) - 1));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment