5月7号修改:
针对5月6号出现的问题二对程序做了改进。主要体现在:
当我输入85.99,程序执行到处理小数部分时,计算机实际上存储的数字为0.98999999999999488;当我输入5.99,程序执行到处理小数部分时,计算机实际上存储的数字为0.99000000000000021,但是能输出正确结果。虽然知道用二进制数表示小数并不能做到完全相等,但似乎如果误差小于一个特定的值,计算机还是能输出我们想要的结果。于是我加了这么一个判断,运算结果是我们想要的。
题外话:很奇怪的一件事,在这个程序中,小数部分的误差与前面整数大小成正比例;而且在while循环里,误差越来越大。
if(abs(1 - dMoney)>0.0000000000000001 && abs(1 - dMoney)<=0.001){
mMoney ++;
}
5月6号修改:
在做黑盒测试时,发现了一些问题:
1):当我输入.00时,虽然含有小数,但应该输出错误信息,实际输出整;但当我输入0.00时,能识别输入信息不能为0;
2):当我输入85.99时,输出八十五元九角八分
3):当我输入0.85时,提示输入” 请输入具体的数值,且不能为零 “的错误
针对第一、三问题,我修改了isAvailable()函数中一些判断逻辑,使其能处理0开头的非零数字;针对第二个问题,暂时还没有想到更好的解决办法,不知你们有没有一些想法
问题是简单的,但要完全考虑到所有的情况还是有点难度的,这是我写的代码,由于水平有限,没有考虑到情况欢迎留言讨论。
首先是判断输入数据是否是有效输入,其中high和low是全局变量,分别表示整数部分的位数以及小数部分的位数
/*
此函数用于判断输入的从键盘输入的数据是否有效
当输入数据大于千亿、小数点后数字多于2个、或是含有字母时,无效输入
*/
bool isAvailable(std::string inputMoney){
std::string::iterator pInputMoney = inputMoney.begin();
//判断是否读到了小数点
bool isMeetDot = false;
bool firstMeetDot = true;
if (atof(inputMoney.c_str()) == 0){
std::cout<<"请输入具体的数值,且不能为零"<<std::endl;
return false;
}
//遍历输入的数据
for( ; pInputMoney < inputMoney.end() ; pInputMoney ++){
if (isMeetDot){
low ++;
}
if (*pInputMoney > '9' || *pInputMoney < '0'){
if (*pInputMoney == '.'){
if (firstMeetDot){
isMeetDot = true;
firstMeetDot = false;
}else{
std::cout<<"小数点只能有一个,不能有多个"<<std::endl;
return false;
}
}else{
std::cout<<"请输入数字,不能输入字符"<<std::endl;
return false;
}
}
if (!isMeetDot){
high ++;
}
}
//小数部分的位数,不能超过2,否则当作非法输入
if (low > 2){
std::cout<<"小数点后面至多两位"<<std::endl;
return false;
}
//整数部分的位数,不能超过12,否则当作非法输入
if (high > 12){
std::cout<<"输入数据过大,目前只支持仟亿"<<std::endl;
}
return true;
}
然后需要将string型数据转换为double数据
/*
string型数据转化为double型
*/
void stringTranslate2Double(string inputStr , double &inputDouble){
inputDouble = atof(const_cast<const char*>(inputStr.c_str()));
}
然后是处理double型数据,这是main函数
/*
有效测试数据:805.08 、 8005.80 、 85.00 、 85 、 8500 、 85.85 、 8050
无效测试数据:85000000000000 、 85.001 、 85..85 、 85.a8
*/
int main(){
std::string sMoney;
double dMoney;
const std::string NUM[10] = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
const std::string UNIT[] = {"分","角","元","拾","佰","仟","万","拾","佰","仟","亿","拾","佰""仟"};
for (;;){
high = 0 ;
low = 0;
int mMoney = 0;
bool FrontNumberIsZero = false;
std::cout<<"请输入待转换的数值:"<<std::endl;
std::cin>>sMoney;
//退出循环
if (sMoney == "exit"){
break;
}
if(isAvailable(sMoney)){
std::cout<<"转化后为:\t";
stringTranslate2Double(sMoney,dMoney);
//std::cout<<dMoney<<std::endl;
std::cout<<"人名币:";
//处理整数部分
while (high != 0){
mMoney = dMoney / (pow(10,high-1));
dMoney = dMoney - (pow(10,high-1)) * mMoney;
if (mMoney == 0){
FrontNumberIsZero = true;
switch (high){
case 9:
std::cout<<UNIT[high+1];
//FrontNumberIsZero = false;
break;
case 5:
std::cout<<UNIT[high+1];
//FrontNumberIsZero = false;
break;
case 1:
std::cout<<UNIT[high+1];
//FrontNumberIsZero = false;
break;
default:
break;
}
}else{
if (FrontNumberIsZero){
std::cout<<NUM[0];
}
FrontNumberIsZero = false;
std::cout<<NUM[mMoney]<<UNIT[high+1];
}
if (high == 1 && low == 0){
std::cout<<"整";
}
high--;
}
//处理小数部分,类似于对整数的处理
while (low != 0){
mMoney = dMoney * 10;
dMoney = dMoney * 10 - mMoney;
//因为计算机表示小数并不是精确的表示,所以可能会存在表示上的误差
//这个if循环是简单的处理这个误差,但不能完全的根除,这里只是提供一个经验值
if(abs(1 - dMoney) > 0.0000000000000001 && abs(1 - dMoney) <= 0.001){
mMoney ++;
}
if(mMoney == 0 ){
if (low == 1){
if (FrontNumberIsZero){
std::cout<<"整";
}
}
FrontNumberIsZero = true;
}else{
if (FrontNumberIsZero){
std::cout<<NUM[0];
}
std::cout<<NUM[mMoney]<<UNIT[low-1];
FrontNumberIsZero = false;
}
low --;
}
std::cout<<std::endl;
}
}
return 0;
}