3

This question is regarding a code example in Section 7.4 of Beej's Guide to Network Programming.

Here is the code example.

uint32_t htonf(float f)
{
    uint32_t p;
    uint32_t sign;

    if (f < 0) { sign = 1; f = -f; }
    else { sign = 0; }

    p = ((((uint32_t)f)&0x7fff)<<16) | (sign<<31); // whole part and sign
    p |= (uint32_t)(((f - (int)f) * 65536.0f))&0xffff; // fraction

    return p;
}

Why is the bitwise-AND with 0xffff required to store the fraction?

As far as I understand, f - (int) f is always going to be a number that satisfies the inequality, 0 <= f - (int) f < 1. Since this number is always going to be less than 1, this number multiplied by 65536 is always going to be less than 65536. In other words, this number would never exceed 16 bits in its binary representation.

If this number never exceeds 16 bits in length, then what is the point in trying to select the least significant 16 bits with & 0xffff. It seems like a redundant step to me.

Do you agree? Or do you see a scenario where the & 0xffff is necessary for this function to work correctly?

Lone Learner
  • 18,088
  • 20
  • 102
  • 200

1 Answers1

1

The & 0xffff is superfluous.

It is questionable to even use. Consider the following. If some prior or potential future code may create a some_float_expression < 0 or some_float_expression >= 0x10000, then truncating the expression with & 0xffff could result in a incorrect answer. The below is sufficient.

(uint32_t)(some_float_expression);

IMO, code has other issues:

  1. No range error detection. @M.M

  2. I'd expect a round-to-nearest conversion, rather than truncate toward 0.0.

  3. Minor: if (f < 0) is the wrong test for detecting th sign of -0.0f. Use signbit().

  4. Unclear why code is not somelthing like

    if (in range) 
      p = (uint32_t)(f*65536.0f) | (sign<<31);
    
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256