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.
Related
I'm making a function that takes a value using scanf_s and converts that into a binary value. The function works perfectly... until I put in a really high value.
I'm also doing this on VS 2019 in x64 in C
And in case it matters, I'm using
main(int argc, char* argv[])
for the main function.
Since I'm not sure what on earth is happening, here's the whole code I guess.
BinaryGet()
{
// Declaring lots of stuff
int x, y, z, d, b, c;
int counter = 0;
int doubler = 1;
int getb;
int binarray[2000] = { 0 };
// I only have to change things to 1 now, am't I smart?
int binappend[2000] = { 0 };
// Get number
printf("Gimme a number\n");
scanf_s("%d", &getb);
// Because why not
printf("\n");
// Get the amount of binary places to be used (how many times getb divides by 2)
x = getb;
while (x > 1)
{
d = x;
counter += 1;
// Tried x /= 2, gave me infinity loop ;(
x = d / 2;
}
// Fill the array with binary values (i.e. 1, 2, 4, 8, 16, 32, etc)
for (b = 1; b <= counter; b++)
{
binarray[b] = doubler * 2;
doubler *= 2;
}
// Compare the value of getb to binary values, subtract and repeat until getb = 0)
c = getb;
for (y = counter; c >= 1; y--)
{
// Printing c at each subtraction
printf("\n%d\n", c);
// If the value of c (a temp variable) compares right to the binary value, subtract that binary value
// and put a 1 in that spot in binappend, the 1 and 0 list
if (c >= binarray[y])
{
c -= binarray[y];
binappend[y] += 1;
}
// Prevents buffer under? runs
if (y <= 0)
{
break;
}
}
// Print the result
for (z = 0; z <= counter; z++)
{
printf("%d", binappend[z]);
}
}
The problem is that when I put in the value 999999999999999999 (18 digits) it just prints 0 once and ends the function. The value of the digits doesn't matter though, 18 ones will have the same result.
However, when I put in 17 digits, it gives me this:
99999999999999999
// This is the input value after each subtraction
1569325055
495583231
495583231
227147775
92930047
25821183
25821183
9043967
655359
655359
655359
655359
131071
131071
131071
65535
32767
16383
8191
4095
2047
1023
511
255
127
63
31
15
7
3
1
// This is the binary
1111111111111111100100011011101
The binary value it gives me is 31 digits. I thought that it was weird that at 32, a convenient number, it gimps out, so I put in the value of the 32nd binary place minus 1 (2,147,483,647) and it worked. But adding 1 to that gives me 0.
Changing the type of array (unsigned int and long) didn't change this. Neither did changing the value in the brackets of the arrays. I tried searching to see if it's a limit of scanf_s, but found nothing.
I know for sure (I think) it's not the arrays, but probably something dumb I'm doing with the function. Can anyone help please? I'll give you a long-distance high five.
The problem is indeed related to the power-of-two size of the number you've noticed, but it's in this call:
scanf_s("%d", &getb);
The %d argument means it is reading into a signed integer, which on your platform is probably 32 bits, and since it's signed it means it can go up to 2³¹-1 in the positive direction.
The conversion specifiers used by scanf() and related functions can accept larger sizes of data types though. For example %ld will accept a long int, and %lld will accept a long long int. Check the data type sizes for your platform, because a long int and an int might actually be the same size (32 bits) eg. on Windows.
So if you use %lld instead, you should be able to read larger numbers, up to the range of a long long int, but make sure you change the target (getb) to match! Also if you're not interested in negative numbers, let the type system help you out and use an unsigned type: %llu for an unsigned long long.
Some details:
If scanf or its friends fail, the value in getb is indeterminate ie. uninitialised, and reading from it is undefined behaviour (UB). UB is an extremely common source of bugs in C, and you want to avoid it. Make sure your code only reads from getb if scanf tells you it worked.
In fact, in general it is not possible to avoid UB with scanf unless you're in complete control of the input (eg. you wrote it out previously with some other, bug free, software). While you can check the return value of scanf and related functions (it will return the number of fields it converts), its behaviour is undefined if, say, a field is too large to fit into the data type you have for it.
There's a lot more detail on scanf etc. here.
To avoid problems with not knowing what size an int is, or if a long int is different on this platform or that, there is also the header stdint.h which defines integer types of a specific width eg. int64_t. These also have macros for use with scanf() like SCNd64. These are available from C99 onwards, but note that Windows' support of C99 in its compilers is incomplete and may not include this.
Don't be so hard on yourself, you're not dumb, C is a hard language to master and doesn't follow modern idioms that have developed since it was first designed.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have two functions which supposedly can convert decimals to binary, however I can't seem to get them to work if the decimal is above 3 (I get weird negative numbers). I can't fully understand the code in the functions as I've only just started to learn C, however I was hoping if someone could tell me if the functions work, or if I am just not doing something right i.e. should I be using int32_t type as the value to pass into the function?
uint8_t dec_to_bin(int decimal){
int n = decimal, i, j, binno=0,dn;
dn=n;
i=1;
for(j=n;j>0;j=j/2)
{
binno=binno+(n%2)*i;
i=i*10;
n=n/2;
}
return binno;
}
uint8_t dec_to_bin2(int decimal){
long long binaryNumber = 0;
int remainder, i = 1;
while (decimal!=0){
remainder = decimal%2;
decimal /= 2;
binaryNumber += remainder*i;
i *= 10;
}
return binaryNumber;
}
Unfortunately I have no way to find out the values of the binary numbers as a uint_8 type as I am doing this on a micro-controller and there is no way to debug or print values anywhere (I have posted numerous threads asking how to do this, with no luck). We have however been provided with another function:
int bin_to_dec(uint64_t binary) {
int result = 0;
for ( int i = 7; i >= 0; i-- ) {
result = result * 10 + ((binary >> i) & 1);
}
return result;
}
This function converts the binary number back to an integer so I can display it on the screen with a library function (the library function can only display integers or strings). If I pass 10 into either of the decimal to binary converter functions, then pass the uint_8 value from either function to the binary to decimal converter and print to the LCD, I get -3110. This should just be 1010.
I'm sorry to say, but your dec_to_bin and dec_to_bin2 functions are meaningless. Throw them away. They might -- might -- have a tiny bit of value as a teaching exercise. But if you're trying to write actual code for a microcontroller to actually do something, you don't need these functions, and you don't want these functions. (Also you need to understand why you don't need these functions.)
The problem is not that they're implemented wrongly. They're fundamentally flawed in their very intent.
These functions seem to convert, for example, the integer 5 to the integer 101, and at first glance that might look like "decimal to binary conversion", but it's not. You've just converted the number five to the number one hundred and one.
Let's look at this a different way. If I say
int i = 17;
and if I then call
printf("%d\n", i);
I see the value "17" printed, as I expect. But I can also call
printf("%x\n", i);
and this prints i's value in hexadecimal, so I see "11". Did I just convert i from decimal to hexadecimal? No, I did not! I took the same number, "seventeen", and I printed it out in two different ways: in decimal, and in hexadecimal.
For all practical purposes, unless you're designing the actual hardware a program will run on, it really doesn't make sense to ask what base a number is stored in. A variable like int i is just a number, an integer. (Deep down inside, of course, on a conventional processor we know it's stored in binary all the time.)
The only time it makes sense to explicitly convert a number to binary is if you want to print it out in a human-readable text representation, in binary. In that case, you're converting from an integer to a string. (The string will consist of the characters '0' and '1'.)
So if you want to write a meaningful decimal-to-binary converter (which will actually be an anything-to-binary converter), either have it print the binary number out to the screen, or store it in a string (an array of characters, or char []).
And if you're in a class where you're being asked to write uint8_t dec_to_bin(int decimal) (or where your instructor is giving you examples of such functions), I can't help you, and I'm afraid you're doomed. Half of what this instructor is teaching you is wrong or badly misleading, will seriously handicap you from ever being a successful C programmer. Of course I can't tell you which half, because I don't know what other lies you're being taught. Good luck -- you'll need it! -- unlearning these false facts later.
I don't know why you're trying to store binary data as base 10 numbers instead of just printing or storing (as a char[]) the bits of an int (get kth bit of n as (n >> k) & 1 then print/store), but I'll assume it's necessary.
Your solution could be prone to overflowing the uint8_t as mentioned in the comments. Even a uint64_t can only hold 19 bits of binary data in the format you're using, less than the 32 of typical ints. The return type of your second function is still uint8_t, this might just be a typo, but it means the internal representation of long long will be implicitly cast on return.
I've written some functions based on yours, but with a little more bit manipulation that work for me.
uint64_t dec_to_bin (int n)
{
uint64_t result = 0;
int k, i;
// 64 bits can only hold 19 (log10(2^64)) bits in this format
for (i = 0, k = n; k && i < 19; i++) {
// Because the loop is limited to 19 we shouldn't need to worry about overflowing
result *= 10;
result += (n >> i) & 1;
k /= 2;
}
return result;
}
int bin_to_dec (uint64_t n)
{
int result = 0;
while (n) {
result <<= 1;
result += n % 2;
n /= 10;
}
return result;
}
I tested your functions on the input 43 on my system and got
43 // Original Input
101011 // dec_to_bin2 with long long return type
10010011 // bin_to_dec
With an appropriately sized output, your dec_to_bin2 function does work as expected.
And my functions:
43 // Original Input
110101 // dec_to_bin
43 // bin_to_dec
The endianness may not be what you're expecting, but that can be changed if necessary.
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).
I'm creating a change counter program for my C++ class. The numbers we are using are in the 10s of trillions and I was wondering if there was an easy way to store that into a floating point type variable then cast that into an integer type. It isn't an integer literal, it's accepted as an input and I expect possible change.
Don't use floats. Keep it as an integer and use 64-bit longs. Use "long long" or "int64_t" as the type for storing these integers. The latter can be used by #include <stdint.h>
int main()
{
long long x = 1450000000000LL;
printf("x == %lld\n", x);
return 0;
}
Uhm. No :D
You can however use matrices and write functions for the mathematical operations you need to use. If you're doing a lot or arithmetic with very large numbers, have a look at http://gmplib.org/
If you use floating point math to represent your change counter you'll get in serious troubles. Why? - You are a victim of accuracy problems that lead to problems representing values differing in the 1s, 10s and 100s and so on up to (IIRC) 10^6 of the values. (assuming you are referring to 10^12 version of the term 'trillion'. See H. Schmidt's IEEE 754 Converter page and the Wikipedia article about thisif you want deeper insight into this)
So if you need a precision that goes higher than a several million (and I assume you do), you'll really get in hot water if you use such a beast like floating points. You really need something like the (multiple precision library from GNU in order to be able to calculate the numbers. Of course you are free to implement the same functionality yourself.
In your case mabye a 64-bit integer could do it. (Note that long long is not always 64 bit and nonstandard for C89) Just parse the user input yourself by doing something like this (untested, just to illustrate the idea):
const char input[] = "14.5"
uint64_t result = 0;
uint64_t multiplier = 1000000000000;
unsigned int i = 0;
/* First convert the integer part of the number of your input value.
Could also be done by a library function like strtol or something
like that */
while ((input[i] != '.')
&& (input[i] != '\0'))
{
/* shift the current value by 1 decimal magnitude and add the new 10^0 */
result = (result * 10) + (input[i] - '0');
i++;
}
/* Skip the decimal point */
if (input[i] == '.')
{
i++;
}
/* Add the sub trillions */
while (input[i] != '\0')
{
/* shift the current value by 1 decimal magnitude and add the new 10^0 */
result = (result * 10) + (input[i] - '0');
multiplier /= 10; // as this is just another fraction we have added,
// we reduce the multiplier...
i++:
}
result = result * multiplier;
Of course there are a several exceptions that need to be handled seperatly like overflows of the result or handling non numeric characters properly but as I noted above, the code is only to illustrate the idea.
P.S: In case of signed integers you have to handle the negative sign too of course.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Decimal to Binary conversion
I need to convert a 20digits decimal to binary using C programming. How do I go about it. Really, I am finding it hard. What buffer will I create, because it will be very large, even the calculator can't compute converting 20 digits to Binary.
I need suggestions, links and possibly sample codes.
Thanks.
Do you need to convert a decimal string to a binary string or to a value?
Rule of thumb 10^3 ~= 2^10, therefore 10^20 ~= 2^70 > 64 bits (67 to be accurate).
==> A 64bit integer will not not be enough. You can you a structure with 2 64bit integers (long long in C) or even a 8bit byte for the upper part and 64 for the lower part.
Make sure the lower part is unsigned.
You will need to write code that checks for overflow on lower part and increases upper part when this happens. You will also need to use the long division algorithm once you cross the 64bit line.
What about using a library for extended precision arithmetic? try to give a look at http://gmplib.org/
I don't know if you are trying to convert a string of numerical characters into a really big int, or a really big int into a string of 1s and 0s... but in general, you'll be doing something like this:
for (i = 0; i < digits; i++)
{
bit[i] = (big_number>>i) & 1;
// or, for the other way around
// big_number |= (bit[i] << i);
}
the main problem is that there is no builtin type that can store "big_number". So you'll probably be doing it more like this...
uint8_t big_number[10]; // the big number is stored in 10 bytes.
// (uint8_t is just "unsigned char")
for (block = 0; block < 10; block++)
{
for (i = 0; i < 8; i++)
{
bit[block*8 + i] = (big_number[block]>>i) & 1;
}
}
[edit]
To read an string of numerical characters into an int (without using scanf, or atoi, etc), I would do something like this:
// Supposing I have something like char token[]="23563344324467434533";
int n = strlen(token); // number of digits.
big_number = 0;
for (int i = 0; i < n; i++)
{
big_number += (token[i] - '0') * pow(10, n-i-1);
}
That will work for reading the number, but again, the problem with this is that there is no built-in type to store big_number. You could use a float or a double, and that would get the magnitude of the number correct, but the last few decimal places would be rounded off. If you need perfect precision, you will have to use an arbitrary-precision integer. A google search turns up a few possible libraries to use for that; but I don't have much personal experience with those libraries, so I won't make a recommendation.
Really though, the data type you use depends on what you want to do with the data afterwards. Maybe you need an arbitrary-precision integer, or maybe a double would be exactly what you need; or maybe you can write your own basic data type using the technique I outlined with the blocks of uint8_t, or maybe you're better off just leaving it as a string!