7

Can the copy_bit function below be simplified to something like out[out_bit] = in[in_bit]? (i.e. Not using an if statement)

template< typename T >
inline void copy_bit( T& out, const T in, const std::size_t out_bit, const std::size_t in_bit )
{
    if ( (in & (1 << in_bit)) != 0 )
    {
        out |= (1 << out_bit); // Set bit
    }
    else
    {
        out &= ~(1 << out_bit); // Clear bit
    }
}

// Set bit 4 in x to bit 11 in y
copy_bit( x, y, 4, 11 );

Update: Just to be clear, this isn't homework or an XY problem where suggesting std::bitset answers the question.

x-x
  • 7,287
  • 9
  • 51
  • 78
  • 1
    Well, we don't care for homework. We should just solve the problem for real applications. – masoud Aug 11 '14 at 05:54
  • 1
    @RoeeGavirel You are right, but I meant that part with `out[out_bit] = in[in_bit]`. Is it possible to do that 'directly'? – Alireza Aug 11 '14 at 05:55
  • 1
    @Alireza: `out[out_bit] = in[in_bit]` doesn't imply that the bits must be changed directly, since in C++ you can overload `operator[]`. – masoud Aug 11 '14 at 05:57
  • not mentioned anywhere yet, but undefined behaviour is caused by `1 << in_bit` if `in_bit >= CHAR_BIT * sizeof(int)` regardless of `T` ; consider doing `static_cast(1)`, and if `T` might be signed then cast to the unsigned version of `T` – M.M Aug 11 '14 at 11:37
  • +1 for mentioning the XY problem :) – Leeor Aug 18 '14 at 15:27

3 Answers3

9

you can do it like that like this:

//Change the bit if and only if they are not equal:
out ^= (((out >> out_bit) ^ (in >> in_bit)) & 1) << out_bit;

(Shift both values so that the required bits are in the least significant position with >>, select with & only the lower bit of the result of the ^ operation; then shift the result into position of an otherwise zero-value to ^ with the original destination. The result is the same as copying bit in_bit of in to bit out_bit of out.)

TonyB
  • 158
  • 1
  • 3
Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94
  • bonus points if you can profile this and compare with the original code (it's hard to see why OP makes this request unless he thinks he can outdo his compiler for performance gains) – M.M Aug 11 '14 at 11:32
  • I did the hard part, let someone else do the profiling (: . Anyway the request was to simplify the code not to optimize it. – Roee Gavirel Aug 11 '14 at 12:40
  • Am not sure a lot of people would consider this more "simple" than the original code :) – Drax Aug 11 '14 at 13:18
6

One way to do so in one line would be to first reset the output bit to zero, and then OR it with whatever bit the in number has:

(out &= ~(1 << out_bit)) |= (((in >> in_bit) & 1) << out_bit)
Ishamael
  • 12,583
  • 4
  • 34
  • 52
  • 3
    Too many compound assignment operators; it's very hard to prove whether this has undefined behavior. – Ben Voigt Aug 11 '14 at 05:56
  • 2
    Yes, I myself get confused with sequence points. I believe my answer might indeed have undefined behavior. – Ishamael Aug 11 '14 at 06:06
  • in C++03 it surely has undefined behaviour (two assignments to same variable without intervening sequence point) although this is easily fixed by not using the compound assignment – M.M Aug 11 '14 at 11:33
4

Try this:

template< typename T >
inline void copy_bit( T& out, const T in, const std::size_t out_bit, const std::size_t in_bit )
{
    out = (out & ~(1 << out_bit)) | (((in & (1 << in_bit)) >> in_bit) << out_bit);
}

Explanation:

  • (out & ~(1 << out_bit)) leave the bits of out that aren't interesting.
  • (in & (1 << in_bit) select the bit of in that is interesting
  • (((in & (1 << in_bit)) >> in_bit) << out_bit) positionate the bit in the correct position.
NetVipeC
  • 4,402
  • 1
  • 17
  • 19
  • Good explanation, but `(((in & (1 << in_bit)) >> in_bit) << out_bit)` could be simplified to `(((in >> in_bit) & 1) << out_bit)`, saves a shift. – Christian Rau Aug 11 '14 at 09:46