Bit masking to determine if number is positive or negative c++ - c++

I want to replicate the behaviour of a micro controller.
If the memory location of the program counter contains 0x26 then I want to check that the value in the next memory location is positive or negative.
If it is positive then I add it to the program counter PC and if it is negative then I add it to the program counter PC, which is essentially subtracting it.
I am using bit masking to do this but I am having issues determining a negative value.
{
if (value_in_mem && 128 == 128)
{
cout << "\nNext byte is : " << value_in_mem << endl;
cout << "\nNumber is positive!" << endl;
PC = PC + value_in_mem;
cout << "\n(Program Counter has been increased)" << endl;
}
else if (value_in_mem && 128 == 0)
{
cout << "\nNext byte is : - " << value_in_mem << endl;
cout << "\nNumber is negative!" << endl;
PC = PC + value_in_mem;
cout << "\n(Program Counter has been decreased)" << endl;
}
}
My method is to && the value_in_mem (an 8 bit signed int) with 128 (0b10000000) to determine if the most significant bit is 1 or 0, negative or postitve respectively.
value_in_mem is a 8-bit hexadecimal value and I think this is where my confusion lies. I'm not entirely sure how negative hexadecimal values work, could someone possibly explain this and the errors in my attempt at the code?

1) You're using && which is a logical AND but you should use & which is a bitwise AND.
// It would be better to use hex values when you're working with bits
if ( value_in_mem & 0x80 == 0x80 )
{
// it's negative
}
else
{
// it's positive
}
2) You can simply compare your value to 0 (if value_in_mem is declared as char)
if ( value_in_mem < 0 )
{
// it's negative
}
else
{
// it's positive
}

Make sure you are using correct types for your values (or cast them where it matters, if you prefer for example to have memory values as unsigned bytes most of the time (I certainly would), then cast it to signed 8 bit integer only for the particular calculation/comparison by static_cast<int8_t>(value_in_mem) ).
To demonstrate the importance of correct typing, and how C++ compiler will then do all the dirty work for you, so you don't have to bother with bits and can use also if (x < 0):
#include <iostream>
int main()
{
{
uint16_t pc = 65530; int8_t b = 0xFF; pc += b;
std::cout << pc << "\n"; // unsigned 16 + signed 8
// 65529 (b works as -1, 65530 - 1 = 65529)
}
{
int16_t pc = 65530; int8_t b = 0xFF; pc += b;
std::cout << pc << "\n"; // signed 16 + signed 8
// -7 (b works as -1, 65530 as int16_t is -6, -6 + -1 = -7)
}
{
int16_t pc = 65530; uint8_t b = 0xFF; pc += b;
std::cout << pc << "\n"; // signed 16 + unsigned 8
// 249 (b works as +255, 65530 as int16_t is -6, -6 + 255 = 249)
}
{
uint16_t pc = 65530; uint8_t b = 0xFF; pc += b;
std::cout << pc << "\n"; // unsigned 16 + unsigned 8
// 249 (b = +255, 65530 + 255 = 65785 (0x100F9), truncated to 16 bits = 249)
}
}

Related

Integer Arithmetics Going Wild

Please, could somebody explain what's happening under the hood there?
The example runs on an Intel machine. Would the behavior be the same on other architectures?
Actually, I have a hardware counter which overruns every now and then, and I have to make sure that the intervals are always computed correctly. I thought that integer arithmetics should always do the trick but when there is a sign change, binary subtraction yields an overflow bit which appears to be actually interpreted as the sign.
Do I really have to handle the sign by myself or is there a more elegant way to compute the interval regardless of the hardware or the implementation?
TIA
std::cout << "\nTest integer arithmetics\n";
int8_t iFirst = -2;
int8_t iSecond = 2;
int8_t iResult = iSecond - iFirst;
std::cout << "\n" << std::to_string(iSecond) << " - " << std::to_string(iFirst) << " = " << std::to_string(iResult);
iResult = iFirst - iSecond;
std::cout << "\n" << std::to_string(iFirst) << " - " << std::to_string(iSecond) << " = " << std::to_string(iResult);
iFirst = SCHAR_MIN + 1; iSecond = SCHAR_MAX - 2;
iResult = iSecond - iFirst;
std::cout << "\n" << std::to_string(iSecond) << " - " << std::to_string(iFirst) << " = " << std::to_string(iResult);
iResult = iFirst - iSecond;
std::cout << "\n" << std::to_string(iFirst) << " - " << std::to_string(iSecond) << " = " << std::to_string(iResult) << "\n\n";
And this is what I get:
Test integer arithmetics
2 - -2 = 4
-2 - 2 = -4
125 - -127 = -4
-127 - 125 = 4
What happens with iResult = iFirst - iSecond is that first both variables iFirst and iSecond are promoted to int due to usual arithmetic conversion. The result is an int. That int result is truncated to int8_t for the assignment (in effect, the top 24 bits of the 32-bit int is cut away).
The int result of -127 - 125 is -252. With two's complement representation that will be 0xFFFFFF04. Truncation only leaves the 0x04 part. Therefore iResult will be equal to 4.
the problem is that your variable is 8 bit. 8 bits can hold up to 256 numbers. So, your variables can only represent numbers within -128~127 range. Any number out of that range will give wrong output. Both of your last calculations produce numbers beyond the variable's range (252 and -252). There is no elegant or even possible way to handle it as it is. You can only handle the overflow bit yourself.
PS. This is not hardware problem. Any processor would give same results.

