8

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...

4
  • You haven't said what "input[16]" is trying to represent. Is it a 128-bit integral value, or something else? Commented Aug 19, 2009 at 17:34
  • 1
    Are you storing the number in "input" in the form of a 128bit unsigned integer? Commented Aug 19, 2009 at 17:35
  • @Roddy: from his algorithm it seems that the characters are the coefficients in a 15-th order polynomial (with base 256). (@paolo_, is this right?) Commented Aug 19, 2009 at 18:18
  • as said by Adrian P., the input[16] vector is a sequence of bits that i want to represent as a 128bit unsigned integer Commented Aug 19, 2009 at 20:13

7 Answers 7

4

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

Sign up to request clarification or add additional context in comments.

1 Comment

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?
4

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 ];
}

Comments

2

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));

Comments

2

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.

1 Comment

By far and away the simplest solution!
1

Have you tried std::atof:

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

2 Comments

I believe the input is not ascii, but actually a floating point value in a buffer.
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.
1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.