Frage

I have a decimal string like this (length < 5000):

std::string decimalString = "555";

Is there a standard way to convert this string to binary representation? Like this:

std::string binaryString = "1000101011";

Update.

This post helps me.

War es hilfreich?

Lösung

As the number is very large, you can use a big integer library (boost, maybe?), or write the necessary functions yourself.

If you decide to implement the functions yourself, one way is to implement the old pencil-and-paper long division method in your code, where you'll need to divide the decimal number repeatedly by 2 and accumulate the remainders in another string. May be a little cumbersome, but division by 2 should not be so hard.

Andere Tipps

Since 10 is not a power of two (or the other way round), you're out of luck. You will have to implement arithmetics in base-10. You need the following two operations:

  1. Integer division by 2
  2. Checking the remainder after division by 2

Both can be computed by the same algorithm. Alternatively, you can use one of the various big integer libraries for C++, such as GNU MP or Boost.Multiprecision.

I tried to do it.. I don't think my answer is right but here is the IDEA behind what I was trying to do..

Lets say we have 2 decimals:

100 and 200..

To concatenate these, we can use the formula:

a * CalcPower(b) + b where CalcPower is defined below..

Knowing this, I tried to split the very long decimal string into chunks of 4. I convert each string to binary and store them in a vector..

Finally, I go through each string and apply the formula above to concatenate each binary string into one massive one..

I didn't get it working but here is the code.. maybe someone else see where I went wrong.. BinaryAdd, BinaryMulDec, CalcPower works perfectly fine.. the problem is actually in ToBinary

#include <iostream>
#include <bitset>
#include <limits>
#include <algorithm>

std::string BinaryAdd(std::string First, std::string Second)
{
    int Carry = 0;
    std::string Result;

    while(Second.size() > First.size())
        First.insert(0, "0");

    while(First.size() > Second.size())
        Second.insert(0, "0");

    for (int I = First.size() - 1; I >= 0; --I)
    {
        int FirstBit = First[I] - 0x30;
        int SecondBit = Second[I] - 0x30;
        Result += static_cast<char>((FirstBit ^ SecondBit ^ Carry) + 0x30);
        Carry = (FirstBit & SecondBit) | (SecondBit & Carry) | (FirstBit & Carry);
    }

    if (Carry)
        Result += 0x31;

    std::reverse(Result.begin(), Result.end());
    return Result;
}

std::string BinaryMulDec(std::string value, int amount)
{
    if (amount == 0)
    {
        for (auto &s : value)
        {
            s = 0x30;
        }
        return value;
    }

    std::string result = value;
    for (int I = 0; I < amount - 1; ++I)
        result = BinaryAdd(result, value);

    return result;
}

std::int64_t CalcPowers(std::int64_t value)
{
    std::int64_t t = 1;
    while(t < value)
        t *= 10;

    return t;
}

std::string ToBinary(const std::string &value)
{
    std::vector<std::string> sets;
    std::vector<int> multipliers;

    int Len = 0;
    int Rem = value.size() % 4;

    for (auto it = value.end(), jt = value.end(); it != value.begin() - 1; --it)
    {
        if (Len++ == 4)
        {
            std::string t = std::string(it, jt);
            sets.push_back(std::bitset<16>(std::stoull(t)).to_string());
            multipliers.push_back(CalcPowers(std::stoull(t)));
            jt = it;
            Len = 1;
        }
    }

    if (Rem != 0 && Rem != value.size())
    {
        sets.push_back(std::bitset<16>(std::stoull(std::string(value.begin(), value.begin() + Rem))).to_string());
    }

    auto formula = [](std::string a, std::string b, int mul) -> std::string
    {
        return BinaryAdd(BinaryMulDec(a, mul), b);
    };

    std::reverse(sets.begin(), sets.end());
    std::reverse(multipliers.begin(), multipliers.end());
    std::string result = sets[0];

    for (std::size_t i = 1; i < sets.size(); ++i)
    {
        result = formula(result, sets[i], multipliers[i]);
    }

    return result;
}

