optimized bit manipulation for getting the NOT value - c++

I have a unsigned 16 bit number,a ,and I need to get the value for ~a. Simply taking the value of ~a does not work( for a=10, I need ~a=5, not ~a=7FF5).
The best I could come up with is:
int negate(int a)
{
int mask1 = 0x4000;
int mask2 = 0x7FFF;
for (int i=0;i<15;i++)
{
if (!(a&mask1))
{
mask1>>=1;
mask2>>=1;
}
else
break;
}
int t = (0x7FFF - ~a) & mask2;
return t;
}
The problem with this is that it's too slow; do you know of a faster way to get the result I need?
Thanks for your help

Just to verify: what you want is to invert all the bits up to and including the most significant bit of the input that's set, but leave all the bits higher than that as zero's?
If that is indeed the case, then here is the code for that:
// inspired by Hacker's Delight
unsigned significant_bits(unsigned x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
// x |= (x >> 16); // only needed for 32-bit integers
return x;
}
unsigned negate(unsigned x)
{
return x ^ significant_bits(x);
}

It sounds like you want ~a & 0xF.

int negate(unsigned int a) {
if(a==0);
else if(a==1) a = 0;
else if(a<4) a ^= 0x0003;
else if(a<8) a ^= 0x0007;
else if(a<16) a ^= 0x000f;
else if(a<32) a ^= 0x001f;
else if(a<64) a ^= 0x003f;
else if(a<128) a ^= 0x007f;
else if(a<256) a ^= 0x00ff;
else if(a<512) a ^= 0x01ff;
else if(a<1024) a ^= 0x03ff;
else if(a<2048) a ^= 0x07ff;
else if(a<4096) a^= 0x0fff;
else if(a<8192) a ^= 0x1fff;
else if(a<16384) a ^= 0x3fff;
else if(a<32768) a ^= 0x7fff;
else a^=0xffff;
return a;
}
int main()
{
printf("%d",negate(10));
return 0;
}
If you want to increase the size say to a 32 bit number you could just add else if branches. The first case
a==0; the result is a itself
a==1; the result is 0, simple assigning 0 is fine .
Or simple you could put it in a loop and take a variable say i just left shift by 1 each time. and then return a ^ = (i - 1) ;

Pass the mask with the call to negate():
int negate(int a, int mask)
{
return ~a & mask;
}
Execution examples:
negate(0x000A, 0x000F) == 0x0005
negate(0x000A, 0x00F0) == 0x00F0
Update:
int negate(int num)
{
unsigned int bitMask = 0xFFFFFFFF;
for(unsigned int bit = 0x80000000; bit != 0; bit >>= 1)
{
if(bit & num)
break;
bitMask /= 2 ;
}
return ~num & bitMask;
}

Related

runtime error: left shift of negative value -1

