Reputation:
My code compiled successfully, but any time I run the argument ./base.o 42 2
, which converts it to base 2
in binary, the output is 0
, and anytime I run ./base.o 99 5
, the result is 444
repeatings.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
int remainder = 0;
int num0 = 0;
int i = 0;
int num1 = atoi(argv[1]);
int num2 = atoi(argv[2]);
int quotient = num1;
while (quotient != 0) {
remainder = num1 % num2;
quotient = quotient / num2;
num0 = (remainder * pow(10, i)) + num0;
i++;
}
printf("%d\n", num0);
return 0;
}
Upvotes: 0
Views: 194
Reputation: 144770
There are multiple issues in the code:
int num1 = atoi(argv[1]);
and int num2 = atoi(argv[2]);
are correct, assuming there are at least 2 arguments: you should test the actual number of arguments received by the program.remainder = num1 % num2;
instead of remainder = quotient % num2;
so you always get the last digit replicated.Here is a modified version:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int remainder[sizeof(int) * CHAR_BIT];
int num1, num2, quotient, i;
const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
if (argc > 2) {
num1 = atoi(argv[1]);
num2 = atoi(argv[2]);
if (num2 < 2 || num2 > 36) {
printf("invalid base: %d\n", num2);
return 1;
}
quotient = num1;
i = 0;
/* using a for(;;) loop instead of `while (quotient != 0)` to
produce at least 1 digit for quotient == 0
*/
for (;;) {
/* using abs to handle negative numbers all the way to INT_MIN */
remainder[i++] = abs(quotient % num2);
quotient = quotient / num2;
if (quotient == 0)
break;
}
if (num1 < 0) {
putchar('-');
}
while (i > 0) {
putchar(digits[remainder[--i]]);
}
putchar('\n');
}
return 0;
}
Upvotes: 1
Reputation: 4816
This looked like a fun question to work on, and I see during the time I was refactoring the initial program that other good alternatives have been offered up. To that mix, I offer up this refactored version of the base conversion program.
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
char derive(int digit)
{
char value;
if (digit < 10)
{
value = (char)digit + '0';
}
else
{
switch(digit)
{
case 10:
value = 'A';
break;
case 11:
value = 'B';
break;
case 12:
value = 'C';
break;
case 13:
value = 'D';
break;
case 14:
value = 'E';
break;
case 15:
value = 'F';
break;
default:
value = '*';
break;
}
}
return value;
}
int main(int argc, char *argv[]) {
char cnv[MAX];
int remainder = 0;
int num0 = 0;
int i = 0;
int num1 = atoi(argv[1]);
int num2 = atoi(argv[2]);
int quotient = num1;
if (num2 < 2 || num2 > 16)
{
printf("Currently, only base numbers from 2 to 16 are allowed\n");
return 0;
}
num0 = num2;
for (int j = 0; j < MAX; j++) /* Initialize the character array to terminator values */
{
cnv[j] = '\0';
}
while (1) /* Determine the largest power of the base needed for deriving a converted value */
{
num0 = num0 * num2;
if (num0 > num1)
{
num0 = num0 / num2;
break;
}
}
while (num0 >= num2) { /* Work down from the highest base power to derive the base value */
remainder = num1 % num0;
quotient = quotient / num0;
cnv[i] = derive(quotient);
quotient = remainder;
num0 = num0 / num2;
i++;
}
cnv[i] = derive(remainder); /* Finish by storing the "units" value */
printf("%s\n", cnv);
return 0;
}
A few bits of information to point out as to what I did to make the base conversion function.
So instead of working up with the power function, this method derives the needed largest power of the base value needed and works its way back down through the division and decrement process.
Testing out the program against the original values presented in the question produced the following terminal output.
@Vera:~/C_Programs/Console/Base/bin/Release$ ./Base 42 2
101010
@Vera:~/C_Programs/Console/Base/bin/Release$ ./Base 99 5
344
Anyway, you might want to evaluate this refactored version along with the other presented solutions to see if it meets the spirit of your project.
Upvotes: 0
Reputation: 10048
Number base is just for humans to read. A number is a shorthand way of writing polynomial of increasing powers of the radix.
For example, the number 3057
with base (== radix) 10
is:
3
×103 + 0
×102 + 5
×101 + 7
×100
I can totally change the radix:
B
×162 + F
×161 + 1
×160
We see that B
(11)×16×16 plus F
(15)×16 plus 1 is 2816+240+1 = 3057 — the very same number as before.
Converting from the text representation to a numeric value is easy:
int value = 0;
for (char * s = text_number; *s; s++)
value = (value * radix) + value_of( *s );
That “value of c” thing is just to say that '7'
should be transformed to a 7
and things like 'E'
should be transformed to 15
(since the ASCII representation of a digit != that digit). This kind of thing is easiest done with a lookup table.
Going the other way is almost as easy, you just need to print the digits in the right order. It helps to have a string to hold those digits.
char buffer[ N ] = { 0 }; // where N is big enough to hold all the digits
char * s = buffer + N - 1; // start at the back
while (value)
{
*(--s) = digit_for( value % radix );
value /= radix;
}
puts( s );
Again, that “digit for” converts values like 7
to '7'
and 15
to 'E'
. Again a simple lookup table (the very same one as before, actually) is useful here.
If value is 0
we should just puts( "0" )
and avoid the loop.
Alas, in computing, life is never as simple as we would like it to be. We need to deal with things like negative numbers and INT_MIN and zeros and stuff.
For what you are doing, I wouldn’t worry about it. But if it matters, you can keep a textual representation of INT_MIN (or whatever data type you are working against) to compare against the input, and assign that value directly if the input matches it.
You can even generate this minimum value representation by converting the largest possible value, adding one to the last character in the string, and slapping a minus sign on the front of it.
Of course, if you are working over an unsigned type, you don’t need to bother.
You still need to be aware of overflow, though. If you get more digits than your resulting type can hold...
And we see where the weeds makes this stuff get kind of tricky. The basic idea is simple, just make sure to handle all the weird edge cases where stuff goes wonky.
Upvotes: 2