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行了,会不会写得有点啰嗦?

Fork me on GitHub