In fact I am trying this question:
5.4 in 《Cracking the coding interview:189 programming questions and solutions,fifth edition》
the question is:
Given a positive integer, print the next smallest and the next largest number that have the same number of 1 bits in their binary representation.
There is an exact same question, but the answers are all wrong.
Moreover, the purpose of my question is to understand why the code cannot pass the ub checker, not just to get ideas for solving the problem.
0
What does "last executed input" mean on leetcode? Is it an example of the input that caused the error, and if so, why are there no warnings from the three compilers, even if I turn on all -Wall?
1
Why is the book wrong?
Here is the code from the book:
class Solution {
public:
int getNext(int n)
{
int c = n;
int c0 = 0;
int c1 = 0;
while (((c & 1) == 0) && (c != 0))
{
c0++;
c >>= 1;
}
while ((c & 1) == 1)
{
c1++;
c >>= 1;
}
if (c0 + c1 == 31 || c0 + c1 == 0) { return -1; }
int p = c0 + c1;
n |= (1 << p);
n &= ~((1 << p) - 1);
n |= (1 << (c1 - 1)) - 1;
return n;
}
int getPrev(int n)
{
int temp = n;
int c0 = 0;
int c1 = 0;
while ((temp & 1) == 1)
{
c1++;
temp >>= 1;
}
if (temp == 0)return -1;
while (((temp & 1) == 0 )&& (temp != 0))
{
c0++;
temp >>= 1;
}
int p = c0 + c1;
n &= ((~0) << (p + 1));
int mask = (1 << (c1 + 1)) - 1;
n |= mask << (c0 - 1);
return n;
}
vector<int> findClosedNumbers(int num) {
int m = getNext(num);
int n = getPrev(num);
return {m,n};
}
};
The error output is
Line 43: Char 14: runtime error: left shift of negative value -1 (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:53:14
I find this and it said "Left Shifting a negative value is Undefined Behavior"
But why I used all the Wall flags I can think of at https://godbolt.org/, but I didn't get any prompts.
Is there some flag to show this just like the UndefinedBehaviorSanitizer?
2.
Someone's answer can't pass
The link mentioned in this answer cannot pass lc, what's the problem with it?
code:
class Solution {
public:
vector<int> findClosedNumbers(int num) {
int m = getNextLarger(num);
int n = getNextSmaller(num);
return { m,n };
}
int getNextLarger(int num) {
if (num == 0 || num == -1)
return num;
// (1) add 1 to the last set bit
int largeNum = num + (num & ~(num - 1));
// (2) move the changed bits to the least significant bits. (right side)
int flipBits = num & ~largeNum;
int lastBits = 0;
while (flipBits != 0) {
flipBits &= flipBits - 1;
lastBits <<= 1;
lastBits |= 1;
}
lastBits >>= 1;
// (2.1) move bits to maintain the same number of set bits.
largeNum |= lastBits;
return largeNum;
}
//Unhandled exception at 0x0033F4B9 in leetcode.exe: 0xC00000FD: Stack overflow
int getNextSmaller(int num) { //with num=2
return ~getNextLarger(~num);
}
};
why the func can passed in msvc, clang, and gcc ,but just cannot pass the UndefinedBehaviorSanitizer?
Because the compiler didn't know at compile time, what value the operand would be at runtime. If compilers were able to detect all UB at compile time, then UB sanitisers wouldn't exist since they would be unnecessary.

Is this constexpr sqrt function portable?

I wrote this implementation of sqrt that is finite in complexity and precise up to the last digit when double is ieee754 double. The question is that is this portable on devices of various endian (assuming 0LL is still 64 bit)? get_fraction returns the 52bits plus the 1 bit at the begining. Small doubles are treated separately and ensured that they also have 1 in the 53rd bit. The c++ part numeric_limits nan can easily be replaced with a constant.
Code:
static inline constexpr int16_t get_exponent(double x)
{
uint64_t bits = *(uint64_t*)&x;
int16_t val = ((bits & 0x7FF0000000000000ULL) >> 52) - 1023;
if(val != -1023)
return val;
uint64_t temp_fractal= (bits & 0x000FFFFFFFFFFFFFULL);
for (int i = 51; i >= 0;--i) {
if(!(temp_fractal & (0x01ULL<<i))) --val;
else break;
}
return val;
}
static inline constexpr uint64_t get_fraction(double x)
{
uint64_t bits = *(uint64_t*)&x;
if (bits & 0x7FF0000000000000ULL)
return (bits & 0x000FFFFFFFFFFFFFULL) | 0x0010000000000000ULL;
uint64_t temp_fraction = bits & 0x000FFFFFFFFFFFFFULL;
for (int i = 51; i >= 0; --i) {
temp_fraction<<=1;
if(0x0010000000000000ULL & temp_fraction) break;
}
return temp_fraction;
}
static inline constexpr bool is_reserved(double x)
{
return get_exponent(x) == 1024;
}
static inline constexpr double my_abs(double x)
{
uint64_t bits = *(uint64_t*)&x;
bits &= 0x7FFFFFFFFFFFFFFFULL;
return *(double*)&bits;
}
constexpr double make_double(bool sign, int16_t exponent, uint64_t fractal)
{
uint64_t data = (fractal & 0x000FFFFFFFFFFFFFULL);
assert((fractal & 0xFFF0000000000000ULL) == 0x0010000000000000ULL);
if (exponent < -1023) {
fractal >>= (-1022 - exponent);
data = fractal;
exponent = -1023;
}
else if (exponent > 1023) {
return (1-2*sign)*std::numeric_limits<double>::infinity();
}
{
data |= ((uint64_t)((uint16_t)(exponent + 1023))) << 52;
if (sign)
data |= 0x8000000000000000ULL;
return *(double*)&data;
}
}
constexpr double my_sqrt(double x)
{
if(!x || is_reserved(x))
return x;
if(x < 0)
return -std::numeric_limits<double>::quiet_NaN();
uint64_t fraction = get_fraction(x);
int16_t exponent = get_exponent(x);
//C standard says it rounds to zero
int16_t half_exponent = ((exponent-1024)/2)+512;
uint64_t test_fraction = 0x0010000000000000ULL;
double test = make_double(0, half_exponent, test_fraction);
if (test * test > x) half_exponent -= 1;
//just to be safe
test = make_double(0, half_exponent, test_fraction);
if (test * test > x) half_exponent -= 1;
//find each bit except last one, binary search for result
for (int i = 51; i > 0; --i) {
test = make_double(0, half_exponent, test_fraction | (0x01ULL<<i));
if(test*test<x) test_fraction |= (0x01ULL << i);
}
double del1 = my_abs(x - test*test);
double temp = make_double(0, half_exponent, test_fraction | 0x01ULL);
double del2 = my_abs(x - temp * temp);
//see if the whole fraction needs to round up by one
if (x > temp * temp) {
test_fraction += 2;
//rounding up by one made the fraction too large
if (test_fraction >= 0x0020000000000000ULL) {
test_fraction >>= 1;
half_exponent -= 1;
}
double temp2 = make_double(0, half_exponent, test_fraction);
double del3 = my_abs(x - temp2 * temp2);
if(del3 <del2) return temp2;
else return temp;
}
else if(del2<del1) return temp;
else return make_double(0, half_exponent, test_fraction);
}
Edit: add some comments
Edit2: add missing functions

Varint encode/decode issue with number > 2^31-1

The code bellow works as expected with numbers <= 2^31-1 but produces wrong (way to large) result on numbers > 2^31-1. This is unexpected since since I never used uint32_t.
void encodeVarint(uint64_t value, uint8_t* output, uint8_t &outputSize)
{
outputSize = 0;
while (value > 127)
{
output[outputSize] = ((uint8_t)(value & 127)) | 128;
value >>= 7;
outputSize++;
}
output[outputSize++] = ((uint8_t)value) & 127;
}
uint64_t decodeVarint(uint8_t* input, uint8_t &inputSize)
{
uint64_t ret = 0;
inputSize = 0;
for (uint8_t i = 0; ; i++)
{
ret |= (input[i] & 127) << (7 * i);
inputSize++;
if(!(input[i] & 128))
break;
}
return ret;
}
Can someone please explain what I am doing wrong?
(input[i] & 127) should have type int and it may be 32-bit long.
Try
ret |= (uint64_t)(input[i] & 127) << (7 * i);
instead of
ret |= (input[i] & 127) << (7 * i);

Substitute an instruction depending on a condition

I have two for loops that I want to write in a function as one. The problem is that it differ only in one instruction
for (int i = 1; i <= fin_cabecera - 1 ; i++ ){
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
letra = sms[++indiceLetra]; //*differs here*
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
And the other
for (int i = datos_fichero; i <= tamanio_en_bits + datos_fichero; i++){
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
f.read(&letra, 1); //*differs here*
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
I thought in something like this:
void write_bit_by_bit(unsigned char buffer[], int from, int to, bool type) {
for (int i = to; i <= from; i++) {
buffer[i] &= 0xfe;
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
type ? (letra = sms[++indiceLetra]) : f.read(&letra, 1);
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
}
But I think there has to be a better method.
Context:
I will give more context (I will try explain it as better as I can within my language limitations). I have to read one byte each time because The Buffer variable represents a image pixel. sms is a message that have to be hidden within the image, and letra is a single char of that message. In order to not modify the aspect of the image, each bit of each character have to be written in the last bit of each pixel. Let me give you and example.
letra = 'H' // 01001000 in binary
buffer[0] = 255 // white pixel 11111111
In order to hide the H char, I will need 8 pixel:
The result will be like:
buffer[0] //11111110,
buffer[1] //11111111
buffer[2] //11111110
buffer[3] //11111110
buffer[4] //11111111
buffer[5] //11111110
buffer[6]//11111110
buffer[7]//11111110
The H is hidden in the last bit of the image. I hope I explained well.
[Solution]
Thanks to #anatolyg I've rewrited the code and now works just as I wanted. Here is how it looks:
void write_bit_by_bit(unsigned char buffer[], ifstream& f,int from, int to, char sms[], bool type){
unsigned short int indiceLetra = 0;
short int bitsLetraRestantes = 7;
unsigned char mask = 0x80; //Empezamos por el bit más significativo (10000000)
char* file_buffer;
if(type){ //Write file data
int number_of_bytes_to_read = get_file_size(f);
file_buffer = new char[number_of_bytes_to_read];
f.read(file_buffer, number_of_bytes_to_read);
}
const char* place_to_get_stuff_from = type ? file_buffer : sms;
char letra = place_to_get_stuff_from[0];
for (int i = from; i <= to; i++) {
buffer[i] &= 0xfe; //hacemos 0 último bit con máscara 11111110
//TODO: Hacer con dos for
if (bitsLetraRestantes < 0) {
bitsLetraRestantes = 7;
mask = 0x80;
letra = place_to_get_stuff_from[++indiceLetra];//letra = sms[++indiceLetra];
}
char c = (letra & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c; //Almacenamos en el ultimo bit del pixel el valor del caracter
}
}
int ocultar(unsigned char buffer[],int tamImage, char sms[], int tamSms){
ifstream f(sms);
if (f) {
strcpy(sms,basename(sms));
buffer[0] = 0xff;
int fin_cabecera = strlen(sms)*8 + 1;
buffer[fin_cabecera] = 0xff;
write_bit_by_bit(buffer, f, 1, fin_cabecera -1, sms, WRITE_FILE_NAME);
int tamanio_en_bits = get_file_size(f) * 8;
int datos_fichero = fin_cabecera + 1;
write_bit_by_bit(buffer, f, datos_fichero, tamanio_en_bits + datos_fichero, sms, WRITE_FILE_DATA);
unsigned char fin_contenido = 0xff;
short int bitsLetraRestantes = 7;
unsigned char mask = 0x80;
for (int i = tamanio_en_bits + datos_fichero + 1;
i < tamanio_en_bits + datos_fichero + 1 + 8; i++) {
buffer[i] &= 0xfe;
char c = (fin_contenido & mask) >> bitsLetraRestantes--;
mask >>= 1;
buffer[i] ^= c;
}
}
return 0;
}
Since you are talking about optimization here, consider performing the read outside the loop. This will be a major optimization (reading 10 bytes at once must be quicker than reading 1 byte 10 times). This will require an additional buffer for (the file?) f.
if (!type)
{
char f_buffer[ENOUGH_SPACE];
number = calc_number_of_bytes_to_read();
f.read(f_buffer, number);
}
for (...) {
// your code
}
After you have done this, your original question is easy to answer:
const char* place_to_get_stuff_from = type ? sms : f_buffer;
for (...) {
...
letra = place_to_get_stuff_from[++indiceLetra];
...
}

Division not crossing over bytes

I'm trying to do division on a uint128_t that is made up of 2 uint64_ts. Weirdly enough, the function works for uint64_ts with only the lower value set and the upper value = 0. I don't understand why.
Here's the code for the division and bit shift
class uint128_t{
private:
uint64_t UPPER, LOWER;
public:
// lots of stuff
uint128_t operator<<(int shift){
uint128_t out;
if (shift >= 128)
out = uint128_t(0, 0);
else if ((128 > shift) && (shift >= 64))
out = uint128_t(LOWER << (64 - shift), 0);
else if (shift < 64)
out = uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift);
return out;
}
uint128_t operator<<=(int shift){
*this = *this << shift;
return *this;
}
uint128_t operator/(uint128_t rhs){
// copy of numerator = copyn
uint128_t copyn(*this), quotient = 0;// constructor: uint128_t(T), uint128_t(S, T), uint128_t(uint128_t), etc
while (copyn >= rhs){
// copy of denomiator = copyd
// temp is the current quotient bit being worked with
uint128_t copyd(rhs), temp(1);
// shift the divosr to the highest bit
while (copyn > (copyd << 1)){
copyd <<= 1;
temp <<= 1;
}
copyn -= copyd;
quotient += temp;
}
return quotient;
}
// more stuff
};
Please ignore my blatant disregard for memory management.
out = uint128_t(LOWER << (64 - shift), 0); is wrong - it should be shift - 64 instead.
As a style note, ALL_CAPITALS are usually reserved for constants only. Variables and members should use mostly lowercase.
try this:
// some bit operations stuff
const unsigned char de_brujin_bit_map_64 [] =
{
0,1,2,7,3,13,8,19,4,25,14,28,9,34,20,40,5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
63,6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
};
inline uint8_t trailing_zero_count(uint64_t x) { return x?de_brujin_bit_map_64[(lower_bit(x)*0x0218A392CD3D5DBFL) >> 58]:64; }
inline uint8_t leading_zero_count(uint64_t x) { return x?(63-de_brujin_bit_map_64[(upper_bit(x)*0x0218A392CD3D5DBFL) >> 58]):64; }
inline uint64_t lower_bit(uint64_t x) { return x & -(int64_t&)x; }
inline uint64_t upper_bit(uint64_t x)
{
if(!x) return 0;
x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32;
return (x >> 1) + 1;
}
inline uint128_t upper_bit(const uint128_t x)
{
if(x.upper()) return uint128_t(upper_bit(x.upper()), 0);
else return uint128_t(0, upper_bit(x.lower()));
}
inline uint128_t lower_bit(const uint128_t x)
{
if(x.lower()) return uint128_t(0, lower_bit(x.lower()));
else return uint128_t(lower_bit(x.upper()), 0);
}
inline uint8_t trailing_zero_count(const uint128_t& x) { return x.lower()?trailing_zero_count(x.lower()):(64+trailing_zero_count(x.upper())); }
inline uint8_t leading_zero_count(const uint128_t& x) { return x.upper()?leading_zero_count(x.upper()):(64+leading_zero_count(x.lower())); }
// division operator
uint128_t uint128_t::operator/(const uint128_t& rhs) const
{
if(rhs == 0) return uint128_t(0); // !!!! zero division
if(rhs == rhs) return uint128_t(1);
if(rhs > *this) return uint128_t(0);
if(rhs == 1) return *this;
if(!upper_ && !rhs.upper_) return uint128_t(0, lower_/rhs.lower_);
if(lower_bit(rhs) == rhs) return *this >> trailing_zero_count(rhs);
uint128_t result;
uint128_t bit_mask = upper_bit();
uint128_t denom = 1;
do
{
bit_mask >>= 1;
denom <<= 1;
if(*this & bit_mask) denom |= 1;
result <<= 1;
if(denom >= rhs) { denom -= rhs; result |= 1; }
}
while (bit_mask.lower_ != 1);
return result;
}
anyway, this version is a little bit faster :)
ensure, 4000 iterations against 127:
uint128_t divident = uint128_t(0xffffffffffffffffULL, 0xffffffffffffffffULL);
uint128_t divisor = 10;
{
uint32_t iter_count = 0;
uint128_t copyn(divident), quotient = 0;
while (copyn >= divisor)
{
++iter_count;
uint128_t copyd(divisor), temp(1);
while ((copyn >> 1) > copyd) { ++iter_count; copyd <<= 1; temp <<= 1; }
copyn -= copyd;
quotient += temp;
}
std::cout << "iterations: " << std::dec << iter_count << std::endl;
}
{
uint32_t iter_count = 0;
uint128_t bit_pos = dtl::bits::upper_bit(divident);
uint128_t tmp = 1, quotient = 0;
do
{
++iter_count;
bit_pos >>= 1;
tmp <<= 1;
if(divident & bit_pos) tmp |= 1;
quotient <<= 1;
if(tmp >= divisor) { tmp -= divisor; quotient |= 1; }
}
while (bit_pos != 1);
std::cout << "iterations: " << std::dec << iter_count << std::endl;
}