256-bit integer to string [duplicate] - c

I'm trying to convert a 128-bit unsigned integer stored as an array of 4 unsigned ints to the decimal string representation in C:
unsigned int src[] = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
printf("%s", some_func(src)); // gives "53072739890371098123344"
(The input and output examples above are completely fictional; I have no idea what that input would produce.)
If I was going to hex, binary or octal, this would be a simple matter of masks and bit shifts to peel of the least significant characters. However, it seems to me that I need to do base-10 division. Unfortunately, I can't remember how to do that across multiple ints, and the system I'm using doesn't support data types larger than 32-bits, so using a 128-bit type is not possible. Using a different language is also out, and I'd rather avoid a big number library just for this one operation.

Division is not necessary:
#include <string.h>
#include <stdio.h>
typedef unsigned long uint32;
/* N[0] - contains least significant bits, N[3] - most significant */
char* Bin128ToDec(const uint32 N[4])
{
// log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322
static char s[128 / 3 + 1 + 1];
uint32 n[4];
char* p = s;
int i;
memset(s, '0', sizeof(s) - 1);
s[sizeof(s) - 1] = '\0';
memcpy(n, N, sizeof(n));
for (i = 0; i < 128; i++)
{
int j, carry;
carry = (n[3] >= 0x80000000);
// Shift n[] left, doubling it
n[3] = ((n[3] << 1) & 0xFFFFFFFF) + (n[2] >= 0x80000000);
n[2] = ((n[2] << 1) & 0xFFFFFFFF) + (n[1] >= 0x80000000);
n[1] = ((n[1] << 1) & 0xFFFFFFFF) + (n[0] >= 0x80000000);
n[0] = ((n[0] << 1) & 0xFFFFFFFF);
// Add s[] to itself in decimal, doubling it
for (j = sizeof(s) - 2; j >= 0; j--)
{
s[j] += s[j] - '0' + carry;
carry = (s[j] > '9');
if (carry)
{
s[j] -= 10;
}
}
}
while ((p[0] == '0') && (p < &s[sizeof(s) - 2]))
{
p++;
}
return p;
}
int main(void)
{
static const uint32 testData[][4] =
{
{ 0, 0, 0, 0 },
{ 1048576, 0, 0, 0 },
{ 0xFFFFFFFF, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 }
};
printf("%s\n", Bin128ToDec(testData[0]));
printf("%s\n", Bin128ToDec(testData[1]));
printf("%s\n", Bin128ToDec(testData[2]));
printf("%s\n", Bin128ToDec(testData[3]));
printf("%s\n", Bin128ToDec(testData[4]));
return 0;
}
Output:
0
1048576
4294967295
4294967296
11248221411398543556294285637029484152

Straightforward division base 2^32, prints decimal digits in reverse order, uses 64-bit arithmetic, complexity O(n) where n is the number of decimal digits in the representation:
#include <stdio.h>
unsigned int a [] = { 0x12345678, 0x12345678, 0x12345678, 0x12345678 };
/* 24197857161011715162171839636988778104 */
int
main ()
{
unsigned long long d, r;
do
{
r = a [0];
d = r / 10;
r = ((r - d * 10) << 32) + a [1];
a [0] = d;
d = r / 10;
r = ((r - d * 10) << 32) + a [2];
a [1] = d;
d = r / 10;
r = ((r - d * 10) << 32) + a [3];
a [2] = d;
d = r / 10;
r = r - d * 10;
a [3] = d;
printf ("%d\n", (unsigned int) r);
}
while (a[0] || a[1] || a[2] || a[3]);
return 0;
}
EDIT: Corrected the loop so it displays a 0 if the array a contains only zeros.
Also, the array is read left to right, a[0] is most-significant, a[3] is least significant digits.