void ConcatenateDecimals(std::int64_t* arr, int size)
{
    auto formula = [](std::int64_t a, std::int64_t b) -> std::int64_t
    {
        return (a * CalcPowers(b)) + b;
    };

    std::int64_t val = arr[0];

    for (int i = 1; i < size; ++i)
    {
        val = formula(val, arr[i]);
    }

    std::cout<<val;
}

int main()
{
    std::string decimal = "64497387062899840145";
    //6449738706289984014 = 0101100110000010000100110010111001100010100000001000001000001110

    /*
    std::int64_t arr[] = {644, 9738, 7062, 8998, 4014};
    ConcatenateDecimals(arr, 5);*/

    std::cout<<ToBinary(decimal);

    return 0;
}

I found my old code that solve sport programming task:

ai -> aj

2 <= i,j <= 36; 0 <= a <= 10^1000

time limit: 1sec

Execution time was ~0,039 in worst case. Multiplication, addition and division algorithms is very fast because of using 10^9 as numeration system, but implementation can be optimized very well I think.

source link

#include <iostream>
#include <string>
#include <vector>
using namespace std;
 
#define sz(x) (int((x).size()))
typedef vector<int> vi;
typedef long long llong;
 
int DigToNumber(char c) {
   if( c <= '9' && c >= '0' )
      return c-'0';
   return c-'A'+10;
}

char NumberToDig(int n) {
   if( n < 10 )
      return '0'+n;
   return n-10+'A';
}
 
const int base = 1000*1000*1000;
 
void mulint(vi& a, int b) { //a*= b
   for(int i = 0, carry = 0; i < sz(a) || carry; i++) {
      if( i == sz(a) )
         a.push_back(0);
      llong cur = carry + a[i] * 1LL * b;
      a[i] = int(cur%base);
      carry = int(cur/base);
   }
   while( sz(a) > 1 && a.back() == 0 )
      a.pop_back();
}

int divint(vi& a, int d) { // carry = a%d; a /= d; return carry;
   int carry = 0;
   for(int i = sz(a)-1; i >= 0; i--) {
      llong cur = a[i] + carry * 1LL * base;
      a[i] = int(cur/d);
      carry = int(cur%d);
   }
   while( sz(a) > 1 && a.back() == 0 )
      a.pop_back();
   return carry;
}

void add(vi& a, vi& b) { // a += b
   for(int i = 0, c = 0, l = max(sz(a),sz(b)); i < l || c; i++) {
      if( i == sz(a) )
         a.push_back(0);
      a[i] += ((i<sz(b))?b[i]:0) + c;
      c = a[i] >= base;
      if( c ) a[i] -= base;
   }
}
 
int main() {
 
   ios_base::sync_with_stdio(0);
   cin.tie(0);
 
   int from, to; cin >> from >> to;
   string s; cin >> s;
   vi res(1,0); vi m(1,1); vi tmp;
   for(int i = sz(s)-1; i >= 0; i--) {
      tmp.assign(m.begin(), m.end());
      mulint(tmp,DigToNumber(s[i]));
      add(res,tmp); mulint(m,from);
   }
   vi ans;
   while( sz(res) > 1 || res.back() != 0 )
      ans.push_back(divint(res,to));
   if( sz(ans) == 0 )
      ans.push_back(0);
   for(int i = sz(ans)-1; i >= 0; i--)
      cout << NumberToDig(ans[i]);
   cout << "\n";
   
   return 0;
}

How "from -> to" works for string "s":

  1. accumulate Big Number (vector< int >) "res" with s[i]*from^(|s|-i-1), i = |s|-1..0
  2. compute digits by dividing "res" by "to" until res > 0 and save them to another vector
  3. send it to output digit-by-digit (you can use ostringstream instead)

PS I've noted that nickname of thread starter is Denis. And I think this link may be useful too.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top