C++二进制-十进制转换器

    布置了二进制-十进制转换器的小作业,本来还要求顺手扩展一下大数的四则运算,我嫌麻烦没做扩展,就只是写来玩玩。也算熟悉一下底层的二进制-十进制转换机制,顺便复习下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行了,会不会写得有点啰嗦?


C++二进制-十进制转换器
https://blog.bipedalbit.net/2015/10/08/C-二进制-十进制转换器/
作者
Bipedal Bit
发布于
2015年10月8日
许可协议