0

i am trying to convert binary value as hex value and i got the following code and it is working well up to 28 bit but not for 32 bit.

The code is as follows.

int main()
{
    long int longint=0;
    string buf;
    cin>>buf;
    int len=buf.size();
    for(int i=0;i<len;i++)
    {
        longint+=( buf[len-i-1]-48) * pow((double)2,i);
    }
    cout<<setbase(16);
    cout<<longint;
    return 0;
}

If I input 28 '1' (111111111111111111111111) then the output is fffffff but if i input 32 '1' (11111111111111111111111111111111) then the output is 80000000.

Can anyone please explain why this is happenning and also in the above code why 48 is subtracted .

Deidrei
  • 2,125
  • 1
  • 14
  • 14
user3048644
  • 93
  • 1
  • 5
  • 17

5 Answers5

1

The problem seems to be with the use of pow, which uses floating-point math, if I recall correctly.. You may be running into issues with overflow.

A more elegant way to calculate powers of two is by using bit-shifts:

2^0 = 1 << 0 = 1
2^1 = 1 << 1 = 2
2^2 = 1 << 2 = 4
2^n = 1 << n
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
1

As Nathan's post, it'll display correct when changing your code like this,

longint += (buf[len-i-1]-'0') << i;
Deidrei
  • 2,125
  • 1
  • 14
  • 14
1

You are using int32 and it is getting out of range when you use it for 32 bytes,try using int64 i.e long long

    unsigned long long longint=0; //Change Here
    string buf;
    cin>>buf;
    int len=buf.length();
    for(int i=0;i<len;i++)
    {
        longint+=( buf[len-i-1]-48) * pow((double)2,i);
    }
    cout<<setbase(16);
    cout<<longint;
kunal
  • 956
  • 9
  • 16
0
  1. This is because you have forced
    ( buf[len-i-1]-48) * pow((double)2,i)
    to be converted to double,

    and double is 8 bytes long,
    but it has to store extra information,
    it can not be full charged to represent 0x80000000,
    you can find more information here

    and your last
    ( buf[len-i-1]-48) * pow((double)2,i)
    (when i is 31) expression already overflow.
    But something weard happend when converting from 4294967295.0000000(which is 0xffffffff) to int , it just come out 0x80000000 , but I am very sorry I don't know why(Please reference the comment from TonyK).

    You can change it to

    longint+=(long int)(( buf[len-i-1]-48) * pow(2,i));

  2. Why minus 48 ?
    because ascii for '0' is 48, you want to convert from literal '0' to numeric 0, you have to do it.

Daniel King
  • 407
  • 4
  • 11
  • An IEEE double has a 53-bit mantissa, which is more than enough to store 0x80000000 to full precision. – TonyK Dec 09 '13 at 09:36
  • You are right, the real problem is if I convert 4294967295.0000000 (which is actually 0xffffffff) to int, it just come out 0x80000000, And this part is out of my understanding – Daniel King Dec 09 '13 at 12:08
  • 0xffffffff is out of range for a 32-bit signed int. If you convert it to _unsigned_ int, you should get 0xffffffff. – TonyK Dec 09 '13 at 12:23
0

The reason is that float-value is with limit precision and pow() computer use numerical calculation approximation which isn't definitely precise. To get a precise value, you should use bit-wise ">>" instead.

You can see how pow() function works as below.

I changed your code

longint+= ( buf[len-i-1]-48) * pow((double)2,i)

to the code below, which is equal, becase pow() return a double value.

double temp = ( buf[len-i-1]-48) * pow((double)2,i);
longint+= temp;
cout<<setbase(16);
cout<<"temp"<<endl;
cout<<temp<<endl;
cout<<longint<<endl;

the output is as below

temp
1.34218e+08
fffffff
temp
2.68435e+08
1fffffff
temp
5.36871e+08
3fffffff
temp
1.07374e+09
7fffffff
temp
2.14748e+09
80000000
final
80000000

Which shows clearly pow() is with limited precision. 2.14748e+09 is not equal to (2^31).

You should use ">>" which is the best or just use conversion to integer which isn't 100 percently correclty, either.

You can see conversion as below.

when I change

double temp = ( buf[len-i-1]-48) * pow((double)2,i);

to

int temp = ( buf[len-i-1]-48) * pow((double)2,i);

the result is

temp
8000000
fffffff
temp
10000000
1fffffff
temp
20000000
3fffffff
temp
40000000
7fffffff
temp
80000000
ffffffff
final
ffffffff

Which works correctly.

substract 48 You got a char from standard input, for example, you got '1' from terminal instead of 1. In order to get 1. You should use '1'-'0'. The reason : computer store '0'~'9' as a byte with value(48~57). As a result, '1' - '0' equals '1' - 48.

Sam
  • 964
  • 3
  • 11
  • 24