I found something weird.
This function puts a digit in a number at the given spot and returns the modified number. Now we want to do put_digit(123456789123456784, 0, 9); That will put 9 at the end of the number, replacing the last number (4).
This is the code that WORKS:
long long int put_digit(long long int number, char place, char digit)
{
long long int result = number;
long long int power = number;
power = pow(10, (place));
result -= get_digit(number, place)*power;
result += digit*pow(10, (place));
return result;
}
The code returns 123456789123456789
This is the code that DOES NOT WORK:
long long int put_digit(long long int number, char place, char digit)
{
long long int result = number;
result -= get_digit(number, place)*pow(10, (place));
result += digit*pow(10, (place));
return result;
}
This code returns 123456789123456800 as the result.
The functions get_digit() returns the digit from the number in the given place. This is it's code:
char get_digit(long long int number, char place)
{
long long int target = number;
char digit = 0;
target /= pow(10, place);
digit = target % 10;
return digit;
}
• This does not happen with lower numbers.
• get_digit() always returns the correct value (4 in this case).
• get_digit() is a char because this is not a counter function, and thus it is better to focus on using less memory rather than using a faster variable like int.
• I've tried using brackets to avoid troublesome operator precedence, but to no avail.
• A weird behavior is also observed when doing put_digit(123456789123456000, 2, 7), which for some reason returns 123456789123456704. This is solved by replacing the pow function in the second result calculation with the variable "power".
I just don't understand why this is happening.
Am I getting some kind of an overflow? Is it my system's fault or my own? Am I using pow() in a bad way?
The declaration of pow()
is: double pow( double base, double exponent );
In the first case:
long long int power = number;
power = pow(10, (place));
the value returned by pow()
is converted to long long int
when it is assigned power
. The rest of the computation is processed using integer numbers and the result is the one you expect.
On the second case:
result -= get_digit(number, place)*pow(10, (place));
the value returned by get_digit(number, place)
is converted to double
because it needs to be multiplied with a floating point number (returned by pow()
). Also, the value of result
is converted to double
before subtracting the result of the multiplication. In the end, the computed value is converted from double
to long long int
to be stored in result
.
But starting on some magnitude, the floating point numbers lose the precision of their least significant digit(s).
Try this simple piece of code to see for yourself:
long long int i = 123456789123456785;
for (; i <= 123456789123456795; i ++) {
printf("long long int: %lld; double: %f\n", i, (double)i);
}
It outputs:
long long int: 123456789123456785; double: 123456789123456784.000000
long long int: 123456789123456786; double: 123456789123456784.000000
long long int: 123456789123456787; double: 123456789123456784.000000
long long int: 123456789123456788; double: 123456789123456784.000000
long long int: 123456789123456789; double: 123456789123456784.000000
long long int: 123456789123456790; double: 123456789123456784.000000
long long int: 123456789123456791; double: 123456789123456784.000000
long long int: 123456789123456792; double: 123456789123456800.000000
long long int: 123456789123456793; double: 123456789123456800.000000
long long int: 123456789123456794; double: 123456789123456800.000000
long long int: 123456789123456795; double: 123456789123456800.000000
This behaviour is not a bug but a limitation of the floating point numbers.
The solution for your code is to convert the value returned by pow(10, place)
to long long int
as soon as it returns:
result -= get_digit(number, place)*(long long int)pow(10, place);