A slow but simple approach is to just printing digits from most significant to least significant using subtraction. Basically you need a function for checking if x >= y and another for computing x -= y when that is the case.
Then you can start counting how many times you can subtract 10^38 (and this will be most significant digit), then how many times you can subtract 10^37 ... down to how many times you can subtract 1.
The following is a full implementation of this approach:
#include <stdio.h>
typedef unsigned ui128[4];
int ge128(ui128 a, ui128 b)
{
int i = 3;
while (i >= 0 && a[i] == b[i])
--i;
return i < 0 ? 1 : a[i] >= b[i];
}
void sub128(ui128 a, ui128 b)
{
int i = 0;
int borrow = 0;
while (i < 4)
{
int next_borrow = (borrow && a[i] <= b[i]) || (!borrow && a[i] < b[i]);
a[i] -= b[i] + borrow;
borrow = next_borrow;
i += 1;
}
}
ui128 deci128[] = {{1u,0u,0u,0u},
{10u,0u,0u,0u},
{100u,0u,0u,0u},
{1000u,0u,0u,0u},
{10000u,0u,0u,0u},
{100000u,0u,0u,0u},
{1000000u,0u,0u,0u},
{10000000u,0u,0u,0u},
{100000000u,0u,0u,0u},
{1000000000u,0u,0u,0u},
{1410065408u,2u,0u,0u},
{1215752192u,23u,0u,0u},
{3567587328u,232u,0u,0u},
{1316134912u,2328u,0u,0u},
{276447232u,23283u,0u,0u},
{2764472320u,232830u,0u,0u},
{1874919424u,2328306u,0u,0u},
{1569325056u,23283064u,0u,0u},
{2808348672u,232830643u,0u,0u},
{2313682944u,2328306436u,0u,0u},
{1661992960u,1808227885u,5u,0u},
{3735027712u,902409669u,54u,0u},
{2990538752u,434162106u,542u,0u},
{4135583744u,46653770u,5421u,0u},
{2701131776u,466537709u,54210u,0u},
{1241513984u,370409800u,542101u,0u},
{3825205248u,3704098002u,5421010u,0u},
{3892314112u,2681241660u,54210108u,0u},
{268435456u,1042612833u,542101086u,0u},
{2684354560u,1836193738u,1126043566u,1u},
{1073741824u,1182068202u,2670501072u,12u},
{2147483648u,3230747430u,935206946u,126u},
{0u,2242703233u,762134875u,1262u},
{0u,952195850u,3326381459u,12621u},
{0u,932023908u,3199043520u,126217u},
{0u,730304488u,1925664130u,1262177u},
{0u,3008077584u,2076772117u,12621774u},
{0u,16004768u,3587851993u,126217744u},
{0u,160047680u,1518781562u,1262177448u}};
void print128(ui128 x)
{
int i = 38;
int z = 0;
while (i >= 0)
{
int c = 0;
while (ge128(x, deci128[i]))
{
c++; sub128(x, deci128[i]);
}
if (i==0 || z || c > 0)
{
z = 1; putchar('0' + c);
}
--i;
}
}
int main(int argc, const char *argv[])
{
ui128 test = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
print128(test);
return 0;
}
That number in the problem text in decimal becomes
11248221411398543556294285637029484152
and Python agrees this is the correct value (this of course doesn't mean the code is correct!!! ;-) )

Same thing, but with 32-bit integer arithmetic:
#include <stdio.h>
unsigned short a [] = {
0x0876, 0x5421,
0xfedc, 0xba90,
0x90ab, 0xcdef,
0x1234, 0x5678
};
int
main ()
{
unsigned int d, r;
do
{
r = a [0];
d = r / 10;
r = ((r - d * 10) << 16) + a [1];
a [0] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [2];
a [1] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [3];
a [2] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [4];
a [3] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [5];
a [4] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [6];
a [5] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [7];
a [6] = d;
d = r / 10;
r = r - d * 10;
a [7] = d;
printf ("%d\n", r);
}
while (a[0] || a[1] || a[2] || a[3] || a [4] || a [5] || a[6] || a[7]);
return 0;
}

You actually don't need to implement long division. You need to implement multiplication by a power of two, and addition. You have four uint_32. First convert each of them to a string. Multiply them by (2^32)^3, (2^32)^2, (2^32)^1, and (2^32)^0 respectively, then add them together. You don't need to do the base conversion, you just need to handle putting the four pieces together. You'll obviously need to make sure the strings can handle a number up to UINT_32_MAX*(2^32)^3.

Supposing you have a fast 32-bit multiplication and division the result can be computed 4 digits at a time by implementing a bigint division/modulo 10000 and then using (s)printf for output of digit groups.
This approach is also trivial to extend to higher (or even variable) precision...
#include <stdio.h>
typedef unsigned long bigint[4];
void print_bigint(bigint src)
{
unsigned long int x[8]; // expanded version (16 bit per element)
int result[12]; // 4 digits per element
int done = 0; // did we finish?
int i = 0; // digit group counter
/* expand to 16-bit per element */
x[0] = src[0] & 65535;
x[1] = src[0] >> 16;
x[2] = src[1] & 65535;
x[3] = src[1] >> 16;
x[4] = src[2] & 65535;
x[5] = src[2] >> 16;
x[6] = src[3] & 65535;
x[7] = src[3] >> 16;
while (!done)
{
done = 1;
{
unsigned long carry = 0;
int j;
for (j=7; j>=0; j--)
{
unsigned long d = (carry << 16) + x[j];
x[j] = d / 10000;
carry = d - x[j] * 10000;
if (x[j]) done = 0;
}
result[i++] = carry;
}
}
printf ("%i", result[--i]);
while (i > 0)
{
printf("%04i", result[--i]);
}
}
int main(int argc, const char *argv[])
{
bigint tests[] = { { 0, 0, 0, 0 },
{ 0xFFFFFFFFUL, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0x12345678UL, 0x90abcdefUL, 0xfedcba90UL, 0x8765421UL } };
{
int i;
for (i=0; i<4; i++)
{
print_bigint(tests[i]);
printf("\n");
}
}
return 0;
}

#Alexey Frunze's method is easy but it's very slow. You should use #chill's 32-bit integer method above. Another easy method without any multiplication or division is double dabble. This may work slower than chill's algorithm but much faster than Alexey's one. After running you'll have a packed BCD of the decimal number

On github is an open source project (c++) which provides a class for a datatype uint265_t and uint128_t.
https://github.com/calccrypto/uint256_t
No, I' not affiliated with that project, but I was using it for such a purpose, but I guess it could be usefull for others as well.

Related

How to interlace two integers in C?

Let say I have two ints
a = 1234
b = 45678
Now I want to "interlace" them into a third int c that looks something like this
c = 415263748 assume the the length of these don't change. So far I've been able to do this:
unsigned interlace(unsigned x, unsigned y) {
unsigned pow = 10;
while(y >= pow)
pow *= 10;
return x * pow + y;
}
You have to get digits one by one. When you say x % 10 you get the least significant digit. When you say x = x /10 you remove the least significant digit. Start doing it for y then keep alternating:
unsigned interlace(unsigned x, unsigned y)
{
//If the parameters order could be inverted...
if(x > y)
{
unsigned z = x;
x = y;
y = z;
}
unsigned ans = y % 10;
y = y/10;
unsigned exponent = 10;
while(y)
{
ans += (x%10)*exponent;
x = x/10;
exponent *= 10;
ans += (y%10)*exponent;
y = y/10;
exponent *= 10;
}
return ans;
}
A slight twist on approach can eliminate the order of parameter issue by handling the interlacing on string representations of the values. This allows a simple way to sew the two numbers together. While strlen() is used here, you can also use snprintf (NULL, 0, "%u", a) and snprintf (NULL, 0, "%u", b) to determine the number of digits in each.
A simple approach interlacing the string representations would be:
#define NUMC 32
unsigned interlace (unsigned a, unsigned b)
{
char sa[NUMC], sb[NUMC], result[2*NUMC];
size_t lena, lenb, n = 0;
sprintf (sa, "%u", a);
sprintf (sb, "%u", b);
lena = strlen(sa);
lenb = strlen(sb);
if (lena > lenb) {
for (size_t i = 0, j = 0; sa[i]; i++) {
result[n++] = sa[i];
if (sb[j])
result[n++] = sb[j++];
}
result[n] = 0;
return (unsigned)strtoul (result, NULL, 0);
}
for (size_t i = 0, j = 0; sb[i]; i++) {
result[n++] = sb[i];
if (sa[j])
result[n++] = sa[j++];
}
result[n] = 0;
return (unsigned)strtoul (result, NULL, 0);
}
(note: the validations on conversion and length checks greater than zero should be added above. They were intentionally omitted for brevity)
The order of parameters is irrelevant. You can call it as interlace (a, b) or interlace (b, a) and the result will be correct each time.
A short example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMC 32
unsigned interlace (unsigned a, unsigned b)
{
char sa[NUMC], sb[NUMC], result[2*NUMC];
size_t lena, lenb, n = 0;
sprintf (sa, "%u", a);
sprintf (sb, "%u", b);
lena = strlen(sa);
lenb = strlen(sb);
if (lena > lenb) {
for (size_t i = 0, j = 0; sa[i]; i++) {
result[n++] = sa[i];
if (sb[j])
result[n++] = sb[j++];
}
result[n] = 0;
return (unsigned)strtoul (result, NULL, 0);
}
for (size_t i = 0, j = 0; sb[i]; i++) {
result[n++] = sb[i];
if (sa[j])
result[n++] = sa[j++];
}
result[n] = 0;
return (unsigned)strtoul (result, NULL, 0);
}
int main (void) {
unsigned a = 1234, b = 45678;
printf ("interlaced: %u\n", interlace (a, b));
}
Example Use/Output
$ ./bin/interlace_int
interlaced: 415263748
Another completely different approach, more inline with your original can make use of the div function and the div_t struct to automate handling the division and remainder. You can use the snprintf (NULL, 0, "%u", var); function to determine the number of digits so you can swap parameters if necessary.
A short example is:
#include <stdio.h>
#include <stdlib.h>
unsigned interlace (unsigned a, unsigned b)
{
unsigned result = 0, mult = 1;
div_t da = { .quot = a }, db = { .quot = b };
if (snprintf (NULL, 0, "%u", b) > snprintf (NULL, 0, "%u", a)) {
div_t tmp = da;
da = db;
db = tmp;
}
do {
da = div (da.quot, 10);
result += da.rem * mult;
mult *= 10;
if (db.quot) {
db = div (db.quot, 10);
result += db.rem * mult;
mult *= 10;
}
} while (da.quot);
return result;
}
int main (void) {
unsigned a = 1234, b = 45678;
printf ("interlaced: %u\n", interlace (a, b));
}
(note: here again, the order of parameters is irrelevant and you can provide a and b in any order and still arrive at the correct result)
Example Use/Output
$ ./bin/interlace_unsinged
interlaced: 415263748
Let me know if you have further questions. Just another way to skin the interlace cat.
This is not exactly what you asked for but maybe you can reuse some of this logic on your function....
OUTPUT:
Interlace 2 numbers as a printf
Enter number a: forty-three
Insert digit : 1234
Enter number b: 45678
Interlaced numbers: 142536478
CODE:
#include <stdio.h>
int main(void){
long int num , num2, temp , factor = 1, factor2 = 1;
puts("Interlace 2 numbers as a printf");
printf("Enter number a: ");
while(!scanf(" %ld",&num)){
while ((temp = getchar()) != '\n' && temp != EOF);
printf("Insert digit : ");
}
printf("Enter number b: ");
while(!scanf(" %ld",&num2)){
while ((temp = getchar()) != '\n' && temp != EOF);
printf("Insert digit : ");
}
temp = num;
while(temp){
temp /= 10;
factor *= 10;
}
temp = num2;
while(temp){
temp /= 10;
factor2 *= 10;
}
printf("Interlaced numbers: ");
while(factor>1)
{
factor /= 10;
printf("%ld",num/factor);
num %= factor;
if (factor2 > 1)
{
factor2 /= 10;
printf("%ld",num2/factor2);
num2 %= factor2;
}
}
while(factor2>1)
{
factor2 /= 10;
printf("%ld",num2/factor2);
num2 %= factor2;
}
putchar('\n');
return 0;
}
#include <stdio.h>
#include <math.h>
int main(void) {
int a = 1234;
int b = 45678;
int c = 0;
while(a || b)
{
if (b)
{
int m = pow(10, (int)log10(b));
c=c*10 + b/m;
b = b%m;
}
if (a)
{
int m = pow(10, (int)log10(a));
c=c*10+a/m;
a = a%m;
}
}
printf("Result: %d\n", c);
return 0;
}
Output:
Success #stdin #stdout 0s 4692KB
Result: 415263748
IDEOne Link
Appending the last digit of the two numbers alternatively to n * 10(repeated operation), gives you the reverse of the interlace.
Just to help if you are stuck in generating reversed interlace.
unsigned interlace (unsigned x, unsigned y)
{
unsigned n, r;
if( x > y)
{
temp = x;
x = y;
y = temp;
}
n = y % 10;
y = y / 10;
while (x || y) // To Generate reverse of the interlace
{
n = n * 10 + (x % 10);
x /= 10;
n = n * 10 + (y % 10);
y /= 10;
}
r = n % 10;
n = n / 10;
while(n != 0) // reverse it to get the interlaced number
{
r = r * 10 + (n % 10);
n /= 10;
}
return r;
}

Radix Sort Float

I am trying to sort floats with radix. My current algorithm works with unsigned. For example, if I enter values 12, 100, 1 my sorted values are 1, 12, and 100. However, when I use a function to convert floats to ints back to floats after calling the radix sort, my values remain unsorted. They print as they were entered by the user.
I am unsure how to modify my current function to be able to sort floats with radix.
void rs(unsigned int *a, int c) {
int i;
int m = a[0];
int bt = 0;
unsigned int *b = malloc(0 * sizeof(int));
for (i = 0; i < c; i++) {
if (a[i] > m)
m = a[i];
}
while((m>>bt) > 0){
int buck[2] = { 0 };
for (i = 0; i < c; i++) {
buck[(a[i]>>bt)&1]++;
}
for (i = 1; i < 2; i++) {
buck[i] += buck[i-1];
}
for (i = c-1; i >= 0; i--) {
b[--buck[(a[i]>>bt)&1]] = a[i];
}
for (i = 0; i < c; i++) {
a[i] = b[i];
}
bt++;
}
free(b);
}
The function I am using to transform floats to ints to floats is: Radix Sort for Floats
void rfloat(float* arr, size_t size) {
assert(sizeof(unsigned) == sizeof(float) && sizeof(float) == 4);
unsigned* d = malloc(size * sizeof(unsigned));
for (size_t i = 0; i < size; i++) {
// Interpret float as 32-bit unsigned.
d[i] = *(unsigned*) &(arr[i]);
// Flip all except top if top bit is set.
d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);
// Flip top bit.
d[i] ^= (1u << 31);
}
rs(d, size);
// Inverse transform.
for (size_t i = 0; i < size; i++) {
d[i] ^= (1u << 31);
d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);
arr[i] = *(float*) &(d[i]);
}
free(d);
}
There's multiple issues.
You use int all over the place where you should be using unsigned (for values) or size_t (for sizes/indices).
You allocate 0 bytes.
(m >> bt) > 0 doesn't work as a stop condition, shifting bits equal or greater than the width is not specified.
After transforming the data types to unsigned the loop boundaries don't work anymore.
I took the liberty of fixing the above and choosing some better variable names:
#include <limits.h>
void rs(unsigned int *a, size_t c) {
size_t i;
unsigned bit = 0;
unsigned *b = malloc(c * sizeof(unsigned));
unsigned m = a[0]; // Max element.
for (i = 0; i < c; i++) {
if (a[i] > m) m = a[i];
}
while (bit < CHAR_BIT*sizeof(m) && (m >> bit)) {
size_t bucket_len[2] = { 0, 0 };
for (i = 0; i < c; i++) bucket_len[(a[i] >> bit) & 1]++;
size_t bucket_end[2] = {bucket_len[0], bucket_len[0] + bucket_len[1]};
for (i = c; i-- > 0; ) {
size_t j = --bucket_end[(a[i] >> bit) & 1];
b[j] = a[i];
}
for (i = 0; i < c; i++) a[i] = b[i];
bit++;
}
free(b);
}

