2

My task is to create a class that implements Floating point number.

The size of the class must be exactly 3 bytes:

1 bit for the sign

6 bits for exponent

17 bits for mantissa

I tried to implement the class using bit fields, but the size is 4 bytes :

class FloatingPointNumber
{
private:
    unsigned int sign : 1;
    unsigned int exponent : 6;
    unsigned int mantissa : 17;
};
vanderwaal
  • 336
  • 1
  • 3
  • 10
  • 8
    Your compiler is permitted to add padding and alignment. – drescherjm Nov 30 '21 at 22:21
  • 1
    Having you considered subclassing `std::array`, and then implementing methods that manipulate the bits directly? The obvious intent behind this programming task is to implement all the hard work yourself, in your own code, instead of letting any built-in compiler feature do all the work for you. – Sam Varshavchik Nov 30 '21 at 22:23
  • You might get it to work with something like [`#pragma pack(1)`](https://stackoverflow.com/q/14179748/10077), but that will hurt portability. – Fred Larson Nov 30 '21 at 22:29
  • 2
    I'd go for @SamVarshavchik's option, but without subclassing a STL array, just using three unsigned chars or `uint8_t` instead. – rturrado Nov 30 '21 at 22:35
  • 1
    I have not seen a 24 bit `int` implementation in the wild. I don't think I've seen one in a lab, either. – user4581301 Nov 30 '21 at 22:36
  • Does this answer your question? [Struct padding in C++](https://stackoverflow.com/questions/5397447/struct-padding-in-c) – Chris Nov 30 '21 at 22:37
  • @user4581301 • I saw a 26-bit int in the lab, which had 13-bit bytes. (It was a VM made by the professor at the UofMN/IT, ostensibly to teach assembly programming.) – Eljay Nov 30 '21 at 23:18

1 Answers1

4

C++ (and C for that matter) compilers are permitted to insert and append any amount of padding into a struct as they see fit. So if your task specifies that it must be exactly 3 bytes, then this task can not be done with struct (or class) using just standard language elements.

Using compiler specific attributes or pragmas, you can force the compiler to not insert padding; however for bitfields the compiler still might see the need to fill up any gaps left to type alignment requirements.

For this specific task your best bet probably is to use a class like this

class CustomFloat {
protected: // or private: as per @paddy's comment
    unsigned char v[3];
}

…and hoping for the compiler not to append some padding bytes.

The surefire way would be to simply to

typedef char CustomFloat[3];

and accept, that you'll not enjoy static type checking benefits whatsoever.

And then for each operation use a form of type punning to transfer the contents of v into a (at least 32 bit wide) variable, unpack the bits from there, perform the desired operation, pack the bits and transfer back into v. E.g. something like this:

uint32_t u = 0;
static_assert( sizeof(u) >= sizeof(v) );
memcpy((void*)&u, sizeof(v), (void const*)v);
unsigned sign = (u & SIGN_MASK) >> SIGN_SHIFT;
unsigned mant = (u & MANT_MASK) >> MANT_SHIFT;
unsigned expt = (u & EXPT_MASK) >> EXPT_SHIFT;

// perform operation

u = 0;
u |= (sign << SIGN_SHIFT) & SIGN_MASK;
u |= (mant << MANT_SHIFT) & MANT_MASK;
u |= (expt << EXPT_SHIFT) & EXPT_MASK;
memcpy((void*)v, sizeof(v), (void const*)&u);

Yes, this looks ugly. Yes, it is quite verbose. But that's what going to happen under the hood anyway, so you might just as well write it down.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Solid answer. Is there a reason you declare the array member as `protected`? To me, that implies that this class is designed to be inherited. It might be more explicit if this is `private` instead, and that's also more in line with the OP's example. – paddy Nov 30 '21 at 22:52
  • No particular reason for `protected`, other than that I think that `private` is sort of overkill; but that's kind of a matter of taste. I added a comment on that in my answer. – datenwolf Nov 30 '21 at 23:02