-1

I had this question on my exam, and I couldn't realy solve it, will appreciate some help.

Fill the blanks only, function must return true if and only if x<y. Assume x,y cannot be NaN (but can be +-inf) no casting is allowed, use only ux, uy, sx, sy

bool func(float x, float y) {
    unsigned* uxp = ______________ ;
    unsigned* uyp = ______________ ;
    unsigned  ux  = *uxp;
    unsigned  uy  = *uyp;
    unsigned  sx = (ux>>31); 
    unsigned  sy = (uy>>31);
    return ___________________________;
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • The first two blanks should be filled by casting the addresses of the parameters to the same type as `uxp` and `uyp`. – Barmar Aug 03 '22 at 22:12
  • 5
    This function is invalid. Invokes Undefined Behaviour by violating the strict aliasing rules. Your teacher needs to learn – 0___________ Aug 03 '22 at 22:15
  • Dosent &x , &y are enough? And then uxp and uyp are 2 pointers to an unsigned integer. – MultiHunter Aug 03 '22 at 22:16
  • 1
    Nope. Strict aliasing means the only "wrong" type you can use is char. You very definitely can't use pointer to type-pun a float to an unsigned int. See [What is the strict aliasing rule?](https://stackoverflow.com/questions/98650) – Steve Summit Aug 03 '22 at 22:19
  • @SteveSummit compiler disagrees https://godbolt.org/z/hWPaGnvdW – 0___________ Aug 03 '22 at 22:37
  • @0___________ Compiler disagrees with what/who? I was replying to MultiHunter's question about "&x , &y are enough", and agreeing with you that strict aliasing was violated! – Steve Summit Aug 03 '22 at 22:56
  • 2
    MultiHunter, `+0.0f == -0.0f`. Should `func()` compare them as the same value or different? – chux - Reinstate Monica Aug 03 '22 at 23:16

1 Answers1

5

Presumably the assignment assumes float uses IEEE-754 binary32 and unsigned is 32 bits.

It is not proper to alias float objects with an unsigned type, although some C implementations support it. Instead, you can create a compound literal union, initialize its float member with the float value, and access its unsigned member. (This is supported by the C standard but not by C++.)

After that, it is simply a matter of dividing the comparison into cases depending on the sign bits:

#include <stdbool.h>

bool func(float x, float y) {
    unsigned* uxp = & (union { float f; unsigned u; }) {x} .u;
    unsigned* uyp = & (union { float f; unsigned u; }) {y} .u;
    unsigned  ux  = *uxp;
    unsigned  uy  = *uyp;
    unsigned  sx = (ux>>31); 
    unsigned  sy = (uy>>31);
    return
         sx &&  sy ? uy < ux :  // Negative values are in "reverse" order.
         sx && !sy ? (uy | ux) & 0x7fffffffu : // Negative x is always less than positive y except for x = -0 and y = +0.
        !sx &&  sy ?    0    :  // Positive x is never less than negative y.
                     ux < uy ;  // Positive values are in "normal" order.
}


#include <stdio.h>


int main(void)
{
    // Print expected values and function values for comparison.
    printf("1, %d\n", func(+3, +4));
    printf("1, %d\n", func(-3, +4));
    printf("0, %d\n", func(+3, -4));
    printf("0, %d\n", func(-3, -4));
    printf("0, %d\n", func(+4, +3));
    printf("1, %d\n", func(-4, +3));
    printf("0, %d\n", func(+4, -3));
    printf("1, %d\n", func(-4, -3));
}

Sample output:

1, 1
1, 1
0, 0
0, 0
0, 0
1, 1
0, 0
1, 1
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Quite poetic code you have here for `return ___________________________`. – chux - Reinstate Monica Aug 04 '22 at 03:53
  • thanks!! first of all I had no idea about strict aliasing rules and that they can lead to an undefined behaviour. although to be honest even after reading about it im not sure what can happend if i'll defined uxp and uyp like this: `code` unsigned* uxp = (unsigned*)&x; `code` . anyways the answer of Eric Postpischil realy helped thanks!! – MultiHunter Aug 06 '22 at 18:35