Peculiar problem regarding convolution in PPM format

After debugging, trying different image softwares (xdg, gimp) I persist to have a bug which throws me off completely.
Problem is about convolution in PPM format, for images different in aspect ratio, I'm using 1500x1000px image, where mask of {0,0,0, 0,1,0, 0,0,0} works just fine (it's just copying image), however for mask where first or last row is different than 0 eg. {0,1,0, 0,0,0, 0,0,0} image is moved by 1/3 of its size rightwards. I find it peculiar, because as far as I know, I do not have an overflow or any pointer arithmetic that might cause this problem.
I've narrowed it down to the kernel of convolution. Afaik I do not have any problems saving, reading image, after running i_convolution it just moves image by predefined value?.
void i_convolution(unsigned int **in, unsigned int ***out,
int y_max, int x_max, int kernel_size)
{
int kernel_sum = 0;
for(int i = 0; i < kernel_size; i++)
{
for(int j = 0; j < kernel_size; j++)
{
kernel_sum += kernel[i * kernel_size + j];
}
}
printf("kernel sum = %d\n", kernel_sum);
for (int i = 1; i < y_max - 1; i++)
{
for (int j = 1; j < x_max - 1; j++)
{
int r = 0;
int g = 0;
int b = 0;
for (int y_conv = -1; y_conv <= 1; y_conv++)
{
for (int x_conv = -1; x_conv <= 1; x_conv++)
{
int y_index = i + y_conv;
int x_index = j + x_conv;
unsigned char rval = (unsigned char)(in[y_index][x_index] & 0xff);
unsigned char gval = (unsigned char)((in[y_index][x_index] & 0xff00) >> 8);
unsigned char bval = (unsigned char)((in[y_index][x_index] & 0xff0000) >> 16);
int kernel_val = kernel[(y_conv + 1)*kernel_size + (x_conv + 1)];
r += (int)(rval * kernel_val);
g += (int)(gval * kernel_val);
b += (int)(bval * kernel_val);
}
}
r /= kernel_sum;//median filtration
g /= kernel_sum;//median filtration
b /= kernel_sum;//median filtration
// b = abs(b);
if (r > 255) r = 255;
else if(r < 0) r = 0;
if (g > 255) g = 255;
else if(g < 0) g = 0;
if (b > 255) b = 255;
else if(b < 0) b = 0;
unsigned int val;
val = 0;
val |= b & 0xff;
val <<= 8;
val |= g & 0xff;
val <<= 8;
val |= r & 0xff;
(*out)[i][j] = val;
}
}
}
let's take kernel {0, 1, 0, 0, 0, 0,
result are like this, with left being original, right after convolution
https://i.imgur.com/rzXKjUY.png
I will be thankful for any help.
Best regards.
I mark it as solved, because there was a problem with me misinterpreting PPM format height and width, which caused this behaviour, swapping y with x (and allocating memory as such) solves it!

