tags:

views:

2202

answers:

8

Hi,

I'm trying to get the numerical (double) value from a byte array of 16 elements, as follows:

unsigned char input[16];
double output;
...
double a  = input[0];
distance = a;
for (i=1;i<16;i++){
    a = input[i] << 8*i;
    output += a;
}

but it does not work. It seems that the temporary variable that contains the result of the left-shift can store only 32 bits, because after 4 shift operations of 8 bits it overflows.

I know that I can use something like

a = input[i] * pow(2,8*i);

but, for curiosity, I was wondering if there's any solution to this problem using the shift operator...

A: 

Well based off of operator precedence the right hand side of

a = input[i] << 8*i;

gets evaluated before it gets converted to a double, so you are shifting input[i] by 8*i bits, which stores its result in a 32 bit temporary variable and thus overflows. You can try the following:

a = (long long unsigned int)input[i] << 8*i;

Edit: Not sure what the size of a double is on your system, but on mine it is 8 bytes, if this is the case for you as well the second half of your input array will never be seen as the shift will overflow even the double type.

DeusAduro
+1  A: 

Have you tried std::atof:

http://www.cplusplus.com/reference/clibrary/cstdlib/atof/

fbrereto
I believe the input is not ascii, but actually a floating point value in a buffer.
Dave Mooney
Only relevant if the input is string format of a number, if he has dumped a double to memory and then loaded it as a char array this would fail.
DeusAduro
+1  A: 

Are you trying to convert a string representation of a number to a real number? In that case, the C-standard atof is your best friend.

xcramps
+4  A: 

Edit: this won't work (see comment) without something like __int128.

a = input[i] << 8*i;

The expression input[i] is promoted to int (6.3.1.1) , which is 32bit on your machine. To overcome this issue, the lefthand operand has to be 64bit, like in

a = (1L * input[i]) << 8*i;

or

a = (long long unsigned) input[i] << 8*i;

and remember about endianness

Adrian Panasiuk
Won't this still overflow once he tries to do the (<< 8*i) for the i>= 9 part of the loop since this loop seems to be trying to convert a 128bit value to a double, or am I missing something here?
Falaina
+1  A: 

In short, No, you can't convert a sequence of bytes directly into a double by bit-shifting as shown by your code sample.

byte, an integer type and double, a floating point type (i.e. not an integer type) are not bitwise compatible (i.e. you can't just bitshift to values of a bunch of bytes into a floating point type and expect an equivalent result.)

1) Assuming the byte array is a memory buffer referencing an integer value, you should be able to convert your byte array into a 128-bit integer via bit-shifting and then convert that resulting integer into a double. Don't forget that endian-issues may come into play depending on the CPU architecture.

2) Assuming the byte array is a memory buffer that contains a 128-bit long double value, and assuming there are no endian issues, you should be able to memcpy the value from the byte array into the long double value

union doubleOrByte {
    BYTE buffer[16];
    long double val;
} dOrb;
dOrb.val = 3.14159267;
long double newval = 0.0;

memcpy((void*)&newval, (void*)dOrb.buffer, sizeof(dOrb.buffer));
Jeff Leonard
+1  A: 

The problem here is that indeed the 32 bit variables cannot be shifted more than 4*8 times, i.e. your code works for 4 char's only.

What you could do is find the first significant char, and use Horner's law: anxn + an-1n-1 + ... = ((...( anx + an-1 ).x + an-2 ) . x + ... ) + a0 as follows:

char coefficients[16] = { 0, 0, ..., 14, 15 };
int exponent=15;
double result = 0.;

for(int exponent = 15; exp >= 0; --exp ) {
   result *= 256.; // instead of <<8.
   result += coefficients[ exponent ];
}
xtofl
A: 

Why not simply cast the array to a double pointer?

unsigned char input[16];

double* pd = (double*)input;

for (int i=0; i<sizeof(input)/sizeof(double); ++i)
    cout << pd[i];

if you need to fix endian-ness, reverse the char array using the STL reverse() before casting to a double array.

Inverse
A: 

i nead a help.. pls pls.. how can i read a file line by line and in each line i will get the first token as an integer the second as double and the third as array of characters..

is it possible in C++ please do help...

allchecxs