Skip to content

Commit

Permalink
Created edm::bit_cast
Browse files Browse the repository at this point in the history
This will be replaced with std::bit_cast when available.
  • Loading branch information
Dr15Jones committed Sep 1, 2021
1 parent 18a6fa5 commit 1df0f46
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 23 deletions.
38 changes: 15 additions & 23 deletions DataFormats/Math/interface/libminifloat.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
#ifndef libminifloat_h
#define libminifloat_h
#include "FWCore/Utilities/interface/thread_safety_macros.h"
#include "FWCore/Utilities/interface/bit_cast.h"
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <cstring>

// ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf
class MiniFloatConverter {
public:
MiniFloatConverter();
inline static float float16to32(uint16_t h) {
uint32_t i32 = mantissatable[offsettable[h >> 10] + (h & 0x3ff)] + exponenttable[h >> 10];
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}
inline static uint16_t float32to16(float x) { return float32to16round(x); }
/// Fast implementation, but it crops the number so it biases low
inline static uint16_t float32to16crop(float x) {
uint32_t i32 = bit_cast<uint32_t>(x);
uint32_t i32 = edm::bit_cast<uint32_t>(x);
return basetable[(i32 >> 23) & 0x1ff] + ((i32 & 0x007fffff) >> shifttable[(i32 >> 23) & 0x1ff]);
}
/// Slower implementation, but it rounds to avoid biases
inline static uint16_t float32to16round(float x) {
uint32_t i32 = bit_cast<uint32_t>(x);
uint32_t i32 = edm::bit_cast<uint32_t>(x);
uint8_t shift = shifttable[(i32 >> 23) & 0x1ff];
if (shift == 13) {
uint16_t base2 = (i32 & 0x007fffff) >> 12;
Expand All @@ -38,15 +38,15 @@ class MiniFloatConverter {
inline static float reduceMantissaToNbits(const float &f) {
static_assert(bits <= 23, "max mantissa size is 23 bits");
constexpr uint32_t mask = (0xFFFFFFFF >> (23 - bits)) << (23 - bits);
uint32_t i32 = bit_cast<uint32_t>(f);
uint32_t i32 = edm::bit_cast<uint32_t>(f);
i32 &= mask;
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}
inline static float reduceMantissaToNbits(const float &f, int bits) {
uint32_t mask = (0xFFFFFFFF >> (23 - bits)) << (23 - bits);
uint32_t i32 = bit_cast<uint32_t>(f);
uint32_t i32 = edm::bit_cast<uint32_t>(f);
i32 &= mask;
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

class ReduceMantissaToNbitsRounding {
Expand All @@ -58,7 +58,7 @@ class MiniFloatConverter {
float operator()(float f) const {
constexpr uint32_t low23 = (0x007FFFFF); // mask to keep lowest 23 bits = mantissa
constexpr uint32_t hi9 = (0xFF800000); // mask to keep highest 9 bits = the rest
uint32_t i32 = bit_cast<uint32_t>(f);
uint32_t i32 = edm::bit_cast<uint32_t>(f);
if (i32 & test) { // need to round
uint32_t mantissa = (i32 & low23) >> shift;
if (mantissa < maxn)
Expand All @@ -67,7 +67,7 @@ class MiniFloatConverter {
} else {
i32 &= mask;
}
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

private:
Expand All @@ -92,33 +92,33 @@ class MiniFloatConverter {

inline static float max() {
constexpr uint32_t i32 = 0x477fe000; // = mantissatable[offsettable[0x1e]+0x3ff]+exponenttable[0x1e]
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

// Maximum float32 value that gets rounded to max()
inline static float max32RoundedToMax16() {
// 2^16 in float32 is the first to result inf in float16, so
// 2^16-1 is the last float32 to result max() in float16
constexpr uint32_t i32 = (0x8f << 23) - 1;
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

inline static float min() {
constexpr uint32_t i32 = 0x38800000; // = mantissatable[offsettable[1]+0]+exponenttable[1]
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

// Minimum float32 value that gets rounded to min()
inline static float min32RoundedToMin16() {
// 2^-14-1 in float32 is the first to result denormalized in float16, so
// 2^-14 is the first float32 to result min() in float16
constexpr uint32_t i32 = (0x71 << 23);
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

inline static float denorm_min() {
constexpr uint32_t i32 = 0x33800000; // mantissatable[offsettable[0]+1]+exponenttable[0]
return bit_cast<float>(i32);
return edm::bit_cast<float>(i32);
}

inline static bool isdenorm(uint16_t h) {
Expand All @@ -127,14 +127,6 @@ class MiniFloatConverter {
}

private:
//in C++20 we can use std::bit_cast which is constexpr
template <class To, class From>
inline static To bit_cast(const From &src) noexcept {
static_assert(sizeof(To) == sizeof(From), "incompatible types");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
CMS_THREAD_SAFE static uint32_t mantissatable[2048];
CMS_THREAD_SAFE static uint32_t exponenttable[64];
CMS_THREAD_SAFE static uint16_t offsettable[64];
Expand Down
36 changes: 36 additions & 0 deletions FWCore/Utilities/interface/bit_cast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef FWCore_Utilities_bit_cast_h
#define FWCore_Utilities_bit_cast_h
// -*- C++ -*-
//
// Package: FWCore/Utilities
// Class : bit_cast
//
/**\function edm::bit_cast bit_cast.h "FWCore/Utilities/interface/bit_cast.h"
Description: C++ 20 std::bit_cast stand-in
Usage:
See documentation on std::bit_cast in C++ 20
*/
//
// Original Author: Christopher Jones
// Created: Wed, 01 Sep 2021 19:11:41 GMT
//

// system include files
#include <cstring>

// user include files

namespace edm {
//in C++20 we can use std::bit_cast which is constexpr
template <class To, class From>
inline To bit_cast(const From &src) noexcept {
static_assert(sizeof(To) == sizeof(From), "incompatible types");
To dst;
std::memcpy(&dst, &src, sizeof(To));
return dst;
}
} // namespace edm
#endif

0 comments on commit 1df0f46

Please sign in to comment.