Деление с плавающей запятой приводит к тому, что значение, равное 1, должно быть 0,99999999, таким образом, в качестве основания используется значение 0 вместо 1, поэтому расчет требуемого изменения является неправильным.
Какой самый простой способ справиться с этим? (Также, если есть какое-то руководство / статья о том, как с этим бороться, я бы хотел ссылку для справки.)
Ex. 3.51 сломан.
Обе версии кода имеют одинаковую проблему.
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
//3.51 is broken due to floating point issue of .999999999 instead of 1. Work around?
int main(int argc, char *argv[])
{
const float DOLLARVALUE=1.0;
const float QUARTERVALUE=0.25;
const float DIMEVALUE=0.10;
const float NICKELVALUE=0.05;
const float PENNIEVALUE=0.01;
const int CELLWIDTH=12;
float totalChange=0;
int countDollars=0;
int countQuarters=0;
int countDimes=0;
int countNickels=0;
int countPennies=0;
float remainingTotal=0;cout<<"Please insert total amount of change needed: ";
cin>>totalChange;
cout<<endl;
remainingTotal=totalChange;countDollars=(remainingTotal/DOLLARVALUE);
remainingTotal=(remainingTotal-(countDollars*DOLLARVALUE));
countQuarters=(remainingTotal/QUARTERVALUE);
remainingTotal=(remainingTotal-(countQuarters*QUARTERVALUE));
countDimes=(remainingTotal/DIMEVALUE);
remainingTotal=(remainingTotal-(countDimes*DIMEVALUE));
countNickels=(remainingTotal/NICKELVALUE);
remainingTotal=(remainingTotal-(countNickels*NICKELVALUE));
countPennies=(remainingTotal/PENNIEVALUE);
remainingTotal=(remainingTotal-(countPennies*PENNIEVALUE));
//cout<<fixed<<setprecision(0);
cout<<"This amount can be given in change by:";
cout<<endl;
cout<<endl;
cout<<"Dollars"<<setw(CELLWIDTH)<<"Quarters";
cout<<setw(CELLWIDTH)<<"Dimes"<<setw(CELLWIDTH)<<"Nickles";
cout<<setw(CELLWIDTH)<<"Pennies";
cout<<endl;
cout<<"------------------------------------------------------";
cout<<endl;
cout<<setw(4)<<countDollars;
cout<<setw(CELLWIDTH)<<countQuarters;
cout<<setw(CELLWIDTH)<<countDimes;
cout<<setw(CELLWIDTH)<<countNickels;
cout<<setw(CELLWIDTH)<<countPennies;
cout<<endl;
cout<<endl;
return 0;
}
Следующая версия имеет те же проблемы в более явном виде.
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
//3.51 is broken due to floating point issue of .999999999 instead of 1. Work around?
int main(int argc, char *argv[])
{
const float DOLLARVALUE=1.0;
const float QUARTERVALUE=0.25;
const float DIMEVALUE=0.10;
const float NICKELVALUE=0.05;
const float PENNIEVALUE=0.01;
const int CELLWIDTH=12;
float totalChange=0;
float countDollars=0;
float countQuarters=0;
float countDimes=0;
float countNickels=0;
float countPennies=0;
float remainingTotal=0;cout<<"Please insert total amount of change needed: ";
cin>>totalChange;
cout<<endl;
remainingTotal=totalChange;countDollars=floor(remainingTotal/DOLLARVALUE);
remainingTotal=(remainingTotal-(countDollars*DOLLARVALUE));countQuarters=floor(remainingTotal/QUARTERVALUE);
remainingTotal=(remainingTotal-(countQuarters*QUARTERVALUE));
countDimes=floor(remainingTotal/DIMEVALUE);
remainingTotal=(remainingTotal-(countDimes*DIMEVALUE));
countNickels=floor(remainingTotal/NICKELVALUE);
remainingTotal=(remainingTotal-(countNickels*NICKELVALUE));
countPennies=floor(remainingTotal/PENNIEVALUE);
remainingTotal=(remainingTotal-(countPennies*PENNIEVALUE));
cout<<"Amount of change needed is: "<<totalChange;
cout<<endl;
cout<<endl;
//cout<<fixed<<setprecision(0);
cout<<"This amount can be given in change by:";
cout<<endl;
cout<<endl;
cout<<"Dollars"<<setw(CELLWIDTH)<<"Quarters";
cout<<setw(CELLWIDTH)<<"Dimes"<<setw(CELLWIDTH)<<"Nickles";
cout<<setw(CELLWIDTH)<<"Pennies";
cout<<endl;
cout<<"------------------------------------------------------";
cout<<endl;cout<<setw(4)<<countDollars;
cout<<setw(CELLWIDTH)<<countQuarters;
cout<<setw(CELLWIDTH)<<countDimes;
cout<<setw(CELLWIDTH)<<countNickels;
cout<<setw(CELLWIDTH)<<countPennies;
cout<<endl;
cout<<endl;
return 0;
}
Есть ли простой обходной путь для этого? Я открыт для всех идей.
Есть несколько способов легко это исправить:
Используйте целые или рациональные числа вместо чисел с плавающей точкой.
Используйте округление вместо усечения, где это применимо.
Вы можете реализовать round(x)
просто как floor(x + 0.5)
,
Не особенно подходит в вашем случае, но прямо ведет к следующему.
Вы можете округлить с точностью до десятичного знака и затем пол. Скажем, вы хотите получить значение ниже 0,9999 до 0, но 0,9999 или что-то более высокое должно быть равно 1. Тогда все, что вам нужно, это использовать floor(x + 0.0001)
вместо floor(x)
,
Других решений пока нет …