IntellectualKitty
IntellectualKitty

Reputation: 693

Normalized Integer to/from Float Conversion

I need to convert normalized integer values to and from real floating-point values. For instance, for int16_t, a value of 1.0 is represented by 32767 and -1.0 is represented by -32768. Although it's a bit tedious to do this for each integer type, both signed and unsigned, it's still easy enough to write by hand.

However, I want to use standard methods whenever possible rather than going off and reinventing the wheel, so what I'm looking for is something like a standard C or C++ header, a Boost library, or some other small, portable, easily-incorporated source that already performs these conversions.

Upvotes: 12

Views: 8284

Answers (3)

PaulArmitt
PaulArmitt

Reputation: 21

I'd question whether your intent is correct here (or indeed that of most of the answers).

Since you're likely just dealing with something like an integer representation of a "real" value such as that produced by an ADC - I'd argue that in fact a floating point fraction of +32767/32768 (not +1.0) is represented by the integer +32767, as a value of +1.0 can't actually be expressed in this form due to the 2's complement arithmetic used.

Upvotes: 0

Binary Birch Tree
Binary Birch Tree

Reputation: 15738

Here's a templated solution using std::numeric_limits:

#include <cstdint>
#include <limits>

template <typename T>
constexpr double normalize (T value) {
  return value < 0
    ? -static_cast<double>(value) / std::numeric_limits<T>::min()
    :  static_cast<double>(value) / std::numeric_limits<T>::max()
    ;
}

int main () {
  // Test cases evaluated at compile time.
  static_assert(normalize(int16_t(32767)) == 1, "");
  static_assert(normalize(int16_t(0)) == 0, "");
  static_assert(normalize(int16_t(-32768)) == -1, "");
  static_assert(normalize(int16_t(-16384)) == -0.5, "");
  static_assert(normalize(uint16_t(65535)) == 1, "");
  static_assert(normalize(uint16_t(0)) == 0, "");
}

This handles both signed and unsigned integers, and 0 does normalize to 0.

View Successful Compilation Result

Upvotes: 9

user31264
user31264

Reputation: 6737

Although it's a bit tedious to do this for each integer type, both signed and unsigned, it's still easy enough to write by hand.

You certainly don't need to do this for each integer type! Use <limits> instead.

template<class T> double AsDouble(const T x) {
    const double valMin = std::numeric_limits<T>::min();
    const double valMax = std::numeric_limits<T>::max();
    return 2 * (x - valMin) / (valMax - valMin) - 1; // note: 0 does not become 0.
}

Upvotes: -2

Related Questions