issue convert double range number to binary - c

I have a problem to convert integer type's double rage number to binary as the below,
void intToBin(int digit) {
int b;
int k = 0;
char *bits;
int i;
bits= (char *) malloc(sizeof(char));
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
But as you can see the that function's arguments input is integer.
I came across the error when I tried with intToBin(10329216702565230)
because 10329216702565230 is over integer range.
How can I extend what that have integer type's double rage number to binary ?
update
I've updated the below code
void intToBin(uint64_t digit) {
int b;
int k = 0;
char *bits;
int i;
bits = malloc(sizeof digit * 64);
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
But I didn't get it what should I do to get the 2's complement ?
m
dmnngn

Solution is to use type which supports that range of numbers.
Use unsigned long long or uint64_t(assuming you are passing non negative integers, otherwise use long long or int64_t). Then you call the function like this Edited to add int64_t to uint64_t from the comment posted. unsigned long long is 64 bits atleast - can even be wider. With OP's comment of getting 64 bits output - better to use (u)int64_t
intToBin(10329216702565230U)
In case you want to use negative numbers use long long.Call it like this
intToBin(10329216702565230L).
You didn't allocate enough memory - you were accessing memory that you haven't allocated, resulting in Undefined behavior. You have allocated 1 char first and then you didn't allocate. You can solve this by reallocating - reallocate memory inside the loop (reallocate 1 char at a time inside loop). And then use it. Instead of calling realloc multiple times why don't you allocate memory for 64 chars and then use it to store the result. And in the end, the left over space can be freed with another realloc call.
You don't need to cast the return value of malloc (void* to char* conversion is done implicitly).
You didn't check the return value of malloc. malloc may return NULL and in that case you have to handle that separately. For example:-
#define NBITS 64
...
...
bits = malloc(NBITS);
if( bits == NULL ){
perror("malloc failed");
exit(EXIT_FAILURE);
}
Note: The 64 magic number is coming introduced with the thought that unsigned long long is 64 bits atleast. So while converting we will be using that in case the number of bits exceeds 64 we will reallocate. A better choice is to use what chux said - sizeof digit * CHAR_BIT.
Also
bits[k] = b+'0';
We are putting the ascii value and then you can print it like this
printf("%c", bits[i]);
You forgot to free the allocated memory. Without freeing it (free(bits)), you have memory leak.
Davic C. Rankins comment

void intToBin(int digit)
{
int b;
int k = 0;
char *bits;
int i;
bits= (char *) malloc(sizeof(char));
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
The answer is simple,
Replace int with int64_t to use 64 bits instead of 32.
Please try it and let us know

Replace int with int64_t to use 64 bits instead of 32.

Related

How to convert large HEX string to INT in C

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

How to allocate enough memory to convert an unsigned long long int into string

With a code where I have a struct:
struct fibo_entry { /* Definition of each table entry */
int n;
unsigned long long int lli; /* 64-bit integer */
char *str;
};
I have to solve a Fibonacci sequence where I have the following:
fibo_table = (struct fibo_entry *)malloc(sizeof(struct fibo_entry));
//fibo_table->str = (char *)malloc(1 + 8 * sizeof(char)); // !!??
for (i = 0; i <= n; i++) {
fibo_table[i].n = i;
if (i == 0) {
fibo_table[i].lli = 0;
//sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
//fibo_table[i].str = atoi(fibo_table[i].lli);
} else if (i == 1) {
fibo_table[i].lli = 1;
} else {
fibo_table[i].lli = fibo_table[i-1].lli + fibo_table[i-2].lli;
//log10(fibo_table[i].lli);
}
}
The process to calculate Fibonacci is done, the problem that I have comes when I have to calculate the memory that I need to allocate a long long int in the string.
I know that the numbers use 64 bits each and I tried with malloc and the concept that sprintf should work to convert one in another, but I can't find a solution. Every time that I try to run the program, just fail.
If you are writing a (positive) number, n, in decimal notation (as the %llu format specifier will), then the number of digits will be (the integral part of) log10(n) + 1.
So, in order to (pre-)determine the maximum buffer size required, you can use the log10 function on the compiler-defined constant, ULLONG_MAX (this is the maximum value that an unsigned long long int can have). Note that, when allocating the character buffer, you should add 1 to the number of digits, to allow for the nul-terminator in your string.
The following short program may be helpful:
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <limits.h>
int main()
{
size_t maxdigits = (size_t)(log10((double)(ULLONG_MAX)) + 1);
printf("Max. digits in unsigned long long = %zu!\n", maxdigits);
printf("Max. value for the type is: %llu\n", ULLONG_MAX);
return 0;
}
On most modern systems, unsigned long long int will be 64 bits, with a maximum value of 18446744073709551615 (20 digits); however, it is better to use the platform/compiler-specific ULLONG_MAX, rather than relying on any particular value being correct.
Further, rather than calculating this maxdigits value multiple times, you need only calculate a 'global' constant once, then re-use that as and when required.
size_t CountDigit(long long int num)
{
size_t count = 0;
if(num < 0)
{
count++;
}
while (num)
{
count++;
num \=10;
}
count++;\\thats for the '\0'
return (count);
}
then you can use count for malloc and after that you can use sprintf or do it yourself, to insert the right chars in it.
How to allocate enough memory to convert an unsigned long long int into string
With an n-bit unsigned integer, a buffer of log10(2^n - 1) + 1 + 1 is needed. +1 for "ceiling" and +1 for the null character.
To find this value at compiler time, could use:
#define LOG10_2_N 302
#define LOG10_2_D 1000
#define ULL_STR_SIZE1 (sizeof (unsigned long long)*CHAR_BIT * LOG10_2_N / LOG10_2_D + 2)
To find this at pre-processor time is a little trickier as we need to find the bit width via macros. This approach also takes space advantage if rare padding bits are used.
// Numbers of bits in a Mersenne Number
// https://mathworld.wolfram.com/MersenneNumber.html
// https://stackoverflow.com/a/4589384/2410359
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define ULLONG_BIT_WIDTH IMAX_BITS(ULLONG_MAX)
// 28/93 is a tight fraction for log10(2)
#define LOG10_2_N 28
#define LOG10_2_D 93
#define ULL_STR_SIZE2 (ULLONG_BIT_WIDTH * LOG10_2_N / LOG10_2_D + 1 + 1)
ULL_STR_SIZE2 is suitable for #if ULL_STR_SIZE2 ... processing.
fibo_table[i].str = malloc(ULL_STR_SIZE2);
if (fibo_table[i].str) {
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
Or at run-time, to "right size", call snprintf() first and find the size needed for per each integer via the return value of *printf().
int n = snprintf(NULL, 0, "%llu", fibo_table[i].lli);
fibo_table[i].str = malloc(n + 1);
if (fibo_table[i].str) {
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
Or slightly more efficient, form a worst case size temporary buffer, write to it and then duplicate the string.
char tmp[ULL_STR_SIZE2];
snprintf(tmp, sizeof tmp, "%llu", fibo_table[i].lli);
fibo_table[i].str = strdup(tmp);
Alternative: change pointer char *str to an array.
struct fibo_entry {
int n;
unsigned long long int lli;
//char *str;
char *str[ULL_STR_SIZE2];
};
and use
snprintf(fibo_table[i].str, sizeof fibo_table[i].str, "%llu", fibo_table[i].lli);
Best to not assume long long is 64-bit. It is at least 64-bit.
You can calculate how many digits you need to use doing something like number_digits = (int)log10((double)num) + 1; and then reserve enough space with fibo_table[i].str = malloc(number_digits * sizeof(char)); remember you need to do this every for iteration, after those two steps you can now use the sprintf as you were sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);, code would look something like this:
int number_digits;
for (i = 0; i <= n; i++) {
if (i == 0) {
....
} else if (i == 1) {
....
} else {
....
}
number_digits = (int)log10((double)i) + 1;
fibo_table[i].str = malloc(number_digits*sizeof(char));
sprintf(fibo_table[i].str, "%llu", fibo_table[i].lli);
}

Conversion of string constant to numeric value using C

I have written a C program which uses two different algorithms to convert a string constant representing a numeric value to its integer value. For some reasons, the first algorithm, atoi(), doesn't execute properly on large values, while the second algorithm, atoi_imp(), works fine. Is this an optimization issue or some other error? The problem is that the first function makes the program's process to terminate with an error.
#include <stdio.h>
#include <string.h>
unsigned long long int atoi(const char[]);
unsigned long long int atoi_imp(const char[]);
int main(void) {
printf("%llu\n", atoi("9417820179"));
printf("%llu\n", atoi_imp("9417820179"));
return 0;
}
unsigned long long int atoi(const char str[]) {
unsigned long long int i, j, power, num = 0;
for (i = strlen(str) - 1; i >= 0; --i) {
power = 1;
for (j = 0; j < strlen(str) - i - 1; ++j) {
power *= 10;
}
num += (str[i] - '0') * power;
}
return num;
}
unsigned long long int atoi_imp(const char str[]) {
unsigned long long int i, num = 0;
for (i = 0; str[i] >= '0' && str[i] <= '9'; ++i) {
num = num * 10 + (str[i] - '0');
}
return num;
}
atoi is part of C standard library, with signature int atoi(const char *);.
You are declaring that a function with that name exists, but give it different return type. Note that in C, function name is the only thing that matters, and the toolchain can only trust what you tell in the source code. If you lie to the compiler, like here, all bets are off.
You should select different name for your own implementation to avoid issues.
As researched by #pmg, C standard (link to C99.7.1.3) says, using names from C standard library for your own global symbols (functions or global variables) is explicitly Undefined Behavior. Beware of nasal demons!
Ok there is at least one problem with your function atoi.
You are looping down on an unsigned value and check if its bigger equal zero, which should be an underflow.
The most easy fix is index shifting i.e.:
unsigned long long int my_atoi(const char str[]) {
unsigned long long int i, j, power, num = 0;
for (i = strlen(str); i != 0; --i) {
power = 1;
for (j = 0; j < strlen(str) - i; ++j) {
power *= 10;
}
num += (str[i-1] - '0') * power;
}
return num;
}
Too late, but may help. I did for base 10, in case you change the base you need to take care about how to compute the digit 0, in *p-'0'.
I would use the Horner's rule to compute the value.
#include <stdio.h>
void main(void)
{
char *a = "5363", *p = a;
int unsigned base = 10;
long unsigned x = 0;
while(*p) {
x*=base;
x+=(*p-'0');
p++;
}
printf("%lu\n", x);
}
Your function has an infinite loop: as i is unsigned, i >= 0 is always true.
It can be improved in different ways:
you should compute the length of str just once. strlen() is not cheap, it must scan the string until it finds the null terminator. The compiler is not always capable of optimizing away redundant calls for the same argument.
power could be computed incrementally, avoiding the need for a nested loop.
you should not use the name atoi as it is a standard function in the C library. Unless you implement its specification exactly and correctly, you should use a different name.
Here is a corrected and improved version:
unsigned long long int atoi_power(const char str[]) {
size_t i, len = strlen(str);
unsigned long long int power = 1, num = 0;
for (i = len; i-- > 0; ) {
num += (str[i] - '0') * power;
power *= 10;
}
return num;
}
Modified this way, the function should have a similar performance as the atoi_imp version. Note however that they do not implement the same semantics. atoi_pow must be given a string of digits, whereas atoi_imp can have trailing characters.
As a matter of fact neither atoi_imp nor atoi_pow implement the specification of atoi extended to handle larger unsigned integers:
atoi ignored any leading white space characters,
atoi accepts an optional sign, either '+' or '-'.
atoi consumes all following decimal digits, the behavior on overflow is undefined.
atoi ignores and trailing characters that are not decimal digits.
Given these semantics, the natural implementation or atoi is that of atoi_imp with extra tests. Note that even strtoull(), which you could use to implement your function handles white space and an optional sign, although the conversion of negative values may give surprising results.

Malloc() to create a new size for integers for use with math - Guidance needed

My goal is to create a integer type with a bigger size than 4 bytes, or 8 if I use long. I tried malloc to try and give more bytes in the memory for a bigger integer, but it still broke on the 31st iteration (gave a negative number). here's my code:
int main()
{
int x = 31; //(normally an int can do up to 30 without going negative so this is my test number)
int i;
int *bigNum = NULL;
bigNum = malloc((sizeof(int)*2));
*bigNum = 1;
for (i=0; i<x; i++) {
*bigNum = *bigNum * 2;
printf("%d \n", *bigNum);
}
free(bigNum);
}
Output:
2
4
...
..
...
1073741824
-2147483648
Although you have allocated more memory for your integer, no other part of the system knows this, including:
the compiler doesn't know this;
the CPU chip doesn't know this.
printf doesn't know this.
So all calculations are just carried out using the native int size.
Note that you can't tell the CPU chip you use larger integers; it is a physical/design limitation of the chip.
Dereferencing an int * gives you an int no matter how much extra memory you allocate for it.
If you want a dat type able to hold more information, try a long (although the guarantee is that it will be at least as big as an int).
If you want to handle integers beyond what your implementation provides, use a bignum library, like MPIR.
goal is to create a integer type with a bigger size
To handle multi-int integers, code also needs supporting functions for each basic operation:
int main(void) {
int x = 31;
RandBigNum *bigNum = RandBigNum_Init();
RandBigNum_Assign_int(bigNum, 1);
for (int i=0; i<x; i++) {
RandBigNum_Muliply_int(bigNum, 2);
RandBigNum_Print(bigNum);
printf(" \n");
}
Now, how might implement all this? Many approaches.
Below is a simply, incomplete and untested one. It is not necessarily a good approach, but to present an initial idea of the details needed to accomplish a big number library.
// Numbers are all positive. The first array element is the size of the number
typedef unsigned RandBigNum;
#define RandBigNum_MAXP1 (UINT_MAX + 1ull)
RandBigNum *RandBigNum_Init(void) {
return calloc(1, sizeof *RandBigNum);
}
void RandBigNum_Muliply_int(RandBigNum *x, unsigned scale) {
unsigned carry = 0;
for (unsigned i = 1; i <= x[0]; i++) {
unsigned long long product = 1ull * x[i] * scale + carry;
x[i] = product % RandBigNum_MAXP1;
carry *= product / RandBigNum_MAXP1;
}
if (carry) {
unsigned n = x[0] + 2;
x = realloc(x, sizeof *x * n); // re-alloc check omitted
x[x[0]] = carry;
x[0]++;
}
}
// many other functions

Strange problem about a function that gets the machine word

I wrote a function to get the machine word in C yesterday, but it seems that there is something wrong in it.
Here is the code:
unsigned machineword()
{
int i = 1;
unsigned temp;
while (temp > 0)
{
i++;
temp = (unsigned)(~0 >> i);
}
return i;
}
The simplest way to get the width of unsigned int is (sizeof(unsigned)*CHAR_BIT).
EDIT: as noted by pmg, you should be aware of the theoretical difference between the size an unsigned takes in memory and the number of bits available for computing with. Your original code tries to compute the latter, and so does the program below. The above trick computes the space occupied in memory.
It is not very convenient to compute this number with >> as it is forbidden in C to use >> with a number equal to or larger than the size in bits of the type you are shifting. You can work around this, if you know that long long is strictly larger than int, by computing with unsigned long long:
unsigned machineword()
{
int i = 1;
unsigned temp=1;
while (temp > 0)
{
i++;
temp = (unsigned)(((unsigned long long)~(0U)) >> i);
}
return i;
}
The simplest way to avoid the UB when shifting for too large value while keeping your structure is:
unsigned machineword()
{
unsigned i = 0;
unsigned temp = ~0U;
while (temp > 0)
{
i++;
temp >>= 1;
}
return i;
}
To calculate the number of bits, you can use CHAR_BIT or UINT_MAX.
The CHAR_BIT approach gives you the number of bits each value occupies in memory.
The UINT_MAX approach gives you the effective available bits.
Usually both values will be the same
#include <limits.h>
#include <stdio.h>
int main(void) {
unsigned tmp = UINT_MAX;
int i = 0;
while (tmp) {
i++;
tmp /= 2;
}
printf("value bits in a unsigned: %d\n", i);
printf("memory bits in a unsigned: %d\n", CHAR_BIT * (int)sizeof (unsigned));
return 0;
}

Resources