布置了二进制-十进制转换器的小作业,本来还要求顺手扩展一下大数的四则运算,我嫌麻烦没做扩展,就只是写来玩玩。也算熟悉一下底层的二进制-十进制转换机制,顺便复习下C++源码规范。注释写了很多,就不多做解释了,只贴代码。
converter.h:
/*
* Copyright (C) Bipedal Bit
* Verson 1.0.0.1
*/
#ifndef _CONVERTER_H_
#define _CONVERTER_H_
#include <string>
/*
* This is a class to offer operations converting radix of number in string.
*/
class Converter
{
private:
/* to store the binary form of picked up number string */
std::string binVal;
/* to store the decimal form of picked up number string */
std::string decVal;
/* to sign the number by marking wether it is negtive */
bool negtive;
/* to mark wether the number has a dot */
bool hasDot;
/* to store the index of dot in binary number string */
int binDotIndex;
/* to store the index of dot in decimal number string */
int decDotIndex;
/* max reserved digits sum when float converted from decimal to binary */
int binFloatPrecision;
/*
* Convert the binary number to decimal form then fill this->decVal.
*/
void bin2Dec();
/*
* Convert the decimal number to binary form then fill this->binVal.
*/
void dec2Bin();
public:
/*
* Constructor of the class to pick up number in string and fill both this->binVal and this->decVal.
*/
Converter(std::string str, int radix, int binFloatPrecision = 20);
/*
* Get the the number string with specified radix.
*/
std::string getNum(int radix);
};
#endif
converter.cpp:
/*
* Copyright (C) Bipedal Bit
* Verson 1.0.0.1
*/
#include "converter.h"
#include <iostream>
#include <stdexcept>
/*
* name: Converter
* args:
* string str: the original string containing target number
* int radix: the radix of the number to pick up form str
* int binFloatPrecision: max reserved digits sum when float converted from decimal to binary
* whose default value is 20
* Constructor of the class to pick up number in string and fill both this->binVal and this->decVal.
*/
Converter::Converter(std::string str, int radix, int binFloatPrecision)
{
/* check radix */
if (radix != 2 && radix != 10)
{
std::cerr << "Invalid argument: Do not support radixes beyond binary and decimal yet.\n";
return;
}
/* check binFloatPrecision */
if (binFloatPrecision < 1)
{
std::cerr << "Invalid argument: binFloatPrecision should be greater than 0.\n";
return;
}
/* fill this->binFloatPrecision */
this->binFloatPrecision = binFloatPrecision;
/* assistant variables for traversing the original string */
int len = str.size();
int i = 0;
/* mark wether there's a dot in the number */
bool hasDot = false;
/* store number string temporarily */
std::string tmp = "";
if (len > 0)
{
/* handle binary radix */
if (radix == 2)
{
/* remove useless characters */
while(str[i] != '-' && str[i] != '0' && str[i] != '1')
{
i++;
}
/* pick up '-' */
if(str[i] == '-')
{
this->negtive = true;
i++;
}
else
{
this->negtive = false;
}
/* remove spare '0's */
while(str[i] == '0')
{
i++;
}
/* get numbers */
for(; i < len ; i++)
{
/* get first dot only */
if (!hasDot && str[i] == '.')
{
hasDot = true;
tmp += '.';
continue;
}
/* get '0's and '1's only */
if (str[i] != '0' && str[i] != '1')
{
break;
}
tmp += str[i];
}
}
/* handle decimal radix */
else
{
/* remove useless characters */
while(str[i] != '-' && !(str[i] >= '0' && str[i] <= '9'))
{
i++;
}
/* pick up '-' */
if(str[i] == '-')
{
this->negtive = true;
i++;
}
else
{
this->negtive = false;
}
/* remove spare '0's */
while(str[i] == '0')
{
i++;
}
/* get numbers */
for(; i < len ; i++)
{
/* get first dot only */
if (!hasDot && str[i] == '.')
{
hasDot = true;
tmp += '.';
continue;
}
/* get all arabic numerals */
if(!(str[i] >= '0' && str[i] <= '9'))
{
break;
}
tmp += str[i];
}
}
}
/* if no number picked up set 0 */
if(tmp == "")
{
tmp = "0";
}
/* add '0' if necessary */
if (tmp[0] == '.')
{
tmp = '0' + tmp;
}
/* mark wether the number has a dot */
this->hasDot = hasDot;
/* fill corresponding number form */
if (radix == 2)
{
this->binVal = tmp;
if (hasDot)
{
/* store dot's index in the number string of binary form */
this->binDotIndex = tmp.find('.');
}
bin2Dec();
}
else
{
this->decVal = tmp;
if (hasDot)
{
/* store dot's index in the number string of decimal form */
this->decDotIndex = tmp.find('.');
}
dec2Bin();
}
/* have a test */
/*
std::cout << "radix: 2" << std::endl;
if(this->negtive)
{
std::cout << '-';
}
std::cout << this->binVal << std::endl;
std::cout << "radix: 10" << std::endl;
if(this->negtive)
{
std::cout << '-';
}
std::cout << this->decVal << std::endl;
*/
}
/*
* name: getNum
* arguments:
* int radix: spedify a radix to find which form number is to got
* return: the number string with specified form
* access: public
* Get the the number string with specified radix.
*/
std::string Converter::getNum(int radix)
{
/* check radix */
if (radix != 2 && radix != 10)
{
std::cerr << "Invalid argument: Do not support radixes beyond binary and decimal yet.\n";
return NULL;
}
std::string tmp = "";
/* add the '-' character if necessary */
if (this->negtive)
{
tmp += '-';
}
/* add the binary form number */
if (radix == 2)
{
tmp += this->binVal;
}
/* add the decimal form number */
else
{
tmp += this->decVal;
}
return tmp;
}
/*
* name: bin2Dec
* access: private
* Convert the binary number to decimal form then fill this->decVal.
*/
void Converter::bin2Dec()
{
/* store number string temporarily */
std::string tmp = "";
/* ============== int part ============== */
/* to get the int range of the binary number string */
int intLen;
if (this->hasDot)
{
intLen = this->binDotIndex;
}
else
{
intLen = this->binVal.size();
}
/* may need carry while traversing digits */
char carry = 0;
/* to store tmp's length */
int decLen;
/* convert radix digit by digit while traversing the int part of the binary number string */
for(int i = 0 ; i < intLen ; i++)
{
/* add new binary digit into carry */
carry += this->binVal[i]-'0';
/* update tmp's length */
decLen = tmp.size();
/* traverse tmp to multiply each digit by 2 and add carries */
for(int j = decLen-1 ; j >= 0 ; j--)
{
tmp[j] = tmp[j]*2+carry;
if (tmp[j] > 9)
{
/* update carry */
carry = tmp[j]/10;
/* limit digit within 10 */
tmp[j] %= 10;
}
else
{
carry = 0;
}
}
/* expand digits if necessary */
while(carry)
{
tmp = char(carry%10)+tmp;
carry /= 10;
}
}
/* ============= part end ============== */
/* add '0' if need */
if (tmp == "")
{
tmp += (char)0;
}
/* ============= float part ============== */
/* if there is a float part */
if (this->hasDot)
{
/* add the dot to the number string */
tmp += '.';
/* get the length except the float part */
int decIntLen = tmp.size();
/* get the length of the whole binary number string */
int binLen = this->binVal.size();
/* convert radix digit by digit while traversing the float part of the binary number string */
for(int i = binLen-1 ; i > intLen ; i--)
{
/* carry to first float digit if occur a '1' */
carry = (this->binVal[i] == '1' ? 5 : 0);
/* update tmp's length */
decLen = tmp.size();
/* traverse tmp to divide each digit by 2 and add carries */
for(int j = decIntLen ; j < decLen ; j++)
{
if (tmp[j] & 1)
{
tmp[j] = tmp[j]/2 + carry;
carry = 5;
}
else
{
tmp[j] = tmp[j]/2 + carry;
carry = 0;
}
}
/* expand digit if necessary */
if (carry)
{
tmp += carry;
}
}
}
/* ============== part end =============== */
/* adjust string and fill this->decVal and this->decDotIndex */
for(int i = 0 ; i < tmp.size() ; i++)
{
if (tmp[i] == '.')
{
continue;
}
tmp[i] += '0';
}
this->decVal = tmp;
this->decDotIndex = tmp.find('.');
}
/*
* name: dec2Bin
* access: private
* Convert the decimal number to binary form then fill this->binVal.
*/
void Converter::dec2Bin()
{
/* store number string temporarily */
std::string tmp = "";
/* ============== int part ============== */
/* to get the int range of the decimal number string */
int intLen;
if (this->hasDot)
{
intLen = this->decDotIndex;
}
else
{
intLen = this->decVal.size();
}
/* may need carry while traversing digits */
char carry = 0;
/* to store tmp's length */
int binLen;
/* convert radix digit by digit while traversing the int part of the decimal number string */
for(int i = 0 ; i < intLen ; i++)
{
/* add new decimal digit into carry */
carry += this->decVal[i]-'0';
/* update tmp's length */
binLen = tmp.size();
/* traverse tmp to multiply each digit by 10 and add carries */
for(int j = binLen-1 ; j >= 0 ; j--)
{
/*
* Type of tmp[] is char[] and MAX_CHAR = 127 > 99.
* So the assignment statement below will work safely.
*/
tmp[j] = tmp[j]*10+carry;
if (tmp[j] > 1)
{
/* update carry */
carry = tmp[j]/2;
/* limit digit within 2 */
tmp[j] &= 1;
}
else
{
carry = 0;
}
}
/* expand digits if necessary */
while(carry)
{
tmp = char(carry%2)+tmp;
carry /= 2;
}
}
/* ============= part end ============== */
/* add '0' if need */
if (tmp == "")
{
tmp += (char)0;
}
/* ============= float part ============== */
/* if there is a float part */
if (this->hasDot)
{
/* add the dot to the number string */
tmp += '.';
/* may need carry while traversing digits */
carry = 0;
/* get the length of the whole decimal number string */
int decLen = this->decVal.size();
/* get the length of the float part of the decimal number string */
int floatLen = decLen-intLen-1;
/* get a copy of the float part of the decimal number string */
std::string tmp2 = this->decVal.substr(intLen+1, floatLen);
/* adjust tmp2 to prepare for algorithm below */
for(int i = 0 ; i < floatLen ; i++)
{
tmp2[i] -= '0';
}
/*
* asume: B = b1*2^-1 + b2*2^-2 + b3*2^-3 + ...
* 2*B = b1 + b2*2^-1 + b3*2^-2 + ... // take b1 as first digit
* 2*(2*B-b1) = b2 + b3*2^-1 + ... // take b2 as second digit
* ...
* so the binary float will got digit by digit in order
*/
for(int i = 0 ; i < this->binFloatPrecision ; i++)
{
/* traverse tmp2 to multiply each digit by 2 and add carries */
for(int j = floatLen-1 ; j >= 0 ; j--)
{
tmp2[j] = tmp2[j]*2+carry;
if (tmp2[j] > 9)
{
/* update carry */
carry = tmp2[j]/10;
/* limit digit within 10 */
tmp2[j] %= 10;
}
else
{
carry = 0;
}
}
/* get the last carry as new digit of binary float */
tmp += carry;
/* reset carry */
carry = 0;
}
}
/* ============== part end =============== */
/* adjust string and fill this->binVal and this->binDotIndex */
for(int i = 0 ; i < tmp.size() ; i++)
{
if (tmp[i] == '.')
{
continue;
}
tmp[i] += '0';
}
this->binVal = tmp;
this->binDotIndex = tmp.find('.');
}
test.cpp:
#include "converter.h"
#include <iostream>
#include <climits>
using namespace std;
int main()
{
//Converter c("0.625", 10);
Converter c("ujsgdfksagrua0.10100000000000000000", 2);
cout << c.getNum(10) << endl;
return 0;
}
都过500行了,会不会写得有点啰嗦?