Runtime error on a Codechef problem: modified Fibonacci series. What's the mistake?

I'm trying to solve a problem on codechef, here's the link:
https://www.codechef.com/problems/KFIB
The given problem statement is:
Chef recently had been studying about Fibonacci numbers and wrote a code to print out the k-th term of the Fibonacci series (1, 1, 2, 3, 5, 8, 13….). He was wondering whether he could write a program to generate the k-th term for similar series. More specifically:
T(n, k) is 1 if n <= k and
T(n, k) = T(n-1, k) + T(n-2, k) + T(n-3, k) … + T(n-k, k) if n > k.
Given n and k, output T(n, k) % (1000000007) as the answer could be very large
Input : Two integers, N and K
Output : One integer, the nth term of the series mod 1000000007
Constraints : 1 ≤ N, K ≤ 2*105
example:
Input: 7 5
Output: 9
The series is as follows {1, 1, 1, 1, 1, 5, 9}
void fibo(int n, unsigned long k) {
unsigned long *a, c;
a = (unsigned long *)malloc(sizeof(unsigned long) * k);
for (unsigned long i = 0; i < k; i++) { //T(n,k)=1 when n<=k
*(a + i)=1;
}
for (unsigned long m = 0; m < n - 1; m++) {
c = *(a);
for (unsigned long j = 0; j < k - 1; j++) {
*(a + j) = *(a + j + 1);
c = c + *(a + j);
}
*(a + k - 1) = c;
}
printf("%d ", *(a) % 1000000007);
}
This works with smaller values but not with very large values. I got the result of the example but when I enter the values 200000 500, I get incorrect answers
The problem is you compute the value modulo ULONG_MAX and reduce the result modulo 1000000007 at the end. This does not give the correct result. You must reduce modulo 1000000007 at each step to avoid potential arithmetic overflow (which does not cause undefined behavior for type unsigned long but gives a different result from the expected one).
Here is a modified version of your code with a faster alternative (more than twice as fast on my laptop):
#include <stdio.h>
#include <stdlib.h>
#define DIVIDER 1000000007ul
unsigned long fibo(unsigned long n, unsigned long k) {
unsigned long c = 1;
if (n > k) {
unsigned long *a = (unsigned long *)malloc(sizeof(*a) * k);
for (unsigned long i = 0; i < k; i++) { //T(n,k)=1 when n<=k
a[i] = 1;
}
for (unsigned long m = k; m < n; m++) {
c = a[0];
for (unsigned long j = 0; j < k - 1; j++) {
a[j] = a[j + 1];
#if 0
// slower version using modulo
c = (c + a[j]) % DIVIDER;
#else
// faster version with a test
if ((c += a[j]) >= DIVIDER)
c -= DIVIDER;
#endif
}
a[k - 1] = c;
}
free(a);
}
return c;
}
int main(int argc, char *argv[]) {
if (argc <= 2) {
printf("usage: fibo n k");
return 1;
} else {
unsigned long n = strtoul(argv[1], NULL, 10);
unsigned long k = strtoul(argv[2], NULL, 10);
printf("%lu\n", fibo(n, k));
}
return 0;
}
Output:
$ time ./fibo 200000 100000
871925546
real 0m34.667s
user 0m34.288s
sys 0m0.113s
$ time ./fibo-faster 200000 100000
871925546
real 0m15.073s
user 0m14.846s
sys 0m0.064s
Given the restrictions on input values:
the values of T(n, k) are in the range [0..1000000006] which fits in an int32_t.
the sum of k terms is in the range [0..200000*1000000006] which fits in an int64_t.
hence we can compute the next term in 64 bits and use a single modulo on the result.
This gives an even faster version (more than 3 times faster):
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define DIVIDER 1000000007
uint32_t fibo(uint32_t n, uint32_t k) {
uint32_t c = 1;
if (n > k) {
uint32_t *a = (uint32_t *)malloc(sizeof(*a) * k);
uint64_t temp;
for (uint32_t i = 0; i < k; i++) { //T(n,k)=1 when n<=k
a[i] = 1;
}
for (uint32_t m = k; m < n; m++) {
temp = a[0];
for (uint32_t j = 0; j < k - 1; j++) {
temp += a[j] = a[j + 1];
}
a[k - 1] = c = temp % DIVIDER;
}
free(a);
}
return c;
}
int main(int argc, char *argv[]) {
if (argc <= 2) {
printf("usage: fibo n k");
return 1;
} else {
uint32_t n = strtoul(argv[1], NULL, 10);
uint32_t k = strtoul(argv[2], NULL, 10);
printf("%lu\n", (unsigned long)fibo(n, k));
}
return 0;
}
Output:
$ time ./fibo-faster 200000 100000
871925546
real 0m3.854s
user 0m3.800s
sys 0m0.018s
To avoid overflow, you can change below statement
c=c+*(a+j);
To
c=(c+*(a+j))%1000000007;
That means only the remainder will be keep in your heap. This won't impact the final results.
Here is the updated code and compiled by clang.(updated according to #bruno's comments)
#include <stdlib.h>
#include <stdio.h>
#define DIVIDER 1000000007ul
#define U4 unsigned long
U4 fibo(U4 n,U4 k)
{
U4 *a,c ;
if(n<=k) return 1;
a= (U4*) malloc (sizeof(U4)*k);
for (U4 i=0;i<k;i++) //T(n,k)=1 when n<=k
{
*(a+i)=1;
}
for (U4 m=k;m<n; m++)
{
c=*(a);
for (U4 j=0;j<k-1;j++)
{
*(a+j)= *(a+j+1);
c=(c+*(a+j))%DIVIDER;
}
*(a+k-1)=c;
}
free(a);
return c;
}
int main(int argc, char *argv[])
{
U4 n, k;
char *endptr;
if(argc <= 2){
printf("usage: t.exe n k");
return 0;
}
n = strtoul(argv[1], &endptr, 10);
k = strtoul(argv[2], &endptr, 10);
printf("%lu", fibo(n,k));
}
Compiler command:
$ clang test.c -o test.exe
$ test.exe 200000 500
80391289

How to convert a 128-bit integer to a decimal ascii string in C?

I'm trying to convert a 128-bit unsigned integer stored as an array of 4 unsigned ints to the decimal string representation in C:
unsigned int src[] = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
printf("%s", some_func(src)); // gives "53072739890371098123344"
(The input and output examples above are completely fictional; I have no idea what that input would produce.)
If I was going to hex, binary or octal, this would be a simple matter of masks and bit shifts to peel of the least significant characters. However, it seems to me that I need to do base-10 division. Unfortunately, I can't remember how to do that across multiple ints, and the system I'm using doesn't support data types larger than 32-bits, so using a 128-bit type is not possible. Using a different language is also out, and I'd rather avoid a big number library just for this one operation.
Division is not necessary:
#include <string.h>
#include <stdio.h>
typedef unsigned long uint32;
/* N[0] - contains least significant bits, N[3] - most significant */
char* Bin128ToDec(const uint32 N[4])
{
// log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322
static char s[128 / 3 + 1 + 1];
uint32 n[4];
char* p = s;
int i;
memset(s, '0', sizeof(s) - 1);
s[sizeof(s) - 1] = '\0';
memcpy(n, N, sizeof(n));
for (i = 0; i < 128; i++)
{
int j, carry;
carry = (n[3] >= 0x80000000);
// Shift n[] left, doubling it
n[3] = ((n[3] << 1) & 0xFFFFFFFF) + (n[2] >= 0x80000000);
n[2] = ((n[2] << 1) & 0xFFFFFFFF) + (n[1] >= 0x80000000);
n[1] = ((n[1] << 1) & 0xFFFFFFFF) + (n[0] >= 0x80000000);
n[0] = ((n[0] << 1) & 0xFFFFFFFF);
// Add s[] to itself in decimal, doubling it
for (j = sizeof(s) - 2; j >= 0; j--)
{
s[j] += s[j] - '0' + carry;
carry = (s[j] > '9');
if (carry)
{
s[j] -= 10;
}
}
}
while ((p[0] == '0') && (p < &s[sizeof(s) - 2]))
{
p++;
}
return p;
}
int main(void)
{
static const uint32 testData[][4] =
{
{ 0, 0, 0, 0 },
{ 1048576, 0, 0, 0 },
{ 0xFFFFFFFF, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 }
};
printf("%s\n", Bin128ToDec(testData[0]));
printf("%s\n", Bin128ToDec(testData[1]));
printf("%s\n", Bin128ToDec(testData[2]));
printf("%s\n", Bin128ToDec(testData[3]));
printf("%s\n", Bin128ToDec(testData[4]));
return 0;
}
Output:
0
1048576
4294967295
4294967296
11248221411398543556294285637029484152
Straightforward division base 2^32, prints decimal digits in reverse order, uses 64-bit arithmetic, complexity O(n) where n is the number of decimal digits in the representation:
#include <stdio.h>
unsigned int a [] = { 0x12345678, 0x12345678, 0x12345678, 0x12345678 };
/* 24197857161011715162171839636988778104 */
int
main ()
{
unsigned long long d, r;
do
{
r = a [0];
d = r / 10;
r = ((r - d * 10) << 32) + a [1];
a [0] = d;
d = r / 10;
r = ((r - d * 10) << 32) + a [2];
a [1] = d;
d = r / 10;
r = ((r - d * 10) << 32) + a [3];
a [2] = d;
d = r / 10;
r = r - d * 10;
a [3] = d;
printf ("%d\n", (unsigned int) r);
}
while (a[0] || a[1] || a[2] || a[3]);
return 0;
}
EDIT: Corrected the loop so it displays a 0 if the array a contains only zeros.
Also, the array is read left to right, a[0] is most-significant, a[3] is least significant digits.
A slow but simple approach is to just printing digits from most significant to least significant using subtraction. Basically you need a function for checking if x >= y and another for computing x -= y when that is the case.
Then you can start counting how many times you can subtract 10^38 (and this will be most significant digit), then how many times you can subtract 10^37 ... down to how many times you can subtract 1.
The following is a full implementation of this approach:
#include <stdio.h>
typedef unsigned ui128[4];
int ge128(ui128 a, ui128 b)
{
int i = 3;
while (i >= 0 && a[i] == b[i])
--i;
return i < 0 ? 1 : a[i] >= b[i];
}
void sub128(ui128 a, ui128 b)
{
int i = 0;
int borrow = 0;
while (i < 4)
{
int next_borrow = (borrow && a[i] <= b[i]) || (!borrow && a[i] < b[i]);
a[i] -= b[i] + borrow;
borrow = next_borrow;
i += 1;
}
}
ui128 deci128[] = {{1u,0u,0u,0u},
{10u,0u,0u,0u},
{100u,0u,0u,0u},
{1000u,0u,0u,0u},
{10000u,0u,0u,0u},
{100000u,0u,0u,0u},
{1000000u,0u,0u,0u},
{10000000u,0u,0u,0u},
{100000000u,0u,0u,0u},
{1000000000u,0u,0u,0u},
{1410065408u,2u,0u,0u},
{1215752192u,23u,0u,0u},
{3567587328u,232u,0u,0u},
{1316134912u,2328u,0u,0u},
{276447232u,23283u,0u,0u},
{2764472320u,232830u,0u,0u},
{1874919424u,2328306u,0u,0u},
{1569325056u,23283064u,0u,0u},
{2808348672u,232830643u,0u,0u},
{2313682944u,2328306436u,0u,0u},
{1661992960u,1808227885u,5u,0u},
{3735027712u,902409669u,54u,0u},
{2990538752u,434162106u,542u,0u},
{4135583744u,46653770u,5421u,0u},
{2701131776u,466537709u,54210u,0u},
{1241513984u,370409800u,542101u,0u},
{3825205248u,3704098002u,5421010u,0u},
{3892314112u,2681241660u,54210108u,0u},
{268435456u,1042612833u,542101086u,0u},
{2684354560u,1836193738u,1126043566u,1u},
{1073741824u,1182068202u,2670501072u,12u},
{2147483648u,3230747430u,935206946u,126u},
{0u,2242703233u,762134875u,1262u},
{0u,952195850u,3326381459u,12621u},
{0u,932023908u,3199043520u,126217u},
{0u,730304488u,1925664130u,1262177u},
{0u,3008077584u,2076772117u,12621774u},
{0u,16004768u,3587851993u,126217744u},
{0u,160047680u,1518781562u,1262177448u}};
void print128(ui128 x)
{
int i = 38;
int z = 0;
while (i >= 0)
{
int c = 0;
while (ge128(x, deci128[i]))
{
c++; sub128(x, deci128[i]);
}
if (i==0 || z || c > 0)
{
z = 1; putchar('0' + c);
}
--i;
}
}
int main(int argc, const char *argv[])
{
ui128 test = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
print128(test);
return 0;
}
That number in the problem text in decimal becomes
11248221411398543556294285637029484152
and Python agrees this is the correct value (this of course doesn't mean the code is correct!!! ;-) )
Same thing, but with 32-bit integer arithmetic:
#include <stdio.h>
unsigned short a [] = {
0x0876, 0x5421,
0xfedc, 0xba90,
0x90ab, 0xcdef,
0x1234, 0x5678
};
int
main ()
{
unsigned int d, r;
do
{
r = a [0];
d = r / 10;
r = ((r - d * 10) << 16) + a [1];
a [0] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [2];
a [1] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [3];
a [2] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [4];
a [3] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [5];
a [4] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [6];
a [5] = d;
d = r / 10;
r = ((r - d * 10) << 16) + a [7];
a [6] = d;
d = r / 10;
r = r - d * 10;
a [7] = d;
printf ("%d\n", r);
}
while (a[0] || a[1] || a[2] || a[3] || a [4] || a [5] || a[6] || a[7]);
return 0;
}
You actually don't need to implement long division. You need to implement multiplication by a power of two, and addition. You have four uint_32. First convert each of them to a string. Multiply them by (2^32)^3, (2^32)^2, (2^32)^1, and (2^32)^0 respectively, then add them together. You don't need to do the base conversion, you just need to handle putting the four pieces together. You'll obviously need to make sure the strings can handle a number up to UINT_32_MAX*(2^32)^3.
Supposing you have a fast 32-bit multiplication and division the result can be computed 4 digits at a time by implementing a bigint division/modulo 10000 and then using (s)printf for output of digit groups.
This approach is also trivial to extend to higher (or even variable) precision...
#include <stdio.h>
typedef unsigned long bigint[4];
void print_bigint(bigint src)
{
unsigned long int x[8]; // expanded version (16 bit per element)
int result[12]; // 4 digits per element
int done = 0; // did we finish?
int i = 0; // digit group counter
/* expand to 16-bit per element */
x[0] = src[0] & 65535;
x[1] = src[0] >> 16;
x[2] = src[1] & 65535;
x[3] = src[1] >> 16;
x[4] = src[2] & 65535;
x[5] = src[2] >> 16;
x[6] = src[3] & 65535;
x[7] = src[3] >> 16;
while (!done)
{
done = 1;
{
unsigned long carry = 0;
int j;
for (j=7; j>=0; j--)
{
unsigned long d = (carry << 16) + x[j];
x[j] = d / 10000;
carry = d - x[j] * 10000;
if (x[j]) done = 0;
}
result[i++] = carry;
}
}
printf ("%i", result[--i]);
while (i > 0)
{
printf("%04i", result[--i]);
}
}
int main(int argc, const char *argv[])
{
bigint tests[] = { { 0, 0, 0, 0 },
{ 0xFFFFFFFFUL, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0x12345678UL, 0x90abcdefUL, 0xfedcba90UL, 0x8765421UL } };
{
int i;
for (i=0; i<4; i++)
{
print_bigint(tests[i]);
printf("\n");
}
}
return 0;
}
#Alexey Frunze's method is easy but it's very slow. You should use #chill's 32-bit integer method above. Another easy method without any multiplication or division is double dabble. This may work slower than chill's algorithm but much faster than Alexey's one. After running you'll have a packed BCD of the decimal number
On github is an open source project (c++) which provides a class for a datatype uint265_t and uint128_t.
https://github.com/calccrypto/uint256_t
No, I' not affiliated with that project, but I was using it for such a purpose, but I guess it could be usefull for others as well.

Resources