Splitting a numbers binary representation for a double.

Use and complete the template provided. The entire template must be completed. If you don't, your post may be deleted!

  1. The problem statement, all variables and given/known data:
    Split a 64bit hexadecimal number into two 32 bit numbers or keys.

  2. Relevant commands, code, scripts, algorithms:

double key = 0; //Stores the key value entered by the user.
double key_copy = key;
int k1;  //1st half of key.
int k2;  //2nd half of key.
  1. The attempts at a solution (include all code and scripts):
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;

int main( int argc, char * argv[] )
{
double key = 0; //Stores the key value entered by the user.
double index = 15; /*Used for pow function.  For loop index corresponds to
hexadecimal powers.*/
if( argc > 1 )
{
if( strlen( argv[1] ) == 16 )
{
        for( int i = 0; i < 16; i++ )
        {
                switch( argv[1] )
                {
                        case '0': key += 0 * pow( 16.0, index );
                                break;
                        case '1': key += 1 * pow( 16.0, index );
                                break;
                        case '2': key += 2 * pow( 16.0, index );
                                break;
                        case '3': key += 3 * pow( 16.0, index );
                                break;
                        case '4': key += 4 * pow( 16.0, index );
                                break;
                        case '5': key += 5 * pow( 16.0, index );
                                break;
                        case '6': key += 6 * pow( 16.0, index );
                                break;
                        case '7': key += 7 * pow( 16.0, index );
                                break;
                        case '8': key += 8 * pow( 16.0, index );
                                break;
                        case '9': key += 9 * pow( 16.0, index );
                                break;
                        case 'A': key += 10 * pow( 16.0, index );
                                break;
                        case 'B': key += 11 * pow( 16.0, index );
                                break;
                        case 'C': key += 12 * pow( 16.0, index );
                                break;
                        case 'D': key += 13 * pow( 16.0, index );
                                break;
                        case 'E': key += 14 * pow( 16.0, index );
                                break;
                        case 'F': key += 15 * pow( 16.0, index );
                                break;
                        default: cout << "You entered a non-hexadecimal value.\n";
                                exit(0);
                }
                index--;
        }

        double key_copy = key;
        int k1;  //1st half of key.
        int k2;  //2nd half of key.
        key_copy /= pow( 2.0, 32.0 );  //Shift key to right to get 1st half of binary.
        k1 = (int) key_copy;
        key_copy = key;
        key_copy *= pow( 2.0, 31.0 );  //Shift key to left then right to get 2nd half
        key_copy /= pow( 2.0, 31.0 );  //of binary representation.
        k2 = key_copy;

        cout << k1 << endl;
        cout << k2 << endl;
}
}
        return 0;
}
  1. Complete Name of School (University), City (State), Country, Name of Professor, and Course Number (Link to Course):
    University of Missouri Saint Louis, Saint Louis (Missouri), United States, Michael Schulte, 4780 (cs.umsl.edu/~schulte)

Note: Without school/professor/course information, you will be banned if you post here! You must complete the entire template (not just parts of it).

It would be nice to know what you think isn't working, or where you are stuck. Modulo that, from looking at (not trying to build/execute) your code....

Your approach makes a mountain from a mole hill I think; unless you aren't allowed to use strtoll(). If there are no restrictions, then have a look at the strtoll() manual page, and if you need to add error checking to ensure that a non-hex character hasn't been entered, have a peek at the strspn() manual page too.

If there are restrictions, there still isn't the need for the use of the pow() function; simple (unsigned) character based math and shifting are all that are needed. Consider this example:

   unsigned char *cval = "123";
    int val = 0;
    int i;

    for( i = 0; i < strlen( cval ); i++ )
    {
        val <<= 4;
        val += cval - '0';
    }
    printf( "%x\n", val );

You'll have to handle a-f and A-F which aren't handled here, but this might point you in the direction of an easier way if strtoll() has to be avoided for the assignment.

Using floating point values for this will make things much more difficult; stick with 64 bit integer. I'd also think about bitwise AND and shift operations as a way to split your key.

The long long int knowledge seems like it will be very helpful along with the unsigned math you showed. The strtoll() I am sure is helpful, I am just not too sure yet what to do with it. Thanks.

Use it to replace your loop that builds values from argv elements.

long long val;

val = strtoll( argv[1], NULL, 16 );
#include <iostream>
#include <stdlib.h>
using namespace std;

int main()
{
        char *hex_key = "abcdef012345678";
        long long key = strtoll( hex_key, NULL, 16 );

        cout << key << endl;
}

on compilation:
g++ b.cpp
b.cpp: In function �int main()�:
b.cpp:7: warning: deprecated conversion from string constant to �char*�

output:
./a.out
773738358679819896

Is there anything I can do to get rid of the warning?

Also, the full hex_key is 9abcdef012345678 which is different from what I used in the above code because of the 9 at the beginning. The output of this is 9223372036854775807
which is different from a result shown on a webpage that calculates hexadecimal numbers. All the outputs for the other hex_key values are consistent with the calculating website. Why is this number different?

Also, in your first reply you gave me

unsigned char *cval = "123";
    int val = 0;
    int i;

    for( i = 0; i < strlen( cval ); i++ )
    {
        val <<= 4;
        val += cval - '0';
    }
    printf( "%x\n", val );

and I am wondering why you subtract '0' and why you shift 4. Is it necessary to shift << by four each time you add a new hex digit?

---------- Post updated at 08:38 PM ---------- Previous update was at 12:56 PM ----------

ok, strtoull() was the function that gets the whole 16 hex digits. the unsigned long long type was what I should have been using.

Glad you figured that out. I was in the process of replying and when I refreshed saw your addition.

The warning must be a C++ thing; I'm a C person, so that construct makes sense to me. Not sure how to get rid of it.

It is not necessary to shift both values

The subtraction in the code is a quick way to convert a digit represented in ASCII to a value. The numbers 0 through 9 have ASCII values 0x30, 0x31... 0x39. If the input value on the command line is "42" argv[x] points to two bytes: 0x34 0x32 . To convert the first character (4) into an integer 4, you can subtract the value of the character zero from it (0x34 - 0x30) which yields 4. You would do the same for the values A-F and a-f to convert the ASCII representation of the hex digit to a value.

Yes, it is necessary to shift the value in val by 4 bits each time you add in a digit. Lets assume "123" was entered on the command line. The first time through the loop val is 0 and the shift has no effect. The character '1' is converted to integer and added to val; val becomes 1.

The second time through the loop val is shifted and becomes 0x10. The character '2' is converted to integer and then is added to val which now holds the value 0x12.

Again val is shifted and bcomes 0x120. The '3' is converted and added to val leaving the variable with 0x123.

Think of it as sliding the digits over one nibble to the left to make room for the next value.

Hope that makes some sense.

1 Like