PDA

View Full Version : Problem with number types - convert binary QString to decimal



jimbo
29th September 2015, 14:14
linux - Qt 4.8.2

Hello,

I'm trying to convert binary strings to decimal.
Getting an error only on 32 bit binary strings. I've marked where I think the error could be, but not shore.
1, 2, 4, 8, & 16 splits are fine.
Perhaps some kind soul can explain where I'm going wrong.

Regards

Maybe thia question does not belong on this forum, feel free to delete.


QString hex, bReturn, tmpReturn;
QList<quint64> uintList = QList<quint64>();
int split = 32; // 1, 2, 4, 8, 16, 32 byte data split

QString data = readEeprom(eepromAdd, startAdd, bytesToRead, i2c);

int dl = data.length();
if (dl %split != 0) {
qDebug() << "Data length is not wholly divisible by split - (" << split << ")";
return; //exit(1);
}

qDebug() << "data - " << data << "-" << dl << "bytes -" << "split =" << split << endl;

int count = 0;
for (int i = 0; i < dl; i += split) {
hex = data.mid(i, split);
qDebug() << "hex1 - " << hex;
qDebug() << "dec1 - " << hex.toULongLong(&ok, 16); // *** this is wrong on 32 byte splits
tmpReturn = bReturn = hexToBinary(hex);
uintList.append(hex.toULongLong(&ok, 16)); //some sort of error handling on &ok // ***suspect error here***

qDebug() << count + 1 << "-" << "split" << split << uintList << "*** decimal" << uintList[count]
<< "- hexToBinary" << bReturn
<< "- binaryToHex" << binaryToHex(tmpReturn.remove(" "))
//<< "- binaryToDec" << binaryToDec(bReturn.remove(" ").rightJustified(split, '0'))
//<< "- decToBinary" << decToBinary(uintList[count]).rightJustified(split * 4, '0'); //pad with leading zeros
;


QString myProg::binaryToHex(QString sBin) { // eg. sBin = "00000000000011110000000000010000"
qDebug() << "sbin1 - " << sBin; //ok
qDebug() << "sbin2 - " << sBin.remove(QRegExp("^[0]*")); //ok

const std::string bin = sBin.remove(QRegExp("^[0]*")).toStdString();
quint64 result = 0;

for(size_t count = 0; count < bin.length(); ++count) {
result *=2;
result += bin[count]=='1'? 1 :0;
}
qDebug() << "len - " << bin.length(); //ok
qDebug() << "res - " << result; //ok
QString res = QString::number(result, 16);

return (res);
}

data - "000100020003000400050006000700080009000a000b000c00 0d000e000f0010" - 64 bytes - split = ??

split = 8
hex1 - "000f0010"
dec1 - 983056
sbin1 - "00000000000011110000000000010000"
sbin2 - "11110000000000010000"
len - 20
res - 983056
8 - split 8 (65538, 196612, 327686, 458760, 589834, 720908, 851982, 983056) *** decimal 983056 - hexToBinary "0000 0000 0000 1111 0000 0000 0001 0000" - binaryToHex "f0010"

split = 16
hex1 - "000d000e000f0010"
dec1 - 3659234827763728
sbin1 - "00000000000011010000000000001110000000000000111100 00000000010000"
sbin2 - "11010000000000001110000000000000111100000000000100 00"
len - 52
res - 3659234827763728
4 - split 16 (281483566841860, 1407400653815816, 2533317740789772, 3659234827763728) *** decimal 3659234827763728 - hexToBinary "0000 0000 0000 1101 0000 0000 0000 1110 0000 0000 0000 1111 0000 0000 0001 0000" - binaryToHex "d000e000f0010"

split = 32
hex1 - "0009000a000b000c000d000e000f0010"
dec1 - 0
sbin1 - "00000000000010010000000000001010000000000000101100 00000000001100000000000000110100000000000011100000 0000000011110000000000010000"
sbin2 - "10010000000000001010000000000000101100000000000011 00000000000000110100000000000011100000000000001111 0000000000010000"
len - 116
res - 3659234827763728 *** should be 5188234733137453056 - max value quint64 18446744073709551615***
2 - split 32 (0, 0) *** decimal 0 - hexToBinary "0000 0000 0000 1001 0000 0000 0000 1010 0000 0000 0000 1011 0000 0000 0000 1100 0000 0000 0000 1101 0000 0000 0000 1110 0000 0000 0000 1111 0000 0000 0001 0000" - binaryToHex "d000e000f0010"

Rondog
29th September 2015, 20:47
My approach to problems like this is to use a reference to the type you want to convert the data to

Example



// assuming data is 32 bit integer
int Conversion::Integer(
const unsigned int index,
const QByteArray &array)
{
int i;
char *c;
unsigned int cntr;

assert((index + sizeof(int) -1) < static_cast<unsigned int>(array.size()));

c = (char*)(&i);

for(cntr = 0;cntr < sizeof(int);cntr++)
{
*(c + cntr) = array[index + cntr];
}

return i;
}

In my example I am interested in converting part of the input data into a 32 bit integer. The input 'index' value is the offset from where to start the data conversion in the input array data. The pointer character 'c' is a reference to the same address (stack) space as the returned integer 'i'. When you modify the text contents of 'c' you are also changing the binary data of 'i'.

QByteArray has methods to convert to and from hexadecimal. Your data (i.e. "000100020003000400050006000700080009000a000b000c00 0d000e000f0010") is in hexadecimal. If you want to extract integer, floating point values, text, or whatever from your data you need to convert it from hex first. Prior to calling the above example you must call QByteArray::fromHex(...) to convert "000100020003000400050006000700080009000a000b000c00 0d000e000f0010" to actual binary data.

jefftee
30th September 2015, 09:00
I'm trying to convert binary strings to decimal.
I am not really sure I understand what you're trying to accomplish. You state you want to convert to decimal, yet you appear to want to convert to the hex equivalent of your binary string. Is there a reason you can't do something as simple as:


book ok;
QString binary = "00000000000011110000000000010000";
qint64 dec = binary.toLongLong(&ok, 2);
QString hex;
hex.sprintf("%llx", dec);
qDebug() << "bin=" << binary;
qDebug() << "dec=" << dec;
qDebug() << "hex=" << hex;

jimbo
30th September 2015, 14:10
Hello jefftee,

Thanks for your example, its a lot shorter than mine. (my ignorance)
I think I should have been more explicit with my problem.
Splits at 1, 2, 4, 8 and 16 give corrrect results.
The problem is with the 32 bit split, decimal and hex return "0" with your code and mine.
I think its probably a problem with overflow and number types. (don't know)

Regards


qDebug() << "data - " << data << "-" << dl << "bytes -" << "split =" << split << endl;

for (int i = 0; i < dl; i += split) {
hex = data.mid(i, split);
tmpReturn = hexToBinary(hex); //my hexToBinary() tested and works.
qDebug() << "hex 1 - " << hex;
qDebug() << "bin - " << tmpReturn;

bool ok;
QString binary = tmpReturn.remove( " ");
qint64 dec1 = binary.toLongLong(&ok, 2);
if (!ok) qDebug() << "error";
QString hex;
hex.sprintf("%llx", dec1);
qDebug() << "bin2 = " << binary;
qDebug() << "dec2 = " << dec1;
qDebug() << "hex2 = " << hex;
qDebug() << "";
}
//Output for a 16 bit split

data - "000100020003000400050006000700080009000a000b000c00 0d000e000f0010" - 64 bytes - split = 16

//Loops 0, 1, and 2 omittted.

hex 1 - "000d000e000f0010"
bin - "0000 0000 0000 1101 0000 0000 0000 1110 0000 0000 0000 1111 0000 0000 0001 0000"
bin2 = "00000000000011010000000000001110000000000000111100 00000000010000"
dec2 = 3659234827763728
hex2 = d000e000f0010"
//Output for a 32bit split

data - "000100020003000400050006000700080009000a000b000c00 0d000e000f0010" - 64 bytes - split = 32

//Loop 0 omittted.

hex 1 - "0009000a000b000c000d000e000f0010"
bin - "0000 0000 0000 1001 0000 0000 0000 1010 0000 0000 0000 1011 0000 0000 0000 1100 0000 0000 0000 1101 0000 0000 0000 1110 0000 0000 0000 1111 0000 0000 0001 0000"
error
bin2 = "00000000000010010000000000001010000000000000101100 00000000001100000000000000110100000000000011100000 0000000011110000000000010000"
dec2 = 0
hex2 = "0"

jefftee
30th September 2015, 20:59
Integer overflow is certainly your issue. See the data below for min/max and sizes for qlonglong:

qlonglong size (bytes) = 8
qlonglong bits = 64 (8 bits/byte times 8 bytes = 64 bits with 63 for precision 1 for sign)
qlonglong min = -9,223,372,036,854,775,808
qlonglong max = +9,223,372,036,854,775,807

What you refer to as a 16-bit split actually requires 64 bits or 8 byte precision, which does not overflow a qlonglong. i.e. You are taking 16 positions from the string, each requires 4 bits to represent the range of possible 0-F values, for a total of 16 x 4 = 64 bits.

What you are calling a 32-bit split would actually require an integer data type with 128 bit or 16 byte precision, which will overflow a qlonglong or qulonglong. i.e. You are taking 32 positions, each requires 4 bits to represent the range of possible 0-F values, for a total of 32 x 4 = 128 bits or 16 bytes.

So, your quest for a 32-bit split [sic] is not possible, nor do I see why you would even care to do so. Since your code works for "splits" up to 16 positions (or the more simplified code I provided also works), is/was this just some educational exercise or why do you perceive the need to process in 32 position chunks?

jimbo
30th September 2015, 21:12
Hello jefftee,


is/was this just some educational exerciseYes, I'm afraid so! While I'm trying to learn.
Thank you for your time and effort.

Regards

jefftee
30th September 2015, 21:20
Heh, not a problem, glad I could help. I just wanted to make sure there wasn't something I was missing. Believe me, I've been down many rabbit holes myself trying to understand why something worked or didn't work accordingly, so I completely understand!