I am trying to change one bit in a double so that for example:
Double x: -1.500912597
which is:
Binary: 10111111 11111000 00000011 10111100 11101101 01100100 01001111 10010011
Change one bit in the underlying binary code (for example, bit 16) so that:
Binary: 10111111 11111001 00000011 10111100 11101101 01100100 01001111 10010011
Double x: -1.563412596999999903
Is there some C++ code I can use for this?
#include <ieee754.h>
ieee754_double d = {-1.500912597};
d.ieee.mantissa1 |= 1u << 16; // set bit 16 of mantissa
double x = d.d;
Header ieee754.h
on my system comes from glibc-headers
package.
The only portable way is to use memcpy
(yes, I know what you're thinking, and no it's not inefficient).
Note that this solution does not take into account byte-ordering. You'd need to cater for that too to be strictly portable.
#include <cstdlib>
#include <cstring>
#include <utility>
#include <iostream>
// only compile this function if Integer is the same size as a double
template<class Integer, std::enable_if_t<sizeof(Integer) == sizeof(double)>* = nullptr>
double or_bits(double input, Integer bits)
{
Integer copy;
// convert the double to a bit representation in the integer
std::memcpy(©, &input, sizeof(input));
// perform the bitwise op
copy |= bits;
// convert the bits back to a double
std::memcpy(&input, ©, sizeof(copy));
// return the double
return input;
}
int main()
{
double d = 1.0;
d = or_bits(d, 0x10ul);
std::cout << d << std::endl;
}
assembly output on gcc5.3:
double or_bits<unsigned long, (void*)0>(double, unsigned long):
movq %xmm0, %rax
orq %rdi, %rax
movq %rax, -8(%rsp)
movsd -8(%rsp), %xmm0
ret
There are endless possibilities for bit manipulation. So you should practice; but I'll give you some examples.
Below code will "set" only bit 3 of x (where bit 0 is the least significant bit):
#define SET_BIT3 (0x08)
x |= SET_BIT3;
Below code will "reset" only bit 3:
#define RESET_BIT3 (0xFFFFFFFFFFFFFFF7)
x &= RESET_BIT3;
Another thing you could do is make a union like this:
typedef union
{
struct
{
unsigned BIT0:1;
unsigned BIT1:1;
unsigned BIT2:1;
unsigned BIT3:1;
unsigned BIT4:1;
unsigned BIT5:1;
unsigned BIT6:1;
unsigned BIT7:1;
unsigned BIT8:1;
unsigned BIT9:1;
unsigned BIT10:1;
unsigned BIT11:1;
unsigned BIT12:1;
unsigned BIT13:1;
unsigned BIT14:1;
unsigned BIT15:1;
};
struct
{
unsigned BYTE0:8;
unsigned BYTE1:8;
};
struct
{
unsigned ALL:16;
};
}two_bytes;
What you can do with it is this:
two_bytes var;
var.ALL = 0; // clear all bits
var.BYTE1 = 0xFF; // make all bits of most significant byte 1
var.BIT7 = 1; // set only bit 7
Or you can turn into bitwise operators again:
#define SET_BIT3 (0x08)
var.ALL |= SET_BIT3;