This question already exists:
Comparing a negative and positive integer's byte array values in C++ [closed]
Closed 1 year ago.
I am pretty much new to C++ and especially signed and unsigned conversions. Currently I am doing one exercise, where I need to compare a value if it is between a two values (one minimum and maximum).
For example
minimum value = -319 - it's byte array (of int8) will be {254, 193}
maximum value = 400 - it's byte array (of int8) {1, 144}
Assume the value to be compared between is -200 {255, 56}, which should be valid, but I am not able to get it correctly.
Assume the compare value, minimum and maximum value bytes is ANDed with 255 unsigned mask byte, which is then stored in int8 byte and then compared between min and max value. Due to the sign bit I am confused and not able to correctly get the comparison, but for all positive values is working fine.
The methods I tried were,
First I tried to convert int8_t to int16_t
int16_t compare = (int16_t)(inp[i] & 0xFF);
int16_t minVal = (int16_t)(minimum[i] & 0xFF);
int16_t maxVal = (int16_t)(maximum[i] & 0xFF); return (compare>=minVal&&compare<=maxVal)
Second method was I set 0 to MS bit in mask byte and then comparing each byte, since I thought comparison with that bit is not needed, but I am not sure if it is right as the data might get wrong.
Third try was to set 0 the MS Bit while comparing . I tried it and this is also a failure.
Please let me know how to compare in this scenario. Thank you
So to clarify the question I get a three 2-element byte arrays, and the function will return true, if the value byte array is inbetween min and max byte array.
So the comparison algorithm above is ran in a for loop:
bool isValueInBetween(uint8_t* min, uint8_t* max, uint8_t* val){
bool is_match = true;
for(int i = 0; i < 2; i++){
int8_t compare = (inp[i] & 0xFF); //masking is used just because in the book it was mentioned, in case different mask occurs, but I think in this case it is not needed
int8_t minVal = (minimum[i] & 0xFF);
int8_t maxVal = (maximum[i] & 0xFF);
if (!(compare>=minVal&&compare<=maxVal))
is_match = false;
}
return is_match;
}
The above algorithm works for positive values, but doesn't work in negative or mixed value scenarios(say min in negative and max in positive). Please let me know any good books for C++.
As written, the question is a little hard to understand without the exact problem statement. As of this posting, it reads as if the question was "Write a function to compare two integer values." and you took it way beyond the extreme and assumed they meant down to the binary level...
What's wrong with using the logical comparison operators directly like so:
bool isValueInBetween(int8_t val, int8_t min, int8_t max) {
return min <= val && val <= max;
}
Related
I am dealing with very large list of booleans in C++, around 2^N items of N booleans each. Because memory is critical in such situation, i.e. an exponential growth, I would like to build a N-bits long variable to store each element.
For small N, for example 24, I am just using unsigned long int. It takes 64MB ((2^24)*32/8/1024/1024). But I need to go up to 36. The only option with build-in variable is unsigned long long int, but it takes 512GB ((2^36)*64/8/1024/1024/1024), which is a bit too much.
With a 36-bits variable, it would work for me because the size drops to 288GB ((2^36)*36/8/1024/1024/1024), which fits on a node of my supercomputer.
I tried std::bitset, but std::bitset< N > creates a element of at least 8B.
So a list of std::bitset< 1 > is much greater than a list of unsigned long int.
It is because the std::bitset just change the representation, not the container.
I also tried boost::dynamic_bitset<> from Boost, but the result is even worst (at least 32B!), for the same reason.
I know an option is to write all elements as one chain of booleans, 2473901162496 (2^36*36), then to store then in 38654705664 (2473901162496/64) unsigned long long int, which gives 288GB (38654705664*64/8/1024/1024/1024). Then to access an element is just a game of finding in which elements the 36 bits are stored (can be either one or two). But it is a lot of rewriting of the existing code (3000 lines) because mapping becomes impossible and because adding and deleting items during the execution in some functions will be surely complicated, confusing, challenging, and the result will be most likely not efficient.
How to build a N-bits variable in C++?
How about a struct with 5 chars (and perhaps some fancy operator overloading as needed to keep it compatible to the existing code)? A struct with a long and a char probably won't work because of padding / alignment...
Basically your own mini BitSet optimized for size:
struct Bitset40 {
unsigned char data[5];
bool getBit(int index) {
return (data[index / 8] & (1 << (index % 8))) != 0;
}
bool setBit(int index, bool newVal) {
if (newVal) {
data[index / 8] |= (1 << (index % 8));
} else {
data[index / 8] &= ~(1 << (index % 8));
}
}
};
Edit: As geza has also pointed out int he comments, the "trick" here is to get as close as possible to the minimum number of bytes needed (without wasting memory by triggering alignment losses, padding or pointer indirection, see http://www.catb.org/esr/structure-packing/).
Edit 2: If you feel adventurous, you could also try a bit field (and please let us know how much space it actually consumes):
struct Bitset36 {
unsigned long long data:36;
}
I'm not an expert, but this is what I would "try". Find the bytes for the smallest type your compiler supports (should be char). You can check with sizeof and you should get 1. That means 1 byte, so 8 bits.
So if you wanted a 24 bit type...you would need 3 chars. For 36 you would need 5 char array and you would have 4 bits of wasted padding on the end. This could easily be accounted for.
i.e.
char typeSize[3] = {0}; // should hold 24 bits
Now make a bit mask to access each position of typeSize.
const unsigned char one = 0b0000'0001;
const unsigned char two = 0b0000'0010;
const unsigned char three = 0b0000'0100;
const unsigned char four = 0b0000'1000;
const unsigned char five = 0b0001'0000;
const unsigned char six = 0b0010'0000;
const unsigned char seven = 0b0100'0000;
const unsigned char eight = 0b1000'0000;
Now you can use the bit-wise or to set the values to 1 where needed..
typeSize[1] |= four;
*typeSize[0] |= (four | five);
To turn off bits use the & operator..
typeSize[0] &= ~four;
typeSize[2] &= ~(four| five);
You can read the position of each bit with the & operator.
typeSize[0] & four
Bear in mind, I don't have a compiler handy to try this out so hopefully this is a useful approach to your problem.
Good luck ;-)
You can use array of unsigned long int and store and retrieve needed bit chains with bitwise operations. This approach excludes space overhead.
Simplified example for unsigned byte array B[] and 12-bit variables V (represented as ushort):
Set V[0]:
B[0] = V & 0xFF; //low byte
B[1] = B[1] & 0xF0; // clear low nibble
B[1] = B[1] | (V >> 8); //fill low nibble of the second byte with the highest nibble of V
I am trying to create a function to find the average of sensor values on the Arduino in order to calibrate it, however the summation is not working properly and therefore the average is not correct. The table below shows a sample of the output. The left column should be the rolling sum of the output which is displayed in the right column (How are negatives getting in there?)
-10782 17112
6334 17116
23642 17308
-24802 17092
-7706 17096
9326 17032
26422 17096
-21986 17128
The calibrateSensors() function, which is supposed to execute this is shown below
void calibrateSensors(int16_t * accelOffsets){
int16_t rawAccel[3];
int sampleSize = 2000;
Serial.println("Accelerometer calibration in progress...");
for (int i=0; i<sampleSize; i ++){
readAccelData(rawAccel); // get raw accelerometer data
accelOffsets[0] += rawAccel[0]; // add x accelerometer values
accelOffsets[1] += rawAccel[1]; // add y accelerometer values
accelOffsets[2] += rawAccel[2]; // add z accelerometer values
Serial.print(accelOffsets[2]);
Serial.print("\t\t");
Serial.print(rawAccel[2]);
Serial.print(" \t FIRST I:");
Serial.println(i);
}
for (int i=0; i<3; i++)
{
accelOffsets[i] = accelOffsets[i] / sampleSize;
Serial.print("Second I:");
Serial.println(i);
}
Serial.println("Accelerometer calibration complete");
Serial.println("Accelerometer Offsets:");
Serial.print("Offsets (x,y,z): ");
Serial.print(accelOffsets[0]);
Serial.print(", ");
Serial.print(accelOffsets[1]);
Serial.print(", ");
Serial.println(accelOffsets[2]);
}
and the readAccelData() function is as follows
void readAccelData(int16_t * destination){
// x/y/z accel register data stored here
uint8_t rawData[6];
// Read the six raw data registers into data array
I2Cdev::readBytes(MPU6050_ADDRESS, ACCEL_XOUT_H, 6, &rawData[0]);
// Turn the MSB and LSB into a signed 16-bit value
destination[0] = (int16_t)((rawData[0] << 8) | rawData[1]) ;
destination[1] = (int16_t)((rawData[2] << 8) | rawData[3]) ;
destination[2] = (int16_t)((rawData[4] << 8) | rawData[5]) ;
Any idea where I am going wrong?
You have two problems:
You do not initialise your arrays. They start with garbage data in them (space is allocated, but not cleared). You can initialise an array to be all zeros by doing:
int array[5] = {};
This will result in a array that initially looks like [0,0,0,0,0]
Your second problem is that you are creating an array of 16-bit signed integers.
A 16-bit integer can store 65536 different values. Problem is that because you are using a signed type, there are only 32767 positive integer values that you can use. You are overflowing and getting negative numbers when you try and store a value larger than that.
I believe the arduino supports 32-bit ints. If you only want positive numbers, then use an unsigned type.
To use an explicit 32-bit integer:
#include <stdint.h>
int32_t my_int = 0;
Some info on standard variable sizes (note that they can be different sizes based on the arduino model the code is built for):
https://www.arduino.cc/en/Reference/Int
On the Arduino Uno (and other ATMega based boards) an int stores a
16-bit (2-byte) value. This yields a range of -32,768 to 32,767
(minimum value of -2^15 and a maximum value of (2^15) - 1). On the
Arduino Due and SAMD based boards (like MKR1000 and Zero), an int
stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648
to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31)
- 1).
https://www.arduino.cc/en/Reference/UnsignedInt
On the Uno and other ATMEGA based boards, unsigned ints (unsigned
integers) are the same as ints in that they store a 2 byte value.
Instead of storing negative numbers however they only store positive
values, yielding a useful range of 0 to 65,535 (2^16) - 1).
The Due stores a 4 byte (32-bit) value, ranging from 0 to
4,294,967,295 (2^32 - 1).
https://www.arduino.cc/en/Reference/UnsignedLong
Unsigned long variables are extended size variables for number
storage, and store 32 bits (4 bytes). Unlike standard longs unsigned
longs won't store negative numbers, making their range from 0 to
4,294,967,295 (2^32 - 1).
With this code:
void calibrateSensors(int16_t * accelOffsets){
int16_t rawAccel[3];
// [...]
accelOffsets[0] += rawAccel[0];
There's an obvious problem: You are adding two 16bit signed integers here. A typical maximum value for a 16bit signed integer is 0x7fff (the first bit would be used as the sign bit), in decimal 32767.
Given your first two sample numbers, 17112 + 17116 is already 34228, so you're overflowing your integer type.
Overflowing a signed integer is undefined behavior in c, because different implementations could use different representations for negative numbers. For a program with undefined behavior, you can't expect any particular result. A very likely result is that the value will "wrap around" into the negative range.
As you already use types from stdint.h, the solution is simple: Use uint32_t for your sums, this type has enough bits for values up to 4294967295.
As a general rule: If you never need a negative value, just stick to the unsigned type. I don't see a reason why you use int16_t here, just use uint16_t.
In a single nibble (0-F) I can store one number from 0 to 15. In one byte, I can store a single number from 0 to 255 (00 - FF).
Can I use a byte (00-FF) to store two different numbers each in the range 0-127 (00 - 7F)?
The answer to your question is NO. You can split a single byte into two numbers, but the sum of the bits in the two numbers must be <= 8. Since, the range 0-127 requires 7 bits, the other number in the byte can only be 1 bit, i.e. 0-1.
For obvious cardinality reasons, you cannot store two small integers in the 0 ... 127 range in one byte of 0 ... 255 range. In other words the cartesian product [0;127]×[0;127] has 214 elements which is bigger than 28 (the cardinal of the [0;255] interval, for bytes)
(If you can afford losing precision - which you didn't tell - you could, e.g. by storing only the highest bits ...)
Perhaps your question is: could I store two small integers from [0;15] in a byte? Then of course you could:
typedef unsigned unibble_t; // unsigned nibble in [0;15]
uint8_t make_from_two_nibbles(unibble_t l, unibble_t r) {
assert(l<=15);
assert(r<=15);
return (l<<4) | r;
}
unibble_t left_nible (uint8_t x) { return x >> 4; }
unibble_t right_nibble (uint8_t) { return x & 0xf; }
But I don't think you always should do that. First, you might use bit fields in struct. Then (and most importantly) dealing with nibbles that way might be more inefficient and make less readable code than using bytes.
And updating a single nibble, e.g. with
void update_left_nibble (uint8_t*p, unibble_t l) {
assert (p);
assert (l<=15);
*p = ((l<<4) | ((*p) & 0xf));
}
is sometimes expensive (it involves a memory load and a memory store, so uses the CPU cache and cache coherence machinery), and most importantly is generally a non-atomic operation (what would happen if two different threads are calling simultaneously update_left_nibble on the same address p -i.e. with pointer aliasing- is undefined behavior).
As a rule of thumb, avoid packing more than one data item in a byte unless you are sure it is worthwhile (e.g. you have a billion of such data items).
One byte is not enough for two values in 0…127, because each of those values needs log2(128) = 7 bits, for a total of 14, but a byte is only 8 bits.
You can declare variables with bit-packed storage using the C and C++ bitfield syntax:
struct packed_values {
uint8_t first : 7;
uint8_t second : 7;
uint8_t third : 2;
};
In this example, sizeof(packed_values) should equal 2 because only 16 bits were used, despite having three fields.
This is simpler than using bitwise arithmetic with << and & operators, but it's still not quite the same as ordinary variables: bit-fields have no addresses, so you can't have a pointer (or C++ reference) to one.
Can I use a byte to store two numbers in the range 0-127?
Of course you can:
uint8_t storeTwoNumbers(unsigned a, unsigned b) {
return ((a >> 4) & 0x0f) | (b & 0xf0);
}
uint8_t retrieveTwoNumbers(uint8_t byte, unsigned *a, unsigned *b) {
*b = byte & 0xf0;
*a = (byte & 0x0f) << 4;
}
Numbers are still in range 0...127 (0...255, actually). You just loose some precision, similar to floating point types. Their values increment in steps of 16.
You can store two data in range 0-15 in a single byte, but you should not (one var = one data is a better design).
If you must, you can use bit-masks and bit-shifts to access to the two data in your variable.
uint8_t var; /* range 0-255 */
data1 = (var & 0x0F); /* range 0-15 */
data2 = (var & 0xF0) >> 4; /* range 0-15 */
I've got to program a function that receives
a binary number like 10001, and
a decimal number that indicates how many shifts I should perform.
The problem is that if I use the C++ operator <<, the zeroes are pushed from behind but the first numbers aren't dropped... For example
shifLeftAddingZeroes(10001,1)
returns 100010 instead of 00010 that is what I want.
I hope I've made myself clear =P
I assume you are storing that information in int. Take into consideration, that this number actually has more leading zeroes than what you see, ergo your number is most likely 16 bits, meaning 00000000 00000001 . Maybe try AND-ing it with number having as many 1 as the number you want to have after shifting? (Assuming you want to stick to bitwise operations).
What you want is to bit shift and then limit the number of output bits which can be active (hold a value of 1). One way to do this is to create a mask for the number of bits you want, then AND the bitshifted value with that mask. Below is a code sample for doing that, just replace int_type with the type of value your using -- or make it a template type.
int_type shiftLeftLimitingBitSize(int_type value, int numshift, int_type numbits=some_default) {
int_type mask = 0;
for (unsigned int bit=0; bit < numbits; bit++) {
mask += 1 << bit;
}
return (value << numshift) & mask;
}
Your output for 10001,1 would now be shiftLeftLimitingBitSize(0b10001, 1, 5) == 0b00010.
Realize that unless your numbits is exactly the length of your integer type, you will always have excess 0 bits on the 'front' of your number.
Sorry about the clumsy title; I couldn't find a bit way of expressing what I'm trying to do.
I am getting an input from the user of multiple 32-bit integers. For example, the user may enter the following values (showing in hex for ease of explanation):
0x00001234
0x00005678
0x0000abcd
In this particular case, the first 2 bytes of each input is constant, and the last 2 bytes are variable. For efficiency purposes, I could store 0x0000 as a single constant, and create a vector of uint16_t values to store the variable portion of the input (0x1234, 0x5678, 0xabcd).
Now let's say the user enters the following:
0x00000234
0x56780000
0x00001000
In this case I would need a vector of uint32_t values to store the variable portion of the input as each value affects different bytes.
My current thought is to do the following:
uint32_t myVal = 0;
myVal |= input1;
myVal |= input2;
// ...
And then at the end find the distance between the first and last "toggled" (i.e. 1) bit in myVal. The distance will give me required field size for the variable portion of all of the inputs.
However, this doesn't sound like it would scale well for a large number of user inputs. Any recommendations about an elegant and efficient way of determining this?
Update:
I simplified the problem in my above explanation.
Just to be clear, I am not doing this to save memory (I have better things to do than to try and conserve a few bytes and this isn't for optimization purposes).
In summary, component A provides component B in my system with values. Sometimes these values are 128-bit, but component B only supports 32-bit values.
If the variable portion of the 128-bit value can be expressed with a 32-bit value, I can accept it. Otherwise I will need to reject it with an error.
I'm not in a position to modify component B to allow 128-bit values, or modify component A to prevent its use of 128-bit values (there are hardware limitations here too).
Though I can't see a reason for all that... Why just not to compare an input with the std::numeric_limits<uint16_t>::max()? If the input gives a larger value then you need to use uint32_t.
Answering your edit:
I suppose for for better performance you should use hardware specific low level instructions. You could iterate over 32-bit parts of the input 128-bit value and subsequently add each one to the some variable and check the difference between next value and current sum. If the difference isn't equal to the sum then you should skip this 128-bit value, otherwise you'll get the necessary result in the end. The sample follows:
uint32_t get_value( uint32_t v1, uint32_t v2, uint32_t v3, uint32_t v4)
{
uint32_t temp = v1;
if ( temp - v2 != temp ) throw exception;
temp += v2; if ( temp - v3 != temp ) throw exception;
temp += v3; if ( temp - v4 != temp ) throw exception;
temp = v4;
return temp;
}
In this C++ example it may be looks silly but I believe in the assembly code this should efficiently process the input stream.
Store the first full 128 bit number you encounter, then push the lower order 32 bits of it onto a vector, set bool reject_all = false. For each remaining number, if high-order (128-32=96) bits differ from the first number's then set reject_all = true, otherwise push their lower-order bits on the vector. At the end of the loop, use reject_all to decide whether to use the vector of values.
The most efficient way to store a series of unsigned integers in the range [0, (2^32)-1] is by just using uint32_t. Jumping through hoops to save 2 bytes from user input is not worth your time--the user cannot possibly, in his lifetime, enter enough integers that your code would have to start compressing them. He or she would die of old age long before memory constraints became apparent on any modern system.
It looks like you have to come up with a cumulative bitmask -- which you can then look at to see whether you have trailing or leading constant bits. An algorithm that operates on each input will be required (making it an O(n) algorithm, where n is the number of values to inspect).
The algorithm would be similar to something like what you've already done:
unsigned long long bitmask = 0uL;
std::size_t count = val.size();
for (std::size_t i = 0; i < count; ++i)
bitmask |= val[i];
You can then check to see how many bits/bytes leading/trailing can be made constant, and whether you're going to use the full 32 bits. If you have access to SSE instructions, you can vectorize this using OpenMP.
There's also a possible optimization by short-circuiting to see if the distance between the first 1 bit and the last 1 bit is already greater than 32, in which case you can stop.
For this algorithm to scale better, you're going to have to do it in parallel. Your friend would be vector processing (maybe using CUDA for Nvidia GPUs, or OpenCL if you're on the Mac or on platforms that already support OpenCL, or just OpenMP annotations).
Use
uint32_t ORVal = 0;
uint32_t ANDVal = 0xFFFFFFFF;
ORVal |= input1;
ANDVal &= input1;
ORVal |= input2;
ANDVal &= input2;
ORVal |= input3;
ANDVal &= input3; // etc.
// At end of input...
mask = ORVal ^ ANDVal;
// bit positions set to 0 were constant, bit positions set to 1 changed
A bit position in ORVal will be 1 if at least one input had 1 in that position and 0 if ALL inputs had 0 in that position. A bit position in ANDVal will be 0 if at least one input had 0 in that bit position and 1 if ALL inputs had 1 in that position.
If a bit position in inputs was always 1, then ORVal and ANDVal will both be set to 1.
If a bit position in inputs was always 0, then ORVal and ANDVal will both be set to 0.
If there was a mix of 0 and 1 in a bit position then ORVal will be set to 1 and ANDVal set to 0, hence the XOR at the end gives the mask for bit positions that changed.