I was trying to solve Project Euler question 16 using c. I did not use bignnum libraries. The question asks 2^1000. I decided to store every digit of that number in an array.
For Example: 45 means arr[0]=4, arr[1]=5;
The problem is definitely i the function int multi.
#include<stdio.h>
#include<conio.h>
int multi(int *base, int k);// does the multiplication of array term by 2
void switcher();//switches every term when the fore mostvalue is >10
int finder();// finds the array address of last value
int arr[1000];
int summer();//sums all values of the array
int main()
{
arr[1000] = { 0 };
arr[0] = 1;
int i, j, sum, k, p;
for (i = 0; i < 1000; i++)
{
j = 0;
k = finder();
p = multi(arr + k, j);
}
sum = summer();
printf("sum of digits of 2^1000 is %d", sum);
_getch();
}
int multi(int *base, int k)
{
int p;
if (base == arr)
{
*base = *base - 1;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
switcher();
}
return 0;
}
*base = *base * 2;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
p = multi(base - 1, 1);
}
else
{
p = multi(base - 1, 0);
}
}
void switcher()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
j--;
for (; j > 0; j--)
{
arr[j + 1] = arr[j];
}
arr[0] = 1;
}
int finder()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
return --j;
}
int summer()
{
int summ, i;
summ = 0;
for (i = 0; i<1000; i++)
{
summ = summ + arr[i];
if (arr[i] == 0)
break;
}
return summ;
}
It compiles but during runtime it shows Access Write Violation, base was ......
Please explain this error and how to resolve it ?
Array is of 100 Bytes but you are looping for 1000. Also in function Finder() , you do not have a limit on variable j so your array size is going beyond 100 bytes.
Also use memset to assign array variables to 0.
As said in the comments, 2^1000 has 302 decimal digits.
You're going far outside your array.
But your code is very complicated because you store the digits with the most significant one first.
Since you're only interested in the digits and not the order in which they would be written, you can store the number "in reverse", with the least significant digit first.
This makes the code much simpler, as you can loop "forwards" and no longer need to shuffle array elements around.
Using -1 as "end of number" marker, it might look like this:
void twice(int* digits)
{
int i = 0;
int carry = 0;
while (digits[i] >= 0)
{
digits[i] *= 2;
digits[i] += carry;
if (digits[i] >= 10)
{
carry = 1;
digits[i] -= 10;
}
else
{
carry = 0;
}
i++;
}
if (carry)
{
digits[i] = 1;
digits[i+1] = -1;
}
}
int main()
{
int digits[302] = {1, -1}; /* Start with 1 */
twice(digits); /* digits is now { 2, -1 } */
return 0;
}
Related
as a part of a C program I wrote the following function, which finds the second smallest element of an array
unsigned int array_second_min (unsigned int w[], unsigned int n)
{
unsigned int i, erst = UINT_MAX, zweit = UINT_MAX, count = 0;
if (n < 2)
return UINT_MAX;
for (i = 0;i < n; i++) {
if (w[i] == w[i + 1])
count++;
}
if (count == n - 1)
return UINT_MAX;
for (i = 0;i < n;i++) {
if (w[i] < erst)
erst = w[i];
}
for (i = 0;i < n;i++) {
if (w[i] == erst)
continue;
if ((w[i] - erst) < zweit)
zweit = w[i];
}
return zweit;
}
the problem is that it is not really functioning as it should. I think the problem is in the last for loop, but am not sure about that.
Thank you for your help
picture of the output:
The following code will return the second smallest element
unsigned int array_second_min (unsigned int w[], unsigned int n){
unsigned int i, first = UINT_MAX, second = UINT_MAX;
if(n < 2)
return UINT_MAX;
sort(w, w+n);
second = w[n-2];
return second;
}
This is a somewhat more efficient solution, as it is O(n):
struct pair {
int r[2];
};
struct pair small2(int *a, int n) {
int r[2];
int order;
r[0] = a[0];
r[1] = a[1];
order = (r[0] >= r[1]);
for (int i = 2; i < n; i++) {
if (a[i] <= r[order]) {
r[!order] = a[i];
order = !order;
} else if (a[i] <= r[!order]) {
r[!order] = a[i];
}
}
struct pair x;
x.r[0] = r[order];
x.r[1] = r[!order];
return x;
}
There is a lack of detail about duplicates, this handles them in an unsurprising fashion. Note the trickiness of the order variable; this works because you are only interested in the least two, if you wanted the least 3, you would have to add the extra tests. It would remain O(n), but the C would be greater.
For an assignment, I have to write code which accepts as input an integer n and outputs the nth 'superunusual' number.
The first few su-numbers are: 22, 23, 26, 33, ... So when the input is 1, the output should be 22. 2 gives 23 and 3 gives 26.
I already have a code that checks if the input number is a su-number, but I can't find a way to calculate the nth number.
So when I now input 22, it says that 22 is a superunusual number.
The code:
/* calculates largest prime factor */
int lprime(int n) {
int max = -1;
while (n % 2 == 0) {
max = 2;
n /= 2;
}
for (int i = 3; i*i <= n; i += 2) {
while (n % i == 0) {
max = i;
n = n / i;
}
}
if (n > 2) {
max = n;
}
return max;
}
/* check unusual number */
int unus(int n) {
/* find largest prime of number */
int factor = lprime(n);
/* Check if largest prime > sqrt(n) */
if ((factor*factor) > n) {
return 1; /* true */
}
else {
return 0; /* false */
}
}
/* delete digit from number */
int del(int num, int n) {
int d = log10(num)+1; /* checks amount of digits */
int revnew = 0;
int new = 0;
for (int i = 0; num != 0; i++) {
int dig = num % 10;
num = num / 10;
if(i == (d - n)) {
continue;
} else {
revnew = (revnew * 10) + dig;
}
}
for (int i = 0; revnew != 0; i++) {
new = (new*10) + (revnew % 10);
revnew = revnew / 10;
}
return new;
}
/* driver code */
int main(int argc, char* v[]) {
int m=22, n;
int x = 0;
int i = 1;
int counter = 0;
scanf("%d", &n);
int d = log10(m)+1;
while (counter < n) {
if (unus(m++)) {
counter++;
}
}
for(unus(m); i < d; i++) {
int nmin = del(m, i);
if (unus(nmin)) {
continue;
} else {
printf("%d is not supurunusual\n", (m-1));
x++;
}
}
if(x==0) {
printf("%d is superunusual!\n", (m-1));
}
return 0;
}
I hope you can understand my code. Otherwise I will explain it better.
Also, I'm quite new to coding, so please don't be to harsh...
You have a function to determine whether a number is unusual, but you do the check whether a number is super-unusual in the body of the main routine. If you extract that code into a proper function:
int is_superunusual(int m)
{
int d = log10(m) + 1;
if (unus(m) == 0) return 0;
for(int i = 0; i < d; i++) { // see footnote
int nmin = del(m, i);
if (unus(nmin) == 0) return 0;
}
return 1;
}
then you can use Eugene's code:
while (counter < n) {
if (is_superunusual(m++)) {
counter++;
}
}
printf("The su number #%d is %d\n", n, m - 1);
Your code tested for unusual numbers, not super-unusual numbers.
Footnote: If you take del(num, n) to mean "remove the nth digit from the end", you can do away with the log10 call in del. You must check all deletions anyway, so the order doesn't really matter here.
I am trying to add two polynomial functions and store the answer into first one. So far I have this:
// co = coefficient, ex = exponent
void add_polynom(int co1[], int ex1[], int co2[], int ex2[])
{
int i, j;
for (i = 0; i < dataSize; i++)
{
for (j = 0; j < dataSize; j++)
{
if (ex1[i] == ex2[j])
{
co1[i] = co1[i] + co2[i];
co2[i] = 0;
}
}
}
}
Am I on the right track?
Your representation of polynomials is impractical:
you iterate in 2 nested loops (quadratic complexity) to try and match the corresponding terms of both polynomials, but if the second has a power that the first does not have, it will be missing in the sum.
you pass the degree as a global variable dataSize that may have an inappropriate value.
You should instead use an array of coefficients for all exponents from 0 to the degree of the polynomial and pass the destination polynomial and its degree this way:
/* add 2 polynomials into a destination array.
* count variables are the sizes of the arrays,
* ie 1 more than the degree of the polynomials.
* return the size of the resulting polynomial,
* potentially larger than the size of the destination array.
*/
int add_polynomials(int dest[], int dest_count,
const int co1[], int count1,
const int co2[], int count2) {
/* compute the result coefficients */
int i, count;
for (i = count = 0; i < dest_count; i++) {
int coef = 0;
if (i < count1)
coef += co1[i];
if (i < count2)
coef += co2[i];
dest[i] = coef;
if (coef != 0)
count = i + 1;
}
/* determine the result count */
for (; i < count1 && i < count2; i++) {
if (co1[i] + co2[i] != 0)
count = i + 1;
}
for (; i < count1; i++) {
if (co1[i] != 0)
count = i + 1;
}
for (; i < count2; i++) {
if (co2[i] != 0)
count = i + 1;
}
return count;
}
If you must use the given prototype and global definition for dataSize, you could use 2 nested loops indeed, but depending on how the exponents are used in both polynomials, it might be impossible to fit the result in the destination array:
the source polynomials can each have up to dataSize terms with any range of exponents. The resulting polynomial might have a total number of terms that exceeds dataSize and thus not representable in an array of size dataSize.
your code fails because you wrote co1[i] = co1[i] + co2[i]; instead of co1[i] = co1[i] + co2[j];, but you also modify co2[i], which is inappropriate and you miss the terms that are only present in co2/ex2.
If we can assume that the maximum exponent is less than dataSize, here is an efficient approach (linear time) that will generate a result in normalized form:
#define dataSize 50
// co = coefficients, ex = exponents
void add_polynom(int co1[], int ex1[], int co2[], int ex2[]) {
int res[dataSize] = { 0 };
int i, j;
for (i = 0; i < dataSize; i++) {
res[ex1[i]] += co1[i];
res[ex2[i]] += co2[i];
}
j = 0;
for (i = dataSize; i-- > 0;) {
if (res[i] != 0) {
co1[j] = res[i];
ex1[j] = i;
j++;
}
}
while (j < dataSize) {
co1[j] = ex1[j] = 0;
}
}
Take for example say 7x^3 + 2x + 1 as first and 5x^4 + 9x^2 as second polynomial. Now dataSize becomes 5(since higher degree of both is 4).
Now co1 would be {1, 2, 0, 7, 0} and co2 would be {0, 0, 9, 0, 5}.
for (i = 0; i < dataSize; i++)
{
co1[i] += co2[i];
}
Your interface is "suboptimal". It forces guarantees to to be made for it to work at all.
Use option 1 if you can guarantee that all values of exs1 and exs2 are in [0..(DATASIZE-1)].
Use option 2 if you can merely guarantee that there are fewer than DATASIZE different values in exs1 and exs2 combined.
Option 1
This solution's performance is bound by O(N).
#define DATASIZE 50
void panic(const char* msg) {
fprintf(stderr, msg);
exit(EXIT_FAILURE);
}
find_ex(ex,
// Assumes all values in exs1 are in [0..49].
// Assumes all values in exs2 are in [0..49].
void add_polynom(int cos1[], int exs1[], int cos2[], int exs2[]) {
int cos_sum[DATASIZE];
size_t i;
int exs1i, exs2i;
for (i=DATASIZE; i--; )
cos_sum[i] = 0;
for (i=DATASIZE; i--; ) {
if (exs1[i] < 0 || exs1[i] >= DATASIZE || exs2[i] < 0 || exs2[i] >= DATASIZE)
panic("add_polynom: Exponent out of range\n");
cos_sum[exs1[i]] += cos1[i];
cos_sum[exs2[i]] += cos2[i];
}
for (i=DATASIZE; i--; ) {
cos1[i] = cos_sum[i];
exs1[i] = i;
cos2[i] = 0;
/* exs2[i] = i; */
}
}
Option 2
This solution's performance is bound by O(N2). The bound can be reduced to O(N) by using an associative array instead of find_index_of_ex, but that's too much work for this answer.
#define DATASIZE 50
void panic(const char* msg) {
fprintf(stderr, msg);
exit(EXIT_FAILURE);
}
ssize_t find_index_of_ex(int ex, int cos[], int exs[], size_t size) {
ssize_t i;
for (i=0; i<size; ++i) {
if (exs[i] == ex) {
return i;
}
}
return -1;
}
// Assumes there are fewer than DATASIZE different values in exs1 and exs2 combined.
void add_polynom(int cos1[], int exs1[], int cos2[], int exs2[]) {
int cos_sum[];
int exs_sum[];
ssize_t lookup_is_by_ex[datasize];
size_t i, sum_count;
ssize_t i_sum;
for (i=DATASIZE; i--; ) {
cos_sum[i] = 0;
exs_sum[i] = 0;
}
sum_count = 0;
for (i=DATASIZE; i--; ) {
if (cos1[i] == 0)
continue;
i_sum = find_index_of_ex(exs1[i], exs_sum, sum_count);
if (i_sum >= 0)
cos_sum[i_sum] += cos1[i];
continue;
}
if (sum_count == DATASIZE)
panic("add_polynom: Too many different exponents\n");
cos_sum[sum_count] = cos1[i];
exs_sum[sum_count] = exs1[i];
++sum_count;
}
for (i=DATASIZE; i--; ) {
if (cos2[i] == 0)
continue;
i_sum = find_index_of_ex(exs2[i], exs_sum, sum_count);
if (i_sum >= 0)
cos_sum[i_sum] += cos2[i];
continue;
}
if (sum_count == DATASIZE)
panic("add_polynom: Too many different exponents\n");
cos_sum[sum_count] = cos2[i];
exs_sum[sum_count] = exs2[i];
++sum_count;
}
for (i=DATASIZE; i--; ) {
cos1[i] = cos_sum[i];
exs1[i] = exs_sum[i];
cos2[i] = 0;
/* exs2[i] = i; */
}
}
I tackled the problem by first figuring out the length of two given numbers and aligning the one with less digits (if one exists) into a new array so that the ones, tens, hundreds etc. align with the bigger number's ones, tens, hundreds, etc.
Then I wanted to save the sum of each two aligned elements (with a mod of 10) into a new array while checking if the sum of digits is greater than 10 - just the basic sum stuff. Now the problem occurs with adding two elements into the aplusb integer and I've tried fixing it with writing
int aplusb = (lengthA[max-i]-'0') +(temp[max-i]-'0');
but it doesn't work. I'm stuck and I don't know what to do. Please help.
The whole code:
#include <stdio.h>
#include <math.h>
int main(){
char a[10000];
char b[10000];
scanf("%s %s", &a, &b);
char sum[10000];
int lengthA = 0;
int lengthB = 0;
int i = 0;
while(a[i]){
i++;
} lengthA = i;
i = 0;
while(b[i]){
i++;
} lengthB = i;
char temp[10000];
int aplusb;
int carry = 0;
int max = lengthA;
int difference = abs(lengthA - lengthB);
if(lengthA>lengthB){
for(i=0; i<lengthA; i++){
temp[i+difference]=b[i];
}
for(i=0; i<=max; i++){
aplusb = lengthA[max-i]+temp[max-i]; //<-- this is the problematic line
if(carry = 1) aplusb++;
if(aplusb>9){
carry = 1;
aplusb%=10;
}
sum[i]=aplusb;
}
}
for(i=0; i<=max; i++){
printf("%c", sum[i]);
}
/*
if(lengthB>lengthA){
max = lengthB;
for(i=0; i<lengthB; i++){
temp[i+difference]=a[i];
}
}*/
return 0;
}
Doing operations and storing on very large numbers is very akin to doing operations and storing polynomials, i.e. with x = 10. a0 + a1.10 + a2.10^2 ... + an.10^n.
There are many polynomial libraries on the Internet, where you could find inspiration. All operations on your very large numbers can be expressed in terms of polynomials. This means that by using base 2^8, or even base 2^63, instead of base 10 to internally store your large numbers you would greatly improve performance.
You must also normalize your coefficients after operations to keep them positive. Operations may result in a negative coefficient, That can easily be fixed, as it is very similar to borrowing after a subtraction, this means coefficients must be larger than your base by 1bit.
To convert back to base 10, you'd need to solve r (your result) for v (your value), such as r(10)=v(2^63). This has only one solution, if you enforce the positive coefficients rule.
[note] After thinking about it some more: the rule on positive coefficients may only be necessary for printing, after all.
Example: adding. no memory error checking
int addPolys(signed char** result, int na, const signed char* a, int nb, const signed char* b)
{
int i, nr, nmin, carry, *r;
nr = max(na, nb) + 1;
nmin = min(na, nb);
r = malloc(sizeof(signed char) * (na + nb + 1));
if (nb < na)
{
nr = nb;
}
for (i = 0; i < nmin; ++i)
{
r[i] = a[i] + b[i];
}
for (; i < na; ++i)
{
r[i] = a[i];
}
for (; i < nb; ++i)
{
r[i] = b[i];
}
r[nr - 1] = 0;
// carry - should really be a proc of its own, unoptimized
carry = 0;
for (i = 0; i < nr; ++i)
{
r[i] += carry;
if (r[i] > 10)
{
carry = r[i] / 10;
r[i] %= 10;
}
else if (r[i] < 0)
{
carry = (r[i] / 10) - 1;
r[i] -= (carry * 10);
}
else
carry = 0;
}
// 'remove' leading zeroes
for (i = nr - 1; i > 0; --i)
{
if (r[i] != 0) break;
}
++i;
*result = r;
if (i != nr)
{
*result = realloc(i * sizeof(signed char));
}
return i; // return number of digits (0 being 1 digit long)
}
That code is working now for any two positive numbers with up to ten thousand digits:
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char chara[10000];
char charb[10000];
scanf("%s %s", &chara, &charb);
int lengthA = strlen(chara);
int lengthB = strlen(charb);
int max = lengthA;
if(lengthB>lengthA) max=lengthB;
int dif = abs(lengthA - lengthB);
//ustvari int tabele
int a[max];
int b[max];
int sum[max+1];
// nastavi nule
int i;
for(i=0; i<max; i++){
a[i] = 0;
b[i] = 0;
sum[i] = 0;
} sum[max] = 0;
//prekopiraj stevila iz char v int tabele &obrni vrstni red
for(i=0; i<lengthA; i++){
a[i] = chara[lengthA-i-1]-'0';
}
for(i=0; i<lengthB; i++){
b[i] = charb[lengthB-i-1]-'0';
}
int vsota;
int prenos = 0;
for(i=0; i<max; i++){
vsota = a[i]+b[i] + prenos;
if(vsota>=10) prenos = 1;
else if (vsota<10) prenos = 0;
sum[i]=vsota%10;
}
if(prenos==1){
sum[max] = 1;
for(i = max; i>=0; i--){
printf("%d", sum[i]);
}
} else {
for(i = max-1; i>=0; i--){
printf("%d", sum[i]);
}
}
return 0;
}
I tried to convert a negative decimal number into a binary number and this code perfectly works on my computer, but the code doesn't work another computer.
I didn't get how it is possible. What is wrong in my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void decTobin(int dec, int s)
{
int b[s], i = 0;
while (dec >= 0 && i != s - 1) {
b[i] = dec % 2;
i++;
dec /= 2;
}
int j = i;
printf("%d", dec);
for (j = i - 1; j >= 0; j--) {
if (b[j] == NULL)
b[j] = 0;
printf("%d",b[j]);
}
}
void ndecTobin(int dec, int s)
{
int b[s], i = 0, a[s], decimal, decimalvalue = 0, g;
while (dec >= 0 && i != s-1) {
b[i] = dec % 2;
i++;
dec /= 2;
}
int j = i;
printf("%d",dec);
for (j = i - 1; j >= 0; j--) {
if (b[j] == NULL)
b[j] = 0;
printf("%d",b[j]);
}
printf("\n");
a[s - 1] = dec;
for (j = s - 2; j >= 0; j--) {
a[j] = b[j];
}
for (j = s - 1; j >= 0; j--) {
if (a[j] == 0)
a[j] = 1;
else
a[j] = 0;
printf("%d",a[j]);
}
for (g = 0; g < s; g++) {
decimalvalue = pow(2, g) * a[g];
decimal += decimalvalue;
}
decimal = decimal + 1;
printf("\n%d\n", decimal);
decTobin(decimal, s);
}
int main()
{
int a, b;
printf("enter a number: ");
scanf(" %d", &a);
printf("enter the base: ");
scanf("%d", &b);
ndecTobin(a, b);
}
decimal and int b[s] not initialized.
By not initializing decimal to 0, it might have the value of 0 on a machine one day and quite different results otherwise.
void decTobin(int dec, int s) {
// while loop does not set all `b`,but following for loop uses all `b`
// int b[s], i = 0;
int b[s] = { 0 }; // or int b[s]; memset(b, 0, sizeof b);
int i = 0;
}
void ndecTobin(int dec, int s) {
int b[s], i = 0, a[s], decimal, decimalvalue = 0, g;
decimal = 0;
...
decimal += decimalvalue;
}
Minor points:
1) if (b[j] == NULL) b[j] = 0; is strange. NULL is best used as a pointer, yet code is comparing b[j], an int to a pointer. Further, since NULL typically has the arithmetic value of 0, code looks like if (b[j] == 0) b[j] = 0;.
2) decTobin() is challenging to follow. It certainly is only meant for non-negative dec and s. Candidate simplification:
void decTobin(unsigned number, unsigned width) {
int digit[width];
for (unsigned i = width; i-- > 0; ) {
digit[i] = number % 2;
number /= 2;
}
printf("%u ", number); // assume this is for debug
for (unsigned i = 0; i<width; i++) {
printf("%u", digit[i]);
}
}
It looks like you are just printing the number as a binary representation. If so this version would work.
void print_binary(size_t n) {
/* buffer large enough to hold number to print */
unsigned buf[CHAR_BIT * sizeof n] = {0};
unsigned i = 0;
/* handle special case user calls with n = 0 */
if(n == 0) {
puts("0");
return;
}
while(n) {
buf[i++] = n % 2;
n/= 2;
}
/* print buffer backwards for binary representation */
do {
printf("%u", buf[--i]);
} while(i != 0);
}
If you don't like the buffer, you can also do it using recursion like this:
void using_recursion(size_t n)
{
if (n > 1)
using_recursion(n/2);
printf("%u", n % 2);
}
Yet another way is to print evaluating most significant bits first. This however introduces issue of leading zeros which in code below are skipped.
void print_binary2(size_t n) {
/* do not print leading zeros */
int i = (sizeof(n) * 8)-1;
while(i >= 0) {
if((n >> i) & 1)
break;
--i;
}
for(; i >= 0; --i)
printf("%u", (n >> i) & 1);
}
Different OS/processor combinations may result in C compilers that store various kinds of numeric variables in different numbers of bytes. For instance, when I first learned C (Turbo C on a 80368, DOS 5) an int was two bytes, but now, with gcc on 64-bit Linux, my int is apparently four bytes. You need to include some way to account for the actual byte length of the variable type: unary operator sizeof(foo) (where foo is a type, in your case, int) returns an unsigned integer value you can use to ensure you do the right number of bit shifts.