-2

I got large HEX string in result into int i could be more than 10 ^ 30, and I converted in hex. I need sum (3 hex string) and remove last 12 numbers.

hex example "000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835", "000000000000000000000000000000000000000000000000f32f5908b7f3c000", "00000000000000000000000000000000000000000000000000e969cd49be4000". And I need to sum them and get result into int. Thank you

I "made" a little two functions and they work but i think could be better, and they dont convert to normal integer number


    // convert hex to unsigned char decimal
    unsigned char div10(unsigned char *hex, unsigned size)
    {
        unsigned rem = 0;
        for(int i = 0; i < size; i++)
        {
            unsigned n = rem * 256 + hex[i];
            hex[i] = n / 10;
            rem = n % 10;
        }
        return rem;
    }
    
    
    unsigned char hex_to_dec_summer(char *local){
        unsigned char result[32]={0};
        unsigned char output[18]={};
    
        char input[64];
        strcpy(input, local);
    
        unsigned char hexnr[sizeof(input)/2]={}; 
        for (int i=0; i<sizeof(input)/2; i++) {
            sscanf(&input[i*2], "%02xd", &hexnr[i]);
        }
        
        
        unsigned char hexzero[32] = {0};
        unsigned i = 0;
        while(memcmp(hexnr, hexzero, sizeof(hexnr)) != 0 && i < sizeof(result))
        {
            result[sizeof(result) - i - 1] = div10(hexnr, sizeof(hexnr));
            i++;
        }
        printf("\n");
    
        for(unsigned j = 0; j < sizeof output; j++)
        {
            output[j]=result[j];
            printf("%d", output[j]);
        }
        output[18]='\0';
    }

