с плавающей запятой — усечение в переполнении стека

Сегодня я пытался написать программу, которая суммирует целочисленный ввод пользователя. Например, если пользовательский ввод 683 он вернул бы 6 + 8 + 3 = 17.

Но я столкнулся с какой-то странной проблемой в моем коде

Код :


#включают

using namespace std;
int computeSum(int num);
int computeInteger(int num, int position);

int main()
{
int num;
int sum;
int total;
cin >> num;

total = computeSum(num);

cout << total;
return 0;
}

int computeSum(int num)
{
int position = 10;
int temp = num;
double total = 0;
bool finish = false;

while(!finish)
{
total = total + computeInteger(num, position);

if(num/ position == 0)
break;
position *= 10;
}

return total;
}

int computeInteger(int num, int position)
{
double subtract1 = (double) num / position; //if num = 683 and position = 10 ,     this will get 68.3
int subtract2 = num / position; //if num = 683 and position = 10 , this will get 68
double solution = subtract1 - subtract2; //take 68.3 - 68 = 0.3
return (int)(solution * 10); // return 0.3 * 10 = 3 , but instead of getting 3 this program return 0.3 * 10 = 2
}

Вопрос

  1. В приведенном выше коде, когда я ввожу 683, для функции computeIntegerвместо получения последней цифры 3 я получаю 2 в качестве возвращаемого значения. Это очень странно, так как я думал, что усечение приведет к удалению только плавающей части, а не к округлению вверх или вниз. Когда я проверяю код cout << (int)(0.3 * 10) Я получил 3, но не в коде выше. Это меня смущает.

0

Решение

двойное вычитание1 = (двойное) число / позиция;
// если num = 683 и position = 10, получится 68,3

Это не совсем верно, 0,3 не является рациональным числом в базе 2, тем, что оно будет очень близко к 0,3, но меньше, поскольку число всегда округляется в меньшую сторону, чтобы сузить ошибку, вы можете привести ее к плаванию или длинному плаванию, но это не тот случай, так как в вашем примере это всегда будет 0,29, если вы хотите понять, что на самом деле происходит, вы должны прочитать о представлении чисел в компьютерах, это очень хорошо описано здесь:

http://en.wikipedia.org/wiki/Computer_number_format

Ошибка, с которой вы столкнулись, является общеизвестной ошибкой, также описанной на вики-странице:

http://en.wikipedia.org/wiki/Round-off_error

И ссылка на стек:

Что является простым примером ошибки с плавающей запятой / округления?

5

Другие решения

В плавающей точке 68,3 не 68,3, но больше похоже на 68,299999997. Прочитать о ошибки округления с плавающей точкой.

5

Чтобы получить плавающую точку с пути:

inline int computeInteger(int num, int position) {
return (num / (position / 10)) % 10;
}
1

Нет необходимости использовать плавающую точку для этого расчета. замещать computeSum и и computeInteger с:

int computeSum(int num)
{
int sum = 0;
for (; num; num /= 10)
sum += num % 10;
return sum;
}

Примечание. Ваш код допускает отрицательные значения для num, Если вы хотите поддержать их, вам нужно будет добавить дополнительный код.

1

Да, вы правы, вы получаете 2. Позвольте мне объяснить, почему:
если num = 683, я покажу вам, что говорит отладчик для значений из вашей функции comuteInteger:

double subtract1 = (double) num / position;  // substract1=68.299999999999997
int subtract2 = num / position; // subtract2 = 68
return (int)(solution * 10); // 2.99999999999997 casted to int will be 2

Это для первого шага ..

0

Если мне придется сделать что-то подобное, я создам рекурсивную функцию, как показано ниже:

int total(int num){
if(num == 0){
return 0;
}else{
return num%10 + total(num/10);
}
}
0

Обычный подход к отбору цифр заключается в использовании n % 10 чтобы получить значение самой младшей цифры, то n /= 10 убрать самую младшую цифру. Повторите, пока не сделано.

0
По вопросам рекламы [email protected]