This is the code for Quick Sort. The array generated is random, using random() function, with 10,000 as upper limit.
When number of elements exceeded 109, e.g. 110, the program did not complete execution and got stuck.
This is the code:
/*
Program to sort a list of numbers using Quick sort algorithm.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// For runtime calculation
#define BILLION 1000000000
// For random number upper limit
#define UPPER_LIMIT 10000
// For printing array
#define PRINT_ARR printf("Parse %d: ", parseCount); for (int p = 0; p < eltCount; p++) printf("%d ", *(ptrMainArr + p)); printf("\n"); parseCount++;
// Declare global parse counter
int parseCount = 0;
// Declare global pointer to array
int *ptrMainArr;
// Number of elements in array
int eltCount;
float calcRunTime(struct timespec start, struct timespec end) {
long double runTime;
if (end.tv_nsec - start.tv_nsec >= 0) {
runTime = (end.tv_sec - start.tv_sec) + ((float)(end.tv_nsec - start.tv_nsec) / BILLION);
}
else {
runTime = (end.tv_sec - start.tv_sec - 1 + ((float)(end.tv_nsec - start.tv_nsec) / BILLION));
}
return runTime;
}
void swap(int *ptr1, int *ptr2) {
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
void quicksort(int *ptrArr, int numOfElts) {
// Single element in sub-array
if (numOfElts == 1) {
return;
}
// No elements in sub-array
if (numOfElts == 0) {
return;
}
// Print elements in array
PRINT_ARR
// Select pivot element (element in middle)
int pivotIdx;
// Even number of elements in array
if ((numOfElts) % 2 == 0) {
pivotIdx = ((numOfElts) / 2) - 1;
}
// Odd number of elements in array
else {
pivotIdx = (int)((numOfElts) / 2);
}
int pivot = *(ptrArr + pivotIdx);
// Initialise left and right bounds
int lb = 0, rb = numOfElts - 2;
// Swap pivot element with last element
swap(ptrArr + pivotIdx, ptrArr + numOfElts - 1);
while (1) {
while (*(ptrArr + lb) < pivot) {
lb++;
}
while (*(ptrArr + rb) > pivot && lb <= rb) {
rb--;
}
if (lb > rb) {
break;
}
swap(ptrArr + lb, ptrArr + rb);
}
swap(ptrArr + lb, ptrArr + (numOfElts - 1));
// Sort left sub-array
quicksort(ptrArr, lb);
// Sort right sub-array
quicksort(ptrArr + (lb + 1), numOfElts - lb - 1);
}
int main() {
printf("*** Quick Sort *** \n");
printf("Enter number of elements: ");
scanf("%d", &eltCount);
int arr[eltCount];
for (int i = 0; i < eltCount; i++) {
arr[i] = random() % UPPER_LIMIT + 1;
}
// Assign array to global pointer variable (to print array after each parse)
ptrMainArr = arr;
// Note: arr -> Pointer to array's first element
// Start clock
struct timespec start, end;
clock_gettime(CLOCK_REALTIME, &start);
// Sort array using quicksort
quicksort(arr, eltCount);
// End clock
clock_gettime(CLOCK_REALTIME, &end);
printf("Quick sort time taken is %f s.\n", calcRunTime(start, end));
return 0;
}
I ran this code for values under 110, and the code worked. Included is a Macro Function 'PRINT_ARR' to print the array after every parse.
I want to know the cause for the error, and how to sort an array of size > 10,000.
The partitioning function fails for any couple of equal numbers. It can be fixed just by adding an =. Moreover after swapping you can increase lb and decrease rb:
while (1) {
while (*(ptrArr + lb) < pivot) {
lb++;
}
while (*(ptrArr + rb) > pivot && lb <= rb) {
rb--;
}
if (lb >= rb) { // <--------------------------------------------------
break;
}
swap(ptrArr + lb++, ptrArr + rb--); // <------------------------------
}
Then additional suggestions:
remove the console input and use a fixed number for testing.
your calcRunTime function is broken. Just use your first equation:
long double calcRunTime(struct timespec start, struct timespec end) {
return (end.tv_sec - start.tv_sec) + ((float)(end.tv_nsec - start.tv_nsec) / BILLION);
}
don't use a VLA. malloc it, so you can grow without the risk of a stack overflow.
First I reproduced the issue by compiling your program and running it with 109 (ok) and 110 (doesn't terminate). Then I hard-coded eltCount to 110 so the program no longer requires interactive input. Removed irrelevant functionality. Modified the PRINT_ARR to take an array and len. Printed array before it's sorted paying particular attention to the last element:
#define PRINT_ARR(arr, len) for (unsigned i = 0; i < (len); i++) printf("%d ", arr[i]); printf("\n")
int main() {
unsigned eltCount = 110;
int arr[eltCount];
for (unsigned i = 0; i < eltCount; i++) {
arr[i] = random() % UPPER_LIMIT + 1;
}
PRINT_ARR(arr, eltCount);
quicksort(arr, eltCount);
PRINT_ARR(arr, eltCount);
return 0;
}
and found:
9384 887 2778 6916 7794 8336 5387 493 6650 1422 2363 28 8691 60 7764 3927 541 3427 9173 5737 5212 5369 2568 6430 5783 1531 2863 5124 4068 3136 3930 9803 4023 3059 3070 8168 1394 8457 5012 8043 6230 7374 4422 4920 3785 8538 5199 4325 8316 4371 6414 3527 6092 8981 9957 1874 6863 9171 6997 7282 2306 926 7085 6328 337 6506 847 1730 1314 5858 6125 3896 9583 546 8815 3368 5435 365 4044 3751 1088 6809 7277 7179 5789 3585 5404 2652 2755 2400 9933 5061 9677 3369 7740 13 6227 8587 8095 7540 796 571 1435 379 7468 6602 98 2903 3318 493
Nothing particular special about the last number other than it's a duplicate as #RetiredNinja noted above.
As the problem is an infinite loop, I looked the loops and particular their exit conditions. From our hint from the above, I changed it to only exist if two bounds are equal:
if(lb >= rb) break;
and the program now terminates.
Related
In this code I want to make Kruskal's algorithm, which calculates a minimum
spanning tree of a given graph. And I want to use min-heap and disjoint set at the code.
To make time complexity of O(e log n), where e is the number of edges and n is the number of vertices in the graph, I will use heap and disjoint set trees.
So the method I went with was:
Check the numbers of vertices and edges in the given input file and make parent array and struct edge which can include at most 10000 vertices and 50000000 edges.
Sort the edges by the weight in a min heap in descending order.
Take out edges from min heap one by one and check whether it makes cycle until min heap is empty
If the number of edges selected is vertices-1 (if all vertices already connected ) break the while loop and print each edges and sum of weights. If all vertices can make minimum spanning tree it prints connected and if all vertices can not make minimum spanning tree it prints disconnected.
I thought the code is well done but when I run this in putty, it is exiting with segmentation fault (core dumped)
input (example)
7
9
0 1 28
0 5 10
1 2 16
1 6 14
2 3 12
3 4 22
3 6 18
4 5 25
4 6 24
result(I want)
0 5 10
2 3 12
1 6 14
1 2 16
3 4 22
4 5 25
99
CONNECTED
I checked the edges are well stored in min-heap in descending order. But I think it has mistakes in making minimum spanning tree. These are points that I am suspicious in the code.
Should I make edge minheap by dynamic allocation instead of minheap[50000000]?
Should I make additional data structures apart from the array parent and struct edge.
It is the code I made! Can you give me help or advice ?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define maxvertice 10000
#define maxedge 50000000
typedef struct edge { //structure to store vertices and weight
int a, b;
int w;
}
edge;
int n = 0; //numbers of edge in the minheap
int parent[maxvertice] = {-1,};
//array to represent disjoint sets! parent which stores the vertice connected
//if it is not connected(independent) it's parent is -1
edge minheap[maxedge]; //heap that sorts edges
void insertheap(edge item, int * n); // arrange edges by the weight in descending order
edge deleteheap(int * n); //popping out from the root (in descending order)
void makeunion(int x, int y); // this make x and y combined
int findparent(int i);
int main(int argc, char * argv[]) {
double start, end;
int i, nv, ne, sumofweight = 0, isitdone;
int cnt_edge = 0;
edge item;
//////////////
if (argc != 2) {
printf("usage: ./hw3 input_filename\n");
return 0;
}
FILE * fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("The input file does not exist.\n");
return 0;
}
FILE * result = fopen("hw3_result.txt", "w");
start = (double) clock() / CLOCKS_PER_SEC;
fscanf(fp, "%d", & nv);
printf("to test : number of vertices : %d\n", nv);
fscanf(fp, "%d", & ne);
printf("to test : number of edges : %d\n", ne);
for (i = 0; i < ne; i++) {
int firstv, secondv, weight;
edge newedge;
fscanf(fp, "%d %d %d", & firstv, & secondv, & weight);
newedge.a = firstv;
newedge.b = secondv;
newedge.w = weight;
// get vertices and edge's weight from the input file and put in heap
insertheap(newedge, & n);
}
/*
for(i =0 ; i<ne; i++){
item= deleteheap(&n);
printf("%d", item.w);
}*/
while (minheap != NULL) { //pop out from the heap until mst is completed
item = deleteheap( & n);
//union at array parent
int par1, par2;
par1 = findparent(item.a);
par2 = findparent(item.b);
if (par1 != par2) {
makeunion(par1, par2);
printf("%d %d %d\n", item.a, item.b, item.w);
cnt_edge = cnt_edge + 1;
sumofweight += item.w;
}
if (cnt_edge == nv - 1) break;
}
if (cnt_edge == nv - 1) {
// fprintf(result, "CONNECTED");
printf("%d\n", sumofweight);
printf("CONNECTED");
}
if (cnt_edge < nv - 1) {
// fprintf(result, "DISCONNECTED");
printf("DISCONNECTED\n");
}
end = (((double) clock()) / CLOCKS_PER_SEC);
fclose(fp);
fclose(result);
printf("output written to hw3_result.txt.\n");
printf("running time: %1f", (end - start));
printf(" seconds\n");
}
void makeunion(int x, int y) {
parent[x] = y;
}
int findparent(int i) {
for (; parent[i] >= 0; i = parent[i]);
return i;
}
void insertheap(edge item, int * n) {
int i;
i = * n;
++( * n);
while ((i != 0) && (item.w < minheap[i / 2].w)) {
minheap[i] = minheap[i / 2];
i /= 2;
}
minheap[i] = item;
printf("to test : the wieght %d is inserted in :%d \n", item.w, i);
}
edge deleteheap(int * n) {
int parent, child;
parent = 0;
child = 1;
edge item, temp;
item = minheap[0];
temp = minheap[( * n) - 1];
( * n) --;
while (child <= * n) {
if ((child < * n) && (minheap[child].w > minheap[child + 1].w)) child++;
if (temp.w <= minheap[child].w) break;
minheap[parent] = minheap[child];
parent = child;
child *= 2;
}
minheap[parent] = temp;
return item;
}
I do not know why, gcc version 4.9.2 (Ubuntu 4.9.2-10ubuntu13 x86_64)
Breakpoint 1, convertToTitle (n=1000000001) at excel_sheet_column_title.c:14
14 printf("%d\n", n);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400697 in convertToTitle (n=1000000001) at excel_sheet_column_title.c:14
14 printf("%d\n", n);
(gdb) p n
$1 = 1000000001
The complete code of the function, just called the function with 1000000001 in the main function:
char *convertToTitle(int n)
{
int mod, idx, last = n / 26 + 1;
char str[last], *title, *tp;
printf("%d\n", n);
idx = last;
while (n > 26) {
mod = n % 26;
if (mod > 0) {
str[--idx] = mod - 1 + 'A';
} else if (mod == 0) {
str[--idx] = 'Z';
n -= 1;
}
n /= 26;
}
if (n > 0) {
str[--idx] = n - 1 + 'A';
}
title = (char *)malloc((last - idx + 1) * sizeof(char));
tp = title;
for (; idx < last; idx++) {
*tp++ = str[idx];
}
*tp = '\0';
return title;
}
Your last is very large. Move it outside of local function (or mark it static) to avoid segfault.
As an alternative (and correct) solution, calculate correct value of last.
(I think you wanted log26n + 1)
26last >= nlast = log26n
last = ceil(log(n) / log(26)) + 1;
Weak calculation of needed buffer size for str[] resulted in an excessively large array size last of 1000000001/26 + 1. This array size was unsupportable as coded as a local variable.
What is needed is a much smaller array about log26(n).
There is little need to "right-size" the buffer per various values of int n. Simply use a constant size that works for INT_MAX.
As the bit size of an int is about log2(INT_MAX)+1,
#include <limits.h>
#define ABOUT_LOG2_26 4.7
#define BUF26_SIZE ((int)(sizeof(int)*CHAR_BIT/ABOUT_LOG2_26 + 2))
char *convertToTitle(int n) {
char str[BUF26_SIZE];
...
// Also cope with negative values of n
if (n < 0) Handle_Error();
Version A:
#include<time.h>
#include<stdio.h>
int main()
{
time_t start = time(0); //denote start time
int i,j; // initialize ints
static double dst[4096][4096]; //initialize arrays
static double src[4096][4096]; //
for(i=0; i<4096; ++i){
for(j=0; j<4096; ++j){
dst[i][j] = src[i][j];
}
}
time_t end = time(0); //denote end time
double time = difftime(end, start); //take difference of start and end time to determine elapsed time
printf("Test One: %fms\n",time);
}
Version B:
#include<time.h>
#include<stdio.h>
int main()
{
time_t start = time(0); //denote start time
int i,j; // initialize ints
static double dst[4096][4096]; //initialize arrays
static double src[4096][4096]; //
for(i=0; i<4096; ++i){
for(j=0; j<4096; ++j){
dst[j][i] = src[j][i];
}
}
time_t end = time(0); //denote end time
double time = difftime(end, start); //take difference of start and end time to determine elapsed time
printf("Test One: %fms\n",time);
}
Using this program, I have determined that if you reverse the positions of i and j in the arrays, it takes 1 second longer to execute.
Why is this happening?
In your code, the loop means that "traverse the address in the same row, one by one, then go to next line". But if you reverse the positions of i and j, this means that "traverse the address in the same column, one by one, the go to next column".
In C, multi-dimensional array are put on linear address space, byte by byte, then line by line, so dst[i][j] = src[i][j] in your case means *(dst + 4096 * i + j) = *(src + 4096 * i + j):
*(dst + 4096 * 0 + 0) = *(src + 4096 * 0 + 0);
*(dst + 4096 * 0 + 1) = *(src + 4096 * 0 + 1);
*(dst + 4096 * 0 + 2) = *(src + 4096 * 0 + 2);
//...
while reversed i and j means:
*(dst + 4096 * 0 + 0) = *(src + 4096 * 0 + 0);
*(dst + 4096 * 1 + 0) = *(src + 4096 * 1 + 0);
*(dst + 4096 * 2 + 0) = *(src + 4096 * 2 + 0);
//...
So the extra 1 second in second case is cause by accessing memory in a non-contigous manner.
You don't need to do time calculation yourself, because you can run your program with "time" command on linux/UNIX:
$ time ./loop
The results on my linux box for the 2 cases:
$ time ./loop_i_j
real 0m0.244s
user 0m0.062s
sys 0m0.180s
$ time ./loop_j_i
real 0m1.072s
user 0m0.995s
sys 0m0.073s
#include<time.h>
#include<stdio.h>
int main()
{
time_t start = time(0); //denote start time
int i,j; // initialize ints
static double dst[4096][4096]; //initialize arrays
static double src[4096][4096]; //
for(j=0; j<4096; ++j){
for(i=0; i<4096; ++i){
dst[j][i] = src[j][i];
}
}
time_t end = time(0); //denote end time
double time = difftime(end, start); //take difference of start and end time to determine elapsed time
printf("Test One: %fms\n",time);
}
I tested and it is giving me this o/p Test One: 0.000000ms in both cases after reversing and normal. I used gcc compiler.
Maybe the issue is that you have not included stdio.h .I experienced the same behavior once when I did not include stdio.h.
Something related to memory(in stack) allocation during compile time could be possible reason.
I have a simple (brute-force) recursive solver algorithm that takes lots of time for bigger values of OpxCnt variable. For small values of OpxCnt, no problem, works like a charm. The algorithm gets very slow as the OpxCnt variable gets bigger. This is to be expected but any optimization or a different algorithm ?
My final goal is that :: I want to read all the True values in the map array by
executing some number of read operations that have the minimum operation
cost. This is not the same as minimum number of read operations.
At function completion, There should be no True value unread.
map array is populated by some external function, any member may be 1 or 0.
For example ::
map[4] = 1;
map[8] = 1;
1 read operation having Adr=4,Cnt=5 has the lowest cost (35)
whereas
2 read operations having Adr=4,Cnt=1 & Adr=8,Cnt=1 costs (27+27=54)
#include <string.h>
typedef unsigned int Ui32;
#define cntof(x) (sizeof(x) / sizeof((x)[0]))
#define ZERO(x) do{memset(&(x), 0, sizeof(x));}while(0)
typedef struct _S_MB_oper{
Ui32 Adr;
Ui32 Cnt;
}S_MB_oper;
typedef struct _S_MB_code{
Ui32 OpxCnt;
S_MB_oper OpxLst[20];
Ui32 OpxPay;
}S_MB_code;
char map[65536] = {0};
static int opx_ListOkey(S_MB_code *px_kod, char *pi_map)
{
int cost = 0;
char map[65536];
memcpy(map, pi_map, sizeof(map));
for(Ui32 o = 0; o < px_kod->OpxCnt; o++)
{
for(Ui32 i = 0; i < px_kod->OpxLst[o].Cnt; i++)
{
Ui32 adr = px_kod->OpxLst[o].Adr + i;
// ...
if(adr < cntof(map)){map[adr] = 0x0;}
}
}
for(Ui32 i = 0; i < cntof(map); i++)
{
if(map[i] > 0x0){return -1;}
}
// calculate COST...
for(Ui32 o = 0; o < px_kod->OpxCnt; o++)
{
cost += 12;
cost += 13;
cost += (2 * px_kod->OpxLst[o].Cnt);
}
px_kod->OpxPay = (Ui32)cost; return cost;
}
static int opx_FindNext(char *map, int pi_idx)
{
int i;
if(pi_idx < 0){pi_idx = 0;}
for(i = pi_idx; i < 65536; i++)
{
if(map[i] > 0x0){return i;}
}
return -1;
}
static int opx_FindZero(char *map, int pi_idx)
{
int i;
if(pi_idx < 0){pi_idx = 0;}
for(i = pi_idx; i < 65536; i++)
{
if(map[i] < 0x1){return i;}
}
return -1;
}
static int opx_Resolver(S_MB_code *po_bst, S_MB_code *px_wrk, char *pi_map, Ui32 *px_idx, int _min, int _max)
{
int pay, kmax, kmin = 1;
if(*px_idx >= px_wrk->OpxCnt)
{
return opx_ListOkey(px_wrk, pi_map);
}
_min = opx_FindNext(pi_map, _min);
// ...
if(_min < 0){return -1;}
kmax = (_max - _min) + 1;
// must be less than 127 !
if(kmax > 127){kmax = 127;}
// is this recursion the last one ?
if(*px_idx >= (px_wrk->OpxCnt - 1))
{
kmin = kmax;
}
else
{
int zero = opx_FindZero(pi_map, _min);
// ...
if(zero > 0)
{
kmin = zero - _min;
// enforce kmax limit !?
if(kmin > kmax){kmin = kmax;}
}
}
for(int _cnt = kmin; _cnt <= kmax; _cnt++)
{
px_wrk->OpxLst[*px_idx].Adr = (Ui32)_min;
px_wrk->OpxLst[*px_idx].Cnt = (Ui32)_cnt;
(*px_idx)++;
pay = opx_Resolver(po_bst, px_wrk, pi_map, px_idx, (_min + _cnt), _max);
(*px_idx)--;
if(pay > 0)
{
if((Ui32)pay < po_bst->OpxPay)
{
memcpy(po_bst, px_wrk, sizeof(*po_bst));
}
}
}
return (int)po_bst->OpxPay;
}
int main()
{
int _max = -1, _cnt = 0;
S_MB_code best = {0};
S_MB_code work = {0};
// SOME TEST DATA...
map[ 4] = 1;
map[ 8] = 1;
/*
map[64] = 1;
map[72] = 1;
map[80] = 1;
map[88] = 1;
map[96] = 1;
*/
// SOME TEST DATA...
for(int i = 0; i < cntof(map); i++)
{
if(map[i] > 0)
{
_max = i; _cnt++;
}
}
// num of Opx can be as much as num of individual bit(s).
if(_cnt > cntof(work.OpxLst)){_cnt = cntof(work.OpxLst);}
best.OpxPay = 1000000000L; // invalid great number...
for(int opx_cnt = 1; opx_cnt <= _cnt; opx_cnt++)
{
int rv;
Ui32 x = 0;
ZERO(work); work.OpxCnt = (Ui32)opx_cnt;
rv = opx_Resolver(&best, &work, map, &x, -42, _max);
}
return 0;
}
You can use dynamic programming to calculate the lowest cost that covers the first i true values in map[]. Call this f(i). As I'll explain, you can calculate f(i) by looking at all f(j) for j < i, so this will take time quadratic in the number of true values -- much better than exponential. The final answer you're looking for will be f(n), where n is the number of true values in map[].
A first step is to preprocess map[] into a list of the positions of true values. (It's possible to do DP on the raw map[] array, but this will be slower if true values are sparse, and cannot be faster.)
int pos[65536]; // Every position *could* be true
int nTrue = 0;
void getPosList() {
for (int i = 0; i < 65536; ++i) {
if (map[i]) pos[nTrue++] = i;
}
}
When we're looking at the subproblem on just the first i true values, what we know is that the ith true value must be covered by a read that ends at i. This block could start at any position j <= i; we don't know, so we have to test all i of them and pick the best. The key property (Optimal Substructure) that enables DP here is that in any optimal solution to the i-sized subproblem, if the read that covers the ith true value starts at the jth true value, then the preceding j-1 true values must be covered by an optimal solution to the (j-1)-sized subproblem.
So: f(i) = min(f(j) + score(pos(j+1), pos(i)), with the minimum taken over all 1 <= j < i. pos(k) refers to the position of the kth true value in map[], and score(x, y) is the score of a read from position x to position y, inclusive.
int scores[65537]; // We effectively start indexing at 1
scores[0] = 0; // Covering the first 0 true values requires 0 cost
// Calculate the minimum score that could allow the first i > 0 true values
// to be read, and store it in scores[i].
// We can assume that all lower values have already been calculated.
void calcF(int i) {
int bestStart, bestScore = INT_MAX;
for (int j = 0; j < i; ++j) { // Always executes at least once
int attemptScore = scores[j] + score(pos[j + 1], pos[i]);
if (attemptScore < bestScore) {
bestStart = j + 1;
bestScore = attemptScore;
}
}
scores[i] = bestScore;
}
int score(int i, int j) {
return 25 + 2 * (j + 1 - i);
}
int main(int argc, char **argv) {
// Set up map[] however you want
getPosList();
for (int i = 1; i <= nTrue; ++i) {
calcF(i);
}
printf("Optimal solution has cost %d.\n", scores[nTrue]);
return 0;
}
Extracting a Solution from Scores
Using this scheme, you can calculate the score of an optimal solution: it's simply f(n), where n is the number of true values in map[]. In order to actually construct the solution, you need to read back through the table of f() scores to infer which choice was made:
void printSolution() {
int i = nTrue;
while (i) {
for (int j = 0; j < i; ++j) {
if (scores[i] == scores[j] + score(pos[j + 1], pos[i])) {
// We know that a read can be made from pos[j + 1] to pos[i] in
// an optimal solution, so let's make it.
printf("Read from %d to %d for cost %d.\n", pos[j + 1], pos[i], score(pos[j + 1], pos[i]));
i = j;
break;
}
}
}
}
There may be several possible choices, but all of them will produce optimal solutions.
Further Speedups
The solution above will work for an arbitrary scoring function. Because your scoring function has a simple structure, it may be that even faster algorithms can be developed.
For example, we can prove that there is a gap width above which it is always beneficial to break a single read into two reads. Suppose we have a read from position x-a to x, and another read from position y to y+b, with y > x. The combined costs of these two separate reads are 25 + 2 * (a + 1) + 25 + 2 * (b + 1) = 54 + 2 * (a + b). A single read stretching from x-a to y+b would cost 25 + 2 * (y + b - x + a + 1) = 27 + 2 * (a + b) + 2 * (y - x). Therefore the single read costs 27 - 2 * (y - x) less. If y - x > 13, this difference goes below zero: in other words, it can never be optimal to include a single read that spans a gap of 12 or more.
To make use of this property, inside calcF(), final reads could be tried in decreasing order of start-position (i.e. in increasing order of width), and the inner loop stopped as soon as any gap width exceeds 12. Because that read and all subsequent wider reads tried would contain this too-large gap and therefore be suboptimal, they need not be tried.
suppose I have n1 and n2 I want to multiply them
for example I have array
n1={1,2,3};
and in
n2={5,6}
they are two integers in n1 we have the 123 and in n2 56
123*56=6888
then in result I should have
result = {6,8,8,8}
here is the incomplete algorithm which I thought
for(i in n1 bigger array)
for(j in n2 smaller one)
{
mult=n1[i]*n2[j]
mult+= carry;
if(mult>=10)
{
carry = (mult/10);
mult-= (carry*10);
}
}
}
How can I write it? I don't know the place of store
after finishing the insider loop I should store num in array and then compute again and...
How should I write it? I searched the whole of overflow here but I didn't find about it in c code
The Goal is to Compute the Large numbers Integer Numbers has 8 Bytes,in other words 64 bits so they can store 2pow64-1 which is 19 digits now this will help to compute very larger than 19 digits
It would be slightly easier if your digit-arrays were little-endian. Then your example multiplication would look
3 2 1 * 6 5
---------------
18 12 6
15 10 5
---------------
18 27 16 5 // now propagate carries
8 28 16 5
8 8 18 5
8 8 8 6
============
The product of n1[i] and n2[j] would contribute to result[i+j]. The main loop could roughly look like
for (i = 0; i < l1; ++i) // l1 is length of n1
{
for (j = 0; j < l2; ++j) // l2 is length of n2
{
result[i+j] += n1[i]*n2[j];
}
}
// now carry propagation
You see that the result must be at least (l1-1) + (l2-1) + 1 long, since the product of the most significant digits goes int result[(l1-1) + (l2-1)]. On the other hand, n1 < 10^l1 and n2 < 10^l2, so the product is < 10^(l1+l2) and you need at most l1+l2 digits.
But if you're working with char (signed or unsigned), that will quickly overflow in each digit, since (for k <= min(l1-1,l2-1)) k+1 products of two digits (each can be as large as 81) contribute to digit k of the product.
So it's better to perform the multiplication grouped according to the result digit, accumulating in a larger type, and doing carry propagation on writing the result digit. With little-endian numbers
char *mult(char *n1, size_t l1, char *n2, size_t l2, size_t *rl)
{
// allocate and zero-initialise, may be one more digit than needed
char *result = calloc(l1+l2+1,1);
*rl = l1 + l2;
size_t k, i, lim = l1+l2-1;
for (k = 0; k < lim; ++k)
{
unsigned long accum = result[k];
for (i = (k < l2) ? 0 : k-(l2-1); i <= k && i < l1; ++i)
{
accum += (n1[i] - '0') * (n2[k-i] - '0');
}
result[k] = accum % 10 + '0';
accum /= 10;
i = k+1;
while(accum > 0)
{
result[i] += accum % 10;
accum /= 10;
++i;
}
}
if (result[l1+l2-1] == 0)
{
*rl -= 1;
char *real_result = calloc(l1+l2,1);
for (i = 0; i < l1+l2-1; ++i)
{
real_result[i] = result[i];
}
free(result);
return real_result;
}
else
{
result[l1+l2-1] += '0';
return result;
}
}
For big-endian numbers, the indexing has to be modified - you can figure that out yourself, hopefully - but the principle remains the same.
Indeed, the result isn't much different after tracking indices with pencil and paper:
char *mult(char *n1, size_t l1, char *n2, size_t l2, size_t *rl)
{
// allocate and zero-initialise, may be one more digit than needed
// we need (l1+l2-1) or (l1+l2) digits for the product and a 0-terminator
char *result = calloc(l1+l2+1,1);
*rl = l1 + l2;
size_t k, i, lim = l1+l2-1;
// calculate the product from least significant digit to
// most significant, least significant goes into result[l1+l2-1],
// the digit result[0] can only be nonzero by carry propagation.
for (k = lim; k > 0; --k)
{
unsigned long accum = result[k]; // start with carry
for (i = (k < l2) ? 0 : k-l2; i < k && i < l1; ++i)
{
accum += (n1[i] - '0') * (n2[k-1-i] - '0');
}
result[k] = accum % 10 + '0';
accum /= 10;
i = k-1;
while(accum > 0)
{
result[i] += accum % 10;
accum /= 10;
--i;
}
}
if (result[0] == 0) // no carry in digit 0, we allocated too much
{
*rl -= 1;
char *real_result = calloc(l1+l2,1);
for (i = 0; i < l1+l2-1; ++i)
{
real_result[i] = result[i+1];
}
free(result);
return real_result;
}
else
{
result[0] += '0'; // make it an ASCII digit
return result;
}
}
Edit: added 0-terminators
Note: these are not NUL-terminated (unsigned) char arrays, so we need to keep length information (that's good to do anyway), hence it would be better to store that info together with the digit array in a struct. Also, as written it only works for positive numbers. Dealing with negative numbers is awkward if you only have raw arrays, so another point for storing additional info.
Keeping the digits as '0' + value doesn't make sense for the computations, it is only convenient for printing, but that only if they were NUL-terminated arrays. You may want to add a slot for the NUL-terminator then. In that case, the parameter rl in which we store the length of the product is not strictly necessary.
Definitely an interesting problem.
Here was my thought:
For the given array, append each value to the end of a string. Thus you construct a string of the numbers in order. {1,2,3} = "123"
Then, you use a "ToInteger" method that you can find in one of the C libraries. Now you have your number to multiply with.
With this logic, you can probably look up how the "ToInteger" or "ToString" methods work with numbers, which would lead to an answer.
Think how you would do it on paper, since you are simulating multiplying two decimal numbers. For starters, I think you'd go from least significant to most significant digit, so you'd be counting down the indexes (2, 1, 0 for the larger array; 1, 0 for the smaller). Also, you'd somehow have to arrange that when you multiply by n2[0] (the 5 in 56), you start adding at the tens place, not the units.
You won't find complete C code for your problem at SO. Your first approach isn't that bad. You could do the following:
Multiply n1 and n2, conversion is done by mulitplication and addition, i. e. a{1,2,3} -> 1*100 + 2*10 + 3*1, easy to implement
Count the digits of your multiplication result (use division inside a loop)
While looping through the digits you can store them back into another array
If you can't or if you don't want to deal with dynamic array allocation, then think about how big your array for storage must be beforehand and perform a static allocation.
Edit
Based on the discussion another approach:
Suppose, that r = n1 * n2
Create a n*m 2D array, where
n = number of digits in n2
m = number of digits in n1 + 1
Within a loop multiply each digit of n1 with one of the elements of n2, store the result in the array, store the result per-digit in the 2D-array, don't forget to add the carry to each digit
Repeat 2 with all other digits of n2
Now the array is filled and you'll have to add each digits like you would do it on paper, store each result within a target array, take care of the carry again
There is one thing left in the algorithm: Determine the size of the target array, based on the informations within the intermediate array, you can think about this by using pencil and paper ;)
This code isn't optimized, nor does it account for generic lengths of arrays/numbers, but it should give you the general idea of how to implement the algorithm:
(This is similar to string-to-int or int-to-string algorithms, just add the ASCII offset to each item of the array and you have it.)
#include <stdio.h>
#include <stdint.h>
#define N1_N 3
#define N2_N 2
#define MAX_N 4 /* maximum array length allowed */
void print_array (const uint8_t* array, size_t size);
uint32_t array_to_ulong (const uint8_t* array, size_t size);
size_t ulong_to_array (uint8_t* array, size_t size, uint32_t val);
int main()
{
uint8_t n1[N1_N] = {1,2,3};
uint8_t n2[N2_N] = {5,6};
uint8_t n3[MAX_N];
size_t n3_size = MAX_N;
uint32_t n1_int;
uint32_t n2_int;
uint32_t result;
print_array(n1, N1_N);
printf(" * ");
print_array(n2, N2_N);
n1_int = array_to_ulong (n1, N1_N);
n2_int = array_to_ulong (n2, N2_N);
result = n1_int * n2_int;
printf(" = %d = ", result);
n3_size = ulong_to_array (n3, n3_size, result);
print_array(n3, n3_size);
getchar();
return 0;
}
void print_array (const uint8_t* array, size_t size)
{
size_t i;
printf("{");
for(i=0; i<size; i++)
{
printf("%d", array[i]);
if(i != size-1)
{
printf(", ");
}
}
printf("}");
}
uint32_t array_to_ulong (const uint8_t* array, size_t size)
{
uint32_t result = 0;
uint32_t multiplier = 1;
size_t i;
for(i=1; i<=size; i++)
{
result += array[size-i] * multiplier;
multiplier *= 10;
}
return result;
}
size_t ulong_to_array (uint8_t* array, size_t size, uint32_t val)
{
size_t i;
for(i=1; i<=size && val!=0; i++)
{
array[size-i] = val % 10;
val /= 10;
}
return i-1;
}
12345 * 6789 is:
12345 * 6 * 1000 +
12345 * 7 * 100 +
12345 * 8 * 10 +
12345 * 9 * 1
and that is:
1 * 6*1000 * 10000 + 2 * 6*1000 * 1000 + 3 * 6*1000 * 100 + 4 * 6*1000 * 10 + 5 * 6*1000 * 1 +
1 * 7*100 * 10000 + 2 * 7*100 * 1000 + 3 * 7*100 * 100 + 4 * 7*100 * 10 + 5 * 7*100 * 1 +
1 * 8*10 * 10000 + 2 * 8*10 * 1000 + 3 * 8*10 * 100 + 4 * 8*10 * 10 + 5 * 8*10 * 1 +
1 * 9*1 * 10000 + 2 * 9*1 * 1000 + 3 * 9*1 * 100 + 4 * 9*1 * 10 + 5 * 9*1 * 1
so the algorith is multiply each value by each value and add (cumulate) it to the appropriate result array element (1000 is 10^3 so array element 3 (array starting by zero)).
then move thru the result array and shift for results bigger than 10 the div by ten to the left (starting by the far right)
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#define MAX 10000
char * multiply(char [],char[]);
int main(){
char a[MAX];
char b[MAX];
char *c;
int la,lb;
int i;
printf("Enter the first number : ");
scanf("%s",a);
printf("Enter the second number : ");
scanf("%s",b);
printf("Multiplication of two numbers : ");
c = multiply(a,b);
printf("%s",c);
return 0;
}
char * multiply(char a[],char b[]){
static char mul[MAX];
char c[MAX];
char temp[MAX];
int la,lb;
int i,j,k=0,x=0,y;
long int r=0;
long sum = 0;
la=strlen(a)-1;
lb=strlen(b)-1;
for(i=0;i<=la;i++){
a[i] = a[i] - 48;
}
for(i=0;i<=lb;i++){
b[i] = b[i] - 48;
}
for(i=lb;i>=0;i--){
r=0;
for(j=la;j>=0;j--){
temp[k++] = (b[i]*a[j] + r)%10;
r = (b[i]*a[j]+r)/10;
}
temp[k++] = r;
x++;
for(y = 0;y<x;y++){
temp[k++] = 0;
}
}
k=0;
r=0;
for(i=0;i<la+lb+2;i++){
sum =0;
y=0;
for(j=1;j<=lb+1;j++){
if(i <= la+j){
sum = sum + temp[y+i];
}
y += j + la + 1;
}
c[k++] = (sum+r) %10;
r = (sum+r)/10;
}
c[k] = r;
j=0;
for(i=k-1;i>=0;i--){
mul[j++]=c[i] + 48;
}
mul[j]='\0';
return mul;
}