I am currently writing a program in C to convert numbers between bases as an exercise. It asks the user for an input and for the base, that the number given is. It then gives the input into the following function and prints the result.
int convert_to_decimal(char* source, int base) {
int result = 0;
// Bei jeder Addition zu result wird einmal mit sign multipliziert
int sign = 1;
if (source[0] == '-') {
sign = -1;
source++; // Wir überspringen das Vorzeichen bei der Konvertierung
}
int n = strlen(source);
int i = n - 1; // Wir starten bei der letzten Ziffer
while(i >= 0) {
int c = char_to_int(source[i]);
if(c == -1) {
printf("Invalid character in input: %c\n", source[i]);
return 0;
}
if(c >= base) {
printf("Character %c out of range for base %d\n", source[i], base);
return 0;
}
printf("Current char: %c, int value: %d, position: %d\n", source[i], c, i);
printf("Rechenschritt: %d * %d * %d^%d\n", sign, c, base, n - 1 - i);
printf(" = %d * %d * %.0f\n", sign, c, pow(base, n - 1 - i));
result += c * pow(base, n - 1 - i) * sign;
printf("Current result: %d\n", result);
i--;
}
return result;
}
All my manuel tests looked correct when I tested the program, but once I returned today to write some comments for myself I stumbled upon some weird outputs for specific numbers. When entering something like 12 with base 10 or 99 with base 10 we get the correct result. But somehow when I enter:
Enter the number to convert: 100
Enter the base of the number (2 for binary, 10 for decimal, 16 for hexadecimal): 10
I don't get back the 100, but rather a 99:
Current char: 0, int value: 0, position: 2
Rechenschritt: 1 * 0 * 10^0
= 1 * 0 * 1
Current result: 0
Current char: 0, int value: 0, position: 1
Rechenschritt: 1 * 0 * 10^1
= 1 * 0 * 10
Current result: 0
Current char: 1, int value: 1, position: 0
Rechenschritt: 1 * 1 * 10^2
= 1 * 1 * 100
Current result: 99
The decimal value is: 99
So there should be something weird happening with pow(base, n - 1 - i) for 10^2, but when I enter 199 base 10 I get the CORRECT result.
[...]
Current result: 99
Current char: 1, int value: 1, position: 0
Rechenschritt: 1 * 1 * 10^2
= 1 * 1 * 100
Current result: 199
The decimal value is: 199
I suspect that there is an issue when adding up the result, since the output of pow seems to be correct (When adding printf("%.17g\n", pow(base, n - 1 - i));):
Enter the number to convert: 199
Enter the base of the number (2 for binary, 10 for decimal, 16 for hexadecimal): 10
Current char: 9, int value: 9, position: 2
Rechenschritt: 1 * 9 * 10^0
= 1 * 9 * 1
1
Current result: 9
Current char: 9, int value: 9, position: 1
Rechenschritt: 1 * 9 * 10^1
= 1 * 9 * 10
10
Current result: 99
Current char: 1, int value: 1, position: 0
Rechenschritt: 1 * 1 * 10^2
= 1 * 1 * 100
100
Current result: 199
The decimal value is: 199
I'm on Windows 11 and used gcc to compile
Why is this happening, can somebody please explain?
Edit:
I was asked for the result of different inputs:
PS C:\Users\youbo\Documents\obsidian\hda\Rechnerarchitektur\Übungen> .\convert_nums.exe
Enter the number to convert: 100
Enter the base of the number (2 for binary, 10 for decimal, 16 for hexadecimal): 10
Current char: 0, int value: 0, position: 2
Rechenschritt: 1 * 0 * 10^0
= 1 * 0 * 1
Using %.17g: 1
Using %a: 0x0.000000p+0
Current result: 0
Current char: 0, int value: 0, position: 1
Rechenschritt: 1 * 0 * 10^1
= 1 * 0 * 10
Using %.17g: 10
Using %a: 0x0.000000p+0
Current result: 0
Current char: 1, int value: 1, position: 0
Rechenschritt: 1 * 1 * 10^2
= 1 * 1 * 100
Using %.17g: 100
Using %a: 0x1.900000p+6
Current result: 100
The decimal value is: 100
PS C:\Users\youbo\Documents\obsidian\hda\Rechnerarchitektur\Übungen> .\convert_nums.exe
Enter the number to convert: 199
Enter the base of the number (2 for binary, 10 for decimal, 16 for hexadecimal): 10
Current char: 9, int value: 9, position: 2
Rechenschritt: 1 * 9 * 10^0
= 1 * 9 * 1
Using %.17g: 1
Using %a: 0x1.200000p+3
Current result: 9
Current char: 9, int value: 9, position: 1
Rechenschritt: 1 * 9 * 10^1
= 1 * 9 * 10
Using %.17g: 10
Using %a: 0x1.680000p+6
Current result: 99
Current char: 1, int value: 1, position: 0
Rechenschritt: 1 * 1 * 10^2
= 1 * 1 * 100
Using %.17g: 100
Using %a: 0x1.900000p+6
Current result: 199
The decimal value is: 199
3 Answers 3
The pow function performs floating point operations for exponentiation, so the result it comes up with may not be the exact integer value you expect.
Instead of using pow, create a separate function that does the same with integer types and use that:
int intpow(int base, int exp)
{
int result = 1;
while (exp) {
result *= base;
exp--;
}
return result;
}
1 Comment
pow may use floating-point operations to produce its result, so it may be slightly off.
You don't need to use powers to achieve what you want.
You are generating the number as follows:
s0 ×ばつ bn-1 + s1 ×ばつ bn-2 + ... + sn-1 * b0
For example, 456 = 4 ×ばつ 102+ 5 ×ばつ 101 + 6 ×ばつ 100.
But common factors can be factored out to obtain the following equivalent solution:
( ( s0 ) ×ばつ b + s1 ) ×ばつ b + ... + sn-1
For example, 456 = ( ( 4 ) ×ばつ 10 ) + 5 ) ×ばつ 10 + 6.
This suggests the following loop body:
result = result * base + char_to_int( source[i] );
I recommend that you attempt to implement a solution using this approach. If you're interested in seeing a complete solution (because you need help, or if you want to compare against your own), leave a comment (after a few days) and I'll post my already-written complete solution.
Comments
pow() may return a a floating point result the is just a little less than the expected integer value. When converting that double to a int, the result lops off the 0.999...999 forming an int value 1 less than expected.
Instead, round.
// result += c * pow(base, n - 1 - i) * sign;
result += c * round(pow(base, n - 1 - i)) * sign;
// or
result += c * lround(pow(base, n - 1 - i)) * sign;
Even better, avoid floating point math for an int problem,
4 Comments
pow(10,2) is just under 100 as in 99.999999999999985789... due to a weak pow(). Converting that result to an int is 99 as conversion discards the fraction. With "199", that same 99.999.. is first added to 99 and that sum is not 198.999999999999985789..., but a rounded sum of 199.000...000. That sum converted to int is 199. Tip avoid FP functions for an integer problem and take more care when converting FP to integers.
"%a"to print to better see its exact value.printf("%.17g\n", pow(base, n - 1 - i));" --> What output do you get when trying to convert"100"?printf("%.17g\n", pow(base, n - 1 - i));yet it is the productprintf("%.17g\n", c * pow(base, n - 1 - i) * sign);that is more useful. Further, more direct use%aand to only have one computational path:double product = c * pow(base, n - 1 - i) * sign; printf("%a\n", product); result += product;