I know how its make in python3 -> int(hex_number, 16)/(10**12) - like that but i need it in c

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • 1
    For 160-bit numbers like `0xbd4c61f945644cf099d41ab8a0ab2ac5d2533835`, in C you're going to need an [arbitrary-precision arithmetic](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) library. You can use [GMP](https://gmplib.org/), or write your own. See also [this question](https://stackoverflow.com/questions/565150). – Steve Summit Sep 16 '22 at 20:50
  • How can you tell 000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835 and 000000000000000000000000000000000000000000000000f32f5908b7f3c000 from 000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835000000000000000000000000000000000000000000000000f32f5908b7f3c000? – user4581301 Sep 16 '22 at 20:55
  • *And I need to sum them and get result into int* Or what? Because there's no implementation of C anywhere, ever, that I'm aware of that can fit those values into any C integer value. – Andrew Henle Sep 16 '22 at 20:58
  • 1
    Determine the length of the string. With C that's `strlen`, If they are always 64 characters long, it's even easier. Then `&input[length-12]` will give you a pointer to the start of the region of interest. Feed the string into the parser of your choice. I'd probably start with `strtol`, but it typically can't handle 12 hex characters. – user4581301 Sep 16 '22 at 21:02
  • 1
    @user4581301 `strtoull()` would probably be better - it could handle a full 16 hexadecimal characters as `unslgned long long` is guaranteed to be at least 64 bits. Although those leading zeros imply larger values are possible. I'm seeing things like RSA exponents pass before me. – Andrew Henle Sep 16 '22 at 21:06
  • @AndrewHenle Mostly agreed. Unless I'm reading this wrong, the OP states they only care about the last 12 digits, so 64 bits should be enough. Now we just need a 64 bit `int`. – user4581301 Sep 16 '22 at 21:10
  • @user4581301 As I read it, they care about the *first* digits, all but the last 12 *decimal* digits. But it's not so easy to divide 0xbd4c61f945644cf099d41ab8a0ab2ac5d2533835 by 1000000000000 without, like, actually doing the math. – Steve Summit Sep 16 '22 at 21:14
  • I can see your reading, but I'm going to stick with mine and ask for clarification. Aeroxer, can you give us an example of how you want the inputs broken down? Just walk us through how you would decompose the inputs if you had to do it with pen and paper. – user4581301 Sep 16 '22 at 21:19
  • @AeroxerSupport As I understand it, you want to add `bd4c61f945644cf099d41ab8a0ab2ac5d2533835` + `f32f5908b7f3c000` + `e969cd49be4000` = `b44lf9c96ibe8g99296hcl5kd40f3b6bg6df`, and then lop off the last 12 digits. So you either want `b44lf9c96ibe8g99296hcl5k`, or (converted to decimal) `1080702647035076263416932216315997551930810644533` → `1080702647035076263416932216315997551`. Is that right? And is it in fact 12 decimal digits or 12 hexadecimal digits you want to lop off? – Steve Summit Sep 16 '22 at 21:50
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Sep 17 '22 at 00:25
  • @user4581301 `strtoull()` don't usefull because i can have larger number than unsigned long long after conversion from hex, and for it i need to remove last 12 digits – Aeroxer Support Sep 17 '22 at 07:14
  • Sorry for waiting. All what i want its do as this python function (int(hex_number, 16)/(10**12)) for all hex string which will give to him. I could have 1 only input hex or can have 5 input hex string. And after they convertion to int SUM them to one single number. It doesn't matter to me whether the division will occur immediately after the conversion, or whether it will occur after the summation. The main thing is that it works as quickly as possible @SteveSummit – Aeroxer Support Sep 17 '22 at 07:16
  • @SteveSummit It's could be like than: sum all hex bd4c61f945644cf099d41ab8a0ab2ac5d2533835 + f32f5908b7f3c000 + e969cd49be4000 = b44lf9c96ibe8g99296hcl5kd40f3b6bg6df after convert it to integer and remove last 12 digits from that number – Aeroxer Support Sep 17 '22 at 07:17
  • Related question: [Convert Hex to Decimal when no datatype can hold the full number](https://stackoverflow.com/questions/1143302). – Steve Summit Sep 21 '22 at 18:58

2 Answers2

1

The reason this sort of thing works so easily in Python is that, unusually, Python supports arbitrary-precision integers natively.

Most languages, including C, use fixed sizes for their native types. To perform arbitrary-precision arithmetic, you generally need a separate library, such as GMP.

Here is a basic example of using GMP to solve your problem:

#include <stdio.h>
#include <gmp.h>

char *inputs[] = {
    "000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835",
    "000000000000000000000000000000000000000000000000f32f5908b7f3c000",
    "00000000000000000000000000000000000000000000000000e969cd49be4000"
};

int main()
{
    char outstr[100];
    mpz_t x; mpz_init(x);
    mpz_t y; mpz_init(y);
    mpz_t sum; mpz_init(sum);
    mpz_t ten; mpz_init_set_si(ten, 10);
    mpz_t fac; mpz_init(fac);
    mpz_pow_ui(fac, ten, 12);        /* fac = 10**12 */

    int i;
    for(i = 0; i < 3; i++) {
        mpz_set_str(x, inputs[i], 16);
        mpz_tdiv_q(y, x, fac);
        mpz_add(sum, sum, y);        /* sum += x / fac */
    }

    printf("%s\n", mpz_get_str(outstr, 10, sum));
}

The code is a bit verbose, because arbitrary-precision integers (that is, variables of type mpz_t) have nontrivial memory allocation requirements, and everything you do with them requires explicit function calls. (Working with extended types like this would be considerably more convenient in a language with good support for object-oriented programming, like C++.)

To compile this, you'll need to have GMP installed. On my machine, I used

cc testprog.c -lgmp

When run, this program prints

1080702647035076263416932216315997551

Or, if I changed 10 to 16 in the last line, it would print d022c1183a2720991b1fea332a6d6f.

It will make a slight difference whether you divide by 1012 and then sum, or sum and then divide. To sum and then divide, you could get rid of the line mpz_tdiv_q(y, x, fac) inside the loop, change mpz_add(sum, sum, y) to mpz_add(sum, sum, x), and add the line

mpz_tdiv_q(sum, sum, fac);

outside the loop, just before printing.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
1

It's fairly straight forward to add up the (in this case hex) digits of two strings.

This doesn't try to be "optimal", but it does give a sum (as a string of hex digits). vals[0] acts as the accumulator.

When OP clarifies what is meant by "I need sum (3 hex string) and remove last 12 numbers", this answer could be extended.

If more speed is needed, the accumulator could be allocated and used as an array of uint8_t's (saving converting back to ASCII hex until a final total is available.) Also the LUT to convert ASCII hex to '0-F' could be 'binary' (not requiring the subtraction of ASCII character values.)

Anyway...

#include <stdio.h>

char *vals[] = {
    "000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835",
    "000000000000000000000000000000000000000000000000f32f5908b7f3c000",
    "00000000000000000000000000000000000000000000000000e969cd49be4000",
};

char *frmHex =
    "................................................0000000000......"
    ".777777..........................WWWWWW.........................";

char *tohex = "0123456789ABCDEF";

void addTo( char *p0, char *p1 ) {
    printf( "  %s\n+ %s\n", p0, p1 );

    char *px = p0 + strlen( p0 ) - 1;
    char *py = p1 + strlen( p1 ) - 1;

    for( int carry = 0; px >= p0 && py >= p1; px--, py-- ) {
        int val = *px - frmHex[ *px ] + *py - frmHex[ *py ] + carry;

        carry = val / 0x10; *px = tohex[ val % 0x10 ];
    }
    printf( "= %s\n\n", p0 );
}

int main() {
    addTo( vals[ 0 ], vals[ 1 ] );
    addTo( vals[ 0 ], vals[ 2 ] );

    return 0;
}

Output

  000000000000000000000000bd4c61f945644cf099d41ab8a0ab2ac5d2533835
+ 000000000000000000000000000000000000000000000000f32f5908b7f3c000
= 000000000000000000000000BD4C61F945644CF099D41AB993DA83CE8A46F835

  000000000000000000000000BD4C61F945644CF099D41AB993DA83CE8A46F835
+ 00000000000000000000000000000000000000000000000000e969cd49be4000
= 000000000000000000000000BD4C61F945644CF099D41AB994C3ED9BD4053835

If this were to progress (and use binary accumulators), 'compaction' after summing would quickly lead into integer division (that could be done simply with shifting and repeated subtraction.) Anyway...

Fe2O3
  • 6,077
  • 2
  • 4
  • 20