Public Group

# Can you split a 32bit float into 2 16bit floats?

This topic is 3167 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm probably being incredibly stup here, but I'm having difficulty working this out in my own head. I know you can pack 2 16 bit floats into a 32 bit float, but is it possible to split a 32 bit float into 2 16bit floats without losing anything? If so, how would you go about doing so?

##### Share on other sites
If you want to divide a 32 bit value into two 16 bit values
try this -

float f;
WORD higherBits = HIWORD(DWORD(f));
WORD lowerBits = LOWORD(DWORD(F));

Hope that helps.

##### Share on other sites
Quote:
 without losing anything?

Do you mean "and still have anything make sense?" [wink]
float16 f1 = somevalue, f2 = anothervalue;float32 packed;byte* ptrPacked = (byte*)&packed;byte* inputPtr1 = (byte*)&f1;byte* inputPtr2 = (byte*)&f2;ptrPacked[0] = inputPtr1[0];ptrPacked[1] = inputPtr1[1];ptrPacked[2] = inputPtr2[0];ptrPacked[3] = inputPtr2[1];...// packed is now garbage but can be unpacked

##### Share on other sites
It might help if I explain what I'm trying to do.

I want to try and store 32bit depth values (I guess technically 24bit) into an R16G16 target, if at all possible.

Buckeye, doesn't your example do the opposite? Packing two 16bit floats into a 32bit?

##### Share on other sites
Quote:
 Original post by ChetanhlIf you want to divide a 32 bit value into two 16 bit values try this - float f;WORD higherBits = HIWORD(DWORD(f));WORD lowerBits = LOWORD(DWORD(F));Hope that helps.

In DWORD(f), it will just be converted to integer value-wise, not bit-wise.

##### Share on other sites
Quote:
 Buckeye, doesn't your example do the opposite?
Yep. Misread your statement. Just reverse the assignments.
float32 f32 = your_value;float16 f1, f2;//.. etc.f1Ptr[0] = f32Ptr[0];f1Ptr[1] = f32Ptr[1];f2Ptr[0] = f32Ptr[2];f2Ptr[1] = f32Ptr[3];

Quote:
 without losing anything?

Be aware, f1 and f2 are garbage until recombined. Are you just trying to store the 32bit float in the target because R32 (or something similar) is not available or inconvenient?

##### Share on other sites
You are certainly free to take a 32-bit floating point value apart into two 16-bit values by putting the first 16 bits into one and the next into another. But the resulting values aren't meaningful on their own. They certainly aren't "16-bit floats"; C and C++ don't deal with those (there isn't widespread hardware support for them anyway, even if IEEE does define a standard for them). They're just two 16-bit-sized chunks of data which you can put back together to restore the original value.

Buckeye shows the basic approach, although you should avoid C-style casts in C++.

I'll make a generalized function for copying some bytes around, and then use it to implement what you need.

template <size_t offset, typename S, typename D>void copyBytes(const S& source, D& destination) {  // Copy from source to destination at a given offset. The sizes of the  // source and destination types are compared, and the smaller type sets the  // number of bytes copied. The offset value offsets from the beginning of  // the larger type.  const char* source_ptr = reinterpret_cast<const char*>(&source);  char* dest_ptr = reinterpret_cast<char*>(&destination);  const int source_size = sizeof(S);  const int dest_size = sizeof(D);  const bool source_bigger = sizeof(S) > sizeof(D);  const int big_size = source_bigger ? source_size : dest_size;  const int small_size = source_bigger ? dest_size : source_size;  // Ensure that the code doesn't compile if the offset is bad.  char offset_is_too_large[big_size - small_size - offset];    // Do the copy.  if (source_bigger) { source_ptr += offset; }  else { dest_ptr += offset; }  // std::copy lives in <algorithm>.  std::copy(source_ptr, source_ptr + small_size, dest_ptr);}// used likefloat original;my_16bit_type high, low;copyBytes<0>(original, high);copyBytes<2>(original, low);float reconstituted;copyBytes<0>(high, reconstituted);copyBytes<2>(low, reconstituted);

##### Share on other sites
On further reflection, here's a simpler way:

// The general approach is to use boost::array so that we're always dealing// with single values instead of arrays, and have simple functions to copy from// one to another.template <typename S, typename D>void reinterpret(const S& source, D& destination) {  const char* s = reinterpret_cast<const char*>(&source);  char* d = reinterpret_cast<char*>(&destination);  char source_is_too_large[sizeof(D) - sizeof(S)];  std::copy(s, s + sizeof(S), d);}template <typename D, typename S>D reinterpreted(const S& source) {  D result;  reinterpret(source, result);  return result;}// Used like:typedef boost::array<my_16bit_type, 2> segmented_float;float original;segmented_float segmented = reinterpreted<segmented_float>(original);float reconstituted = reinterpreted<float>(segmented);

I factored it to have separate 'reinterpret' and 'reinterpreted' versions for convenience; use 'reinterpret' to read into an l-value that already exists (e.g. 'big_structure bs; reinterpret(original, bs.segments)'), and 'reinterpreted' to initialize a variable or for use in the middle of an expression (e.g. 'my_16bit_type high = reinterpreted<segmented_float>(original)[0]').

Warnings: this should only be used with POD types (fortunately, boost::array qualifies), and I haven't tested it (but it should be close if not correct already).

1. 1
Rutin
44
2. 2
3. 3
4. 4
5. 5

• 13
• 10
• 12
• 10
• 13
• ### Forum Statistics

• Total Topics
632997
• Total Posts
3009794
• ### Who's Online (See full list)

There are no registered users currently online

×