I agree with Anders Abel and Johannes Schaub; I also think that it cannot be guaranteed that in case of an error the main one will remain untouched, so you can consider adding principal=0.0; at the beginning of the cycle.
By the way, to do this kind of work, I usually use this template function:
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result) { do { Os<<Prompt.c_str(); if(Is.fail()) { Is.clear(); Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); } Is>>Result; if(Is.fail()) Os<<FailString.c_str(); } while(Is.fail()); } template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString) { InType temp; AcquireInput(Os,Is,Prompt,FailString,temp); return temp; }
The first overload may be preferable if you want to avoid copying, the second may be more convenient for built-in types. Examples of using:
//1st overload double aDouble; AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",aDouble); //2nd overload (more convenient, in this case and in general with POD) double aDouble=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
In your case, you can change your code as follows:
double principal=0.0; const char * errMsg="Plese enter a number greater than zero. Please try again.\n"; while(principal<=0.0) { principal=0.0; principal=AcquireInput(cout,cin,"Please enter the loan principal: ",errMsg); if(principal<=0.0) cout<<errMsg; }