This question already has answers here:
Binary numbers with the same quantity of 0s and 1s
(6 answers)
Closed 8 years ago.
I want to convert all integers below 1048576 to binary and display all numbers which have the same number of bits set as unset. My program works fine when I use a table t of 20 integers, in which case cpt records the correct result.
However, when I use a table t of 40 integers (which means I want the numbers with 20 '1' bits and 20 '0' bits) the counter is set to 1. What is wrong?
int main(){
long int a;
int r,j,i;
long int aux;
int z,u;
long int cpt;
int t[40];
for(int k=0;k<40;k++) t[k]=0;
cpt=0;
for(a=0;a<1048576;a++){
j=0;u=0;z=0;
aux=a;
do{
r=aux%2;
switch(r){
case 0 : t[j]=0;
aux=(aux/2);
j++;
break;
case 1 : t[j]=1;
aux=((aux-1)/2);
j++;
break;
}
}while(aux!=0);
for(i=0;i<40;i++){
if(t[i]==0) z++;
else u++;
}
if(z==u) cpt++;
}
printf("%d",cpt);
getchar();
}
Your loop only goes to 1048576, which is 2^20.
Don't you need to loop until 2^40?
Also, note that int may not be 40 bits wide.
Note:
The naive solution to check all numbers doesn't scale well. Perhaps you should consider a smarter solution?
Because only one number in the range [0, 1048576) has exactly as many bits 1 as 0, when counted in your 40 "bit" array.
The flaw in your logic is that you do not examine all numbers in a given range. For instance, when you want to examine all 40-bit integers, you need to iterate until 2^40 and not 2^20.
Lastly, this brute force solution won't work very well for your problem. Instead, try to consider the pattern that appears when you examine the number of paths from the top-left node and proceeding to the down or right for a small array on a piece of paper. Does one emerge? If you're math-inclined, you will instantly recognise it; otherwise, take a minute to look through the binomial coefficients.
As others have said, the main thing that is wrong is the algorithm you are using (exhaustive search); you would need to loop from 0 to 240-1 to iterate across the entire set of numbers to be tested (rather than to 220-1), which would be an impractical number of iterations, not least as there are faster ways.
Consider the maths of the problem: you want a 40 bit field, with 20 bits set to 1. So, you are choosing 20 things from 40. Think about the nCr (combination operator from permutations and combinations); that will give you the link to the binomial coefficients. Now think how you might write an algorithm to go through every combination.
Your code would also be more comprehensible if it did not have single letter variable names, and had some comments explaining what it was meant to be doing.
If you are having difficulty remembering the bit width of integer types, I suggest you use
#include <stdint.h>
and use types like int64_t which is guaranteed to be 64 bits. See:
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html
(Note that OP apparently wanted a list of the numbers with 20 bits set, rather just the count of such numbers, so merely looking at binomial coefficients is insufficient).
try using a long long int:
unsigned long long int a;
to fasten and clear a lot of code try also using popcount, it's a function that returns the number of 1-bits in x: http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
//I'm not 100% sure if the popcount will work with long long ints, but you can try.
BTW I have a question about the same euler problem #: Binary numbers with the same quantity of 0s and 1s
Related
I am currently working on a CS50 course and I am trying to make a function that can give me a number of digits in a number that I put. For example number 10323 will be 5 digits. I wrote a code for this but it seems like it doesn't work for case above 10 digits. Can I know what is wrong with this code?
P.S: CS50 uses modified C language for beginners. The language may look a little different but I think its the math that is the problem here so there should be no much difficulty looking at my code?
int digit(int x) //function gives digit of a number
{
if (x == 0)
{
return 0;
}
else
{
int dig = 0;
int n = 1;
int y;
do
{
y = x / n;
dig ++;
n = expo(10,dig);
}
while (y < 0 || y >= 10);
return dig;
}
}
You didn't supply a definition for the function expo(), so it's not possible to say why the digit() function isn't working.
However, you're working with int variables. The specification of the size of the int type is implementation-dependent. Different compilers can have different sized ints. And even a given compiler can have different sizes depending on compilation options.
If the particular compiler your CS50 class is using has 16-bit ints (not likely these days but theoretically possible), those values will go from 0 (0x0000) up to 32767 (0x7FFF), and then wrap around to -32768 (0x8000) and up to 01 (0xFFFF). So in that case, your digit function would only handle part of the range up to 5 decimal digits.
If your compiler using 32-bit ints, then your ints would go from 0 (0x00000000) up to 2147483647 (0x7FFFFFFF), then wrap around to -2147483648 (0x80000000) and up to -1 (0xFFFFFFFF), thus limited to part of the 10-bit range.
I'm going to go out on a limb and guess that you have 32-bit ints.
You can get an extra bit by using the type unsigned int everywhere that you are saying int. But basically you're going to be limited by the compiler and the implementation.
If you want to get the number of decimal digits in much larger values, you would be well advised to use a string input rather than a numeric input. Then you would just look at the length of the string. For extra credit, you might also strip off leading 0's, maybe drop a leading plus sign, maybe drop commas in the string. And it would be nice to recognize invalid strings with unexpected non-numeric characters. But basically all of this depends on learning those string functions.
"while(input>0)
{
input=input/10;
variable++;
}
printf("%i\n",variable);"
link an input to this.
Why this code terminated and crashed to evaluate the number of bits?
int main(void)
{
int y = 94;
int m = bitCount(y);
printf("%d",m);
return 0;
}
int bitCount(int val)
{
int i = 0;
if(!bitCount(val/2))
i++;
return i;
}
Recursive functions work by breaking the problem into smaller parts. It looks like you're trying to break the problem into smaller parts by dividing it by 2. That can work, but you have to keep two things in mind:
You have to count the bits in both parts. For example, if you call bitCount(val/2), that's fine: you've just called bitCount() on a smaller problem, on all but the last bit of val. But what about the last bit that you just threw away? You have to count it if it's 1. (Hint: val%2).
You can't make recursive calls forever. In this case: if val is less than 2, then val/2 will be 0, so there are no 1 bits in it, so there's no need to call bitCount(val/2) to discover that. So you need to "break the recursion" by not calling bitCount in that case.
As I said, this can work, but it's not a particularly good example of a recursive function, because the "breaking it into smaller parts" piece is pretty lopsided. This algorithm will make as many recursive calls as there are bits in the number; it ends up having roughly the same time complexity ("big O") as a straightforward, linear algorithm. Ideally you'd break the number into two halves based on the number of bits, not based on the number.
In other words, in your example, 94 in binary is 1011110, and you're breaking it into the two subproblems 101111 and 0. It'd be better to break it into, say, 1011 and 110.
I don't know of an easy way to do that; splitting a number in half that way is probably about as hard as counting bits in the first place, so there's little advantage. Another possibility is to break off, say, the bottom 4 bits each time, by calling bitCount(val/16) (equivalently, bitCount(val>>4)).
I did a simple program where you can count a number of bits, I will assume you were talking about the 1s and 0s. If not, well I'm dumb :P
bitCount function using recursion:
int bitCount(unsigned int x, int count) {
if (n==0) return count;
if (n%2==1) bitCount(n/2,count+1);
else bitCount(n/2,count);
}
Calling the fuction on main:
int main() {
unsigned int x=94;
int counting = 0;
printf ("Result of bits: %d \n", bitCount(x,counting));
return 1;
}
With the unsigned int = 94, it will return 5. I hope it was that you wanted :)
So I have been told that this can be done and that bitwise operations and masks can be very useful but I must be missing something in how they work.
I am trying to calculate whether a number, say x, is a multiple of y. If x is a multiple of y great end of story, otherwise I want to increase x to reach the closest multiple of y that is greater than x (so that all of x fits in the result). I have just started learning C and am having difficulty understanding some of these tasks.
Here is what I have tried but when I input numbers such as 5, 9, or 24 I get the following respectively: 0, 4, 4.
if(x&(y-1)){ //if not 0 then multiple of y
x = x&~(y-1) + y;
}
Any explanations, examples of the math that is occurring behind the scenes, are greatly appreciated.
EDIT: So to clarify, I somewhat understand the shifting of bits to get whether an item is a multiple. (As was explained in a reply 10100 is a multiple of 101 as it is just shifted over). If I have the number 16, which is 10000, its complement is 01111. How would I use this complement to see if an item is a multiple of 16? Also can someone give a numerical explanation of the code given above? Showing this may help me understand why it does not work. Once I understand why it does not work I will be able to problem solve on my own I believe.
Why would you even think about using bit-wise operations for this? They certainly have their place but this isn't it.
A better method is to simply use something like:
unsigned multGreaterOrEqual(unsigned x, unsigned y) {
if ((x % y) == 0)
return x;
return (x / y + 1) * y;
}
In the trivial cases, every number that is an even multiple of a power of 2 is just shifted to the left (this doesn't apply when possibly altering the sign bit)
For example
10100
is 4 times
101
and
10100
is 2 time
1010
As for other multiples, they would have to be found by combining the outputs of two shifts. You might want to look up some primitive means of computer division, where division looks roughly like
x = a / b
implemented like
buffer = a
while a is bigger than b; do
yes: subtract a from b
add 1 to x
done
faster routines try to figure out higher level place values first, skipping lots of subtractions. All of these routine can be done bitwise; but it is a big pain. In the ALU these routines are done bitwise. Might want to look up a digital logic design book for more ideas.
Ok, so I have discovered what the error was in my code and since the majority say that it is impossible to calculate whether a number is a multiple of another number using masks I figured I would share what I have learned.
It is possible! - if you are using the correct data types that is.
The code given above works if y is declared as a constant unsigned long as x which was being passed in was also an unsigned long. The key point is not the long or constant part but that the number is unsigned. This sign bit causes miscalculation as the first place in the number indicates sign and when performing bitwise operations signs can get muddled.
So here is my code if we are looking for multiples of 16:
const unsigned long y = 16; //declared globally in my case
Then an unsigned long is passed to the function which runs the following code:
if(x&(y-1)){ //if not 0 then multiple of y
x = x&~(y-1) + y;
}
x will now be the size of the nearest multiple of 16.
I am trying to convert decimal Nos. into binary. The code works pretty fine (Windows 7 , 32 bit MS-VS2010):
int main()
{
int k, n;
int binary[100];
printf("Enter the value in decimal \n ");
scanf("%d", &k);
n = (log(k * 1.0) / log(2 * 1.0)) + 1 ; //total no. of binary bits in this decimal
for (int i = n; i > 0; i--)
{
binary[i] = k % 2;
k /= 2;
}
return 0;
}
But the limitation is that it works for Int size values only i.e. 32 bit. I want to modify this code so that it works for 2048 bits (decimal numbers containing 617 digits actually). I am not allowed to use any library.
Can someone give me some pointers how to proceed to tackle this?
Can someone give an example code snippet say for 64 bits ? Then I can use this to extend to higher values.
Update
1-As per suggestions I am trying to use strings. But I am not able to understand how to convert an String into large Int (I cant use stoi() as thsi will convert to 32 bit int , right? ).
2- Secondly I have to find:
log(222121212213212313133123413131313131311313154515441315413451315641314563154134156313461316413415635154613415645156451434)
Is the library function log capable of finding this ? Then what is the solution?
Since you told that you just need some pointers and not the actual answer, here goes:
I am not able to understand how to convert an String into large Int
That's because you can't. If you want to convert a number that huge to a numerical type, in the first place you need such a type that can hold numbers that big. The language doesn't provide you anything more than long long which is usually 128-bits long (i.e. if you can use C99, or just long which is usually lesser than a long long). Since your tutor told you not to use any external library, it's a clear sign that s/he wants you to code the solution using what's available only in the language and perhaps additionally the standard library.
Is the library function log capable of finding this
No, you can't use stoi or log since all of these expect arguments of some arithmetic type, while none of those built-in types are that big to hold numbers this huge. So you've to work completely with strings (i.e. either static or dynamic char buffers).
I understand that you want to use log to deduce the number of digits the binary output would need; but there's another option, which is to not know the number of digits before hand and allocate them dynamically with some upper bound so that you needn't re-allocate them further.
Lets take an example.
Allocate 3 char buffers in, out (length of input) and bin (length of input * 4).
Copy input to in
While in is not "0" or "1" do else goto 12
For each element ch in in do else goto 10
Convert ch to integer i
If is_odd = 1 then i += 10
quot = i / 2
Append quot to out
is_odd = quot % 2; goto 4
If is_odd = 1 append '1' else '0' to bin
Copy out to in, reset out and goto 3
Append in to bin
Print bin in reverse
When you integer divide a number by 2, the quotient would always be less than or equal to the number of digits of the dividend. So you could allocate in and out with the same size as the input and use it for all iterations. For the bin buffer, the knowledge that each decimal digit wouldn't take more than 4 bits (9 takes a nibble, 1001) would help. So if the input is 10 digits, then 10*4 = 40 bytes would be the upper limit needed for bin buffer and 10 bytes would be needed for the in and out buffers.
This is a vague write-up of an algorithm, I hope it conveys the idea. I feel writing code is more easier than writing algorithms properly.
I'm afraid there are no standard types in C that will allow you to store such a big value with 20148 bits... You can try to read the string from console (not converting into int), and then parse the string into "010101...." on your own.
The approach would be like that:
You should go for "dividing" the string by 2 in each step (for each division by 2 you need to divide all digits of the string by 2, and handle special cases like 11 / 2 => 5), and for each step if the value cannot be divided by 2, then you then you can put "1" as another binary digit, otherwise you put "0". This way you gather the digits '0', '1', '0', '1', etc. one by one. Then finally you need to reverse the order of digits. A similar approach implemented in C# you can find here: Decimal to binary conversion in c #
Regarding the update:
Grinding it through WolframAlpha gives:
log(222121212213212313133123413131313131311313154515441315413451315641314563154134156313461316413415635154613415645156451434)
is roughly
274.8056791141317511022806994521207149274321589939103691837589..
Test:
Putting it into exp gives:
2.2212121221321231313312341313131313131131315451544131541.. × 10^119
This raises the question about the precision you need.
Note: I assumed you mean the natural logarithm (base e).
Problem: Find the number of integers 1 < n < 10^7, for which n and n + 1 have the same number of positive divisors. For example, 14 has the positive divisors 1, 2, 7, 14 while 15 has 1, 3, 5, 15.
I can't reach 10^7 because it is too big number for C and me. How can i solve this problem in C?
#include<stdio.h>
#include<conio.h>
int divisorcount(int);
int main()
{
int number,divisornumber1,divisornumber2,j=0;
for(number=1;number<=100;number++){
divisornumber1=divisorcount(number);
divisornumber2=divisorcount(number-1);
if(divisornumber1==divisornumber2){
printf("%d and %d\n",number-1,number);
j++;
}
}
printf("\nThere is %d integers.",j);
getch();
}
int divisorcount(int num)
{
int i,divi=0;
for(i=1;i<=(num)/2;i++)
if(num%i==0)
divi++;
return divi;
}
As a hint to how to solve the problem within a minute, you can go through each number from 2 to 10^7, loop through all multiples of the those numbers and increment by 1 (1 is ignored, since all numbers are multiple of 1). In the end, you will get the number of divisors of each of the numbers in the array (check whether your compiler support 32-bit index). Just use a final linear scan to count.
Ever tried long long num = 100000000LL;? C isn't smart enough to conclude the type on the right side from the left long long so you have to add the LL. With this approach you should be able to handle larger numbers than normal integers, just change your functions and variables in a suitable way.
A long long is always at least 2^64 bit in size which you can check on Wikipedia.
Hint: As someone mentioned in the comments, Project Euler is not about bruteforcing. This is a lame approach. Think about some better strategies. You might want to get help at math.stackexchange?
EDIT: I don't know why I thought, that a uint32_t is not enough for 10^7 - sorry for that mistake.
To expand on nhahtdh's idea, to make it even faster (at cost of making it more complicated), make a prime number sieve calculating the prime numbers up to sqrt(10^7) = about 3170. Then the exponents of prime factors determine the number of multiples so that the product of (exp+1) is the number of integers dividing the number. So you can set an array to ones, then loop over each prime, multiplying with that primes exponent contribution (plus one) for each position it multiplies.