Why is UINT32_MAX + 1 = 0?

Consider the following code snippet:
#include <cstdint>
#include <limits>
#include <iostream>
int main(void)
{
uint64_t a = UINT32_MAX;
std::cout << "a: " << a << std::endl;
++a;
std::cout << "a: " << a << std::endl;
uint64_t b = (UINT32_MAX) + 1;
std::cout << "b: " << b << std::endl;
uint64_t c = std::numeric_limits<uint32_t>::max();
std::cout << "c: " << c << std::endl;
uint64_t d = std::numeric_limits<uint32_t>::max() + 1;
std::cout << "d: " << d << std::endl;
return 0;
}
Which gives the following output:
a: 4294967295
a: 4294967296
b: 0
c: 4294967295
d: 0
Why are b and d both 0? I cannot seem to find an explanation for this.
This behaviour is referred to as an overflow. uint32_t takes up 4 bytes or 32 bits of memory. When you use UINT32_MAX you are setting each of the 32 bits to 1 which is the maximum value 4 bytes of memory can represent. 1 is an integer literal which typically takes up 4 bytes of memory too. So you're basically adding 1 to the maximum value 4 bytes can represent. This is how the maximum value looks like in memory:
1111 1111 1111 1111 1111 1111 1111 1111
When you add one to this, there is no more room to represent one greater than the maximum value and hence all bits are set to 0 and back to their minimum value.
Although you're assigning to a uint64_t that has twice the capacity of uint32_t, it is only assigned after the addition operation is complete.
The addition operation checks the types of both the left and the right operands and this is what decides the type of the result. If atleast one value were of type uint64_t, the other operand would automatically be promoted to uint64_t too.
If you do:
(UINT32_MAX) + (uint64_t)1;
or:
(unint64_t)(UINT32_MAX) + 1;
,
you'll get what you expect. In languages like C#, you can use a checked block to check for overflow and prevent this from happening implicitly.

Binary representation, how do I get to the 'relevant bits'?

There are a couple of tutorials on google, but most show how to print binary representation of a number and do so by printing the whole 16/32 bits.
My question is how do you find out which is the most significant bit that is 1 and work(not necessarily print them) with those after it, itself included.
You can iterate the bits and check each bit's value:
uint data = 0x4AC;
for (auto i = 1, c = 0; c < sizeof(uint)*8; i = i << 1, ++c)
{
if ((data & i) > 0)
{
std::cout << "bit " << i <<" is 1" << std::endl;
}
}
bit 4 is 1
bit 8 is 1
bit 32 is 1
bit 128 is 1
bit 1024 is 1

Bit shift for 32 and 64 unsigned integers

I have a question with this snippet of code:
uint32_t c = 1 << 31;
uint64_t d = 1 << 31;
cout << "c: " << std::bitset<64>(c) << endl;
cout << "d: " << std::bitset<64>(d) << endl;
cout << (c == d ? "equal" : "not equal") << endl;
The result is:
c: 0000000000000000000000000000000010000000000000000000000000000000
d: 1111111111111111111111111111111110000000000000000000000000000000
not equal
Yes, I know that the solution for 'd' is to use '1ULL'. But I cannot understand why this happens when the shift is of 31 bits. I read somewhere that it is safe to shift size-1 bits, so if I write the instruction without the 'UUL' and the literal '1' is 32 bits long then it should be safe to shift it 31 bits, right?
What am I missing here?
Regards
YotKay
The problem is that the expression that you shift left, namely, the constant 1, is treated as a signed integer. That is why the compiler performs sign extension on it before assigning the result to d, causing the result that you see.
Adding suffix U to 1 will fix the problem (demo).
uint64_t d = 1U << 31;

read different data types in line c++

I'm starting in c++ and I need to read a binary file.
I know the structure of file, i.e, each file line is composed by:
'double';'int8';'float32';'float32';'float32';'float32';'float32';'float32';'int8';'float32';'float32';'float32';'float32';'int8';'float32'
or in byte numbers:
8 1 4 4 4 4 4 4 1 4 4 4 4 1 4
I made some code but is too obsolete...
Here is the code:
void test1 () {
const char *filePath = "C:\20110527_phantom19.elm2";
double *doub;
int *in;
float *fl;
FILE *file = NULL;
unsigned char buffer;
if ((file = fopen(filePath, "rb")) == NULL)
cout << "Could not open specified file" << endl;
else
cout << "File opened successfully" << endl;
// Get the size of the file in bytes
long fileSize = getFileSize(file);
cout << "Tamanho do ficheiro: " << fileSize;
cout << "\n";
// Allocate space in the buffer for the whole file
doub = new double[1];
in = new int[1];
fl = new float[1];
// Read the file in to the buffer
//fread(fileBuf, fileSize, 1, file);
//fscanf(file, "%g %d %g", doub[0],in[0],fl[0]);
fread(doub, 8, 1, file);
//cout << doub[0]<< " ";
fseek (file ,8, SEEK_SET);
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< "\n";
cin.get();
//delete[]fileBuf;
fclose(file);
}
How can I change this to an efficient way?
What's the problem when you can easily read whole structs with your custom format and have the fields automatically filled with correct values?
struct MyDataFormat {
double d;
int8 i1;
float32 f[6];
..
};
MyDataFormat buffer;
fread(&buffer, sizeof(MyDataFormat), 1, file);
If each line is the same format I would probably read a line at a time into a buffer and then have a function that pulled that buffer apart into separate elements - easier to understand, easier to test, works with larger files and is possibly more efficent to do fewer reads.
In addition to the "structure" of the file, we need to know the format
of the data types involved, and what you mean by "line", if the format
isn't a text format. In general, however, you will 1) have to read an
appropriately sized block, and then extract each value from it,
according to the specified format. For integral values, it's fairly
easy to extract an unsigned integral value using shifts; for int8, in
fact, you just have to read the byte. For most machines, just casting
the unsigned integer into the correspondingly sized signed type will
work, although this is explicitly not guaranteed; if the unsigned char
is greater than CHAR_MAX, you'll have to scale it down to get the
appropriate value: something like -(UCHAR_MAX+1 - value) should do the
trick (for chars—for larger types, you also have to worry about
the fact that UINT_MAX+1 will overflow).
If the external format is IEEE, and that's also what your machine
uses (the usual case for Windows and Unix machines, but rarely the case
for mainframes), then you can read an unsigned 4 or 8 byte integer
(again, using shifts), and type pun it, something like:
uint64_t
get64BitUInt( char const* buffer )
{
return reinterpret_cast<double>(
((buffer[0] << 52) & 0xFF)
| ((buffer[1] << 48) & 0xFF)
| ((buffer[2] << 40) & 0xFF)
| ((buffer[3] << 32) & 0xFF)
| ((buffer[4] << 24) & 0xFF)
| ((buffer[5] << 16) & 0xFF)
| ((buffer[6] << 8) & 0xFF)
| ((buffer[7] ) & 0xFF) );
}
double
getDouble( char const* buffer )
{
uint64_t retval = get64BitUInt( buffer );
return *reinterpret_cast<double*>( &retval );
}
(This corresponds the usual network byte order. If your binary format
uses another convention, you'll have to adapt it. And the
reinterpret_cast depends on implementation defined behavior; you may
have to rewrite it as:
double
getDouble( char const* buffer )
{
union
{
double d;
uint64_t i;
} results;
results.i = get64BitUInt( buffer );
return results.d;
}
. Or even use memcpy to copy from a uint64_t into a double.)
If your machine doesn't use IEEE floating point, and the external format
is IEEE, you'll have to pick up the 8 byte word as an 8 byte unsigned
int (unsigned long long), then extract the sign, exponent and mantissa
according to the IEEE format; something like the following:
double
getDouble( char const* buffer )
{
uint64_t tmp( get64BitUInt( buffer );
double f = 0.0 ;
if ( (tmp & 0x7FFFFFFFFFFFFFFF) != 0 ) {
f = ldexp( ((tmp & 0x000FFFFFFFFFFFFF) | 0x0010000000000000),
(int)((tmp & 0x7FF0000000000000) >> 52) - 1022 - 53 ) ;
}
if ( (tmp & 0x8000000000000000) != 0 ) {
f = -f ;
}
return f;
}
Don't do this until you're sure you'll need it, however.