I am designing a cipher and need to convert between bases repeatedly in a loop. I have optimized the everything else, but I'm not too familiar with C++ code, and and am trying to figure out how to make the conversion faster.
Here's the current code I'm using:
string digits = "0123456789abcdef";
string tohex(string number) { // Decimal to Hexadecimal function
long length = number.length();
string result = "";
vector<long> nibbles;
for ( long i = 0; i < length; i++ ) {
nibbles.push_back(digits.find(number[i]));
}
long newlen = 0;
do {
long value = 0;
newlen = 0;
for ( long i = 0; i < length; i++ ) {
value = (value * 10) + nibbles[i];
if (value >= 16) {
nibbles[newlen++] = value / 16;
value %= 16;
} else if (newlen > 0) {
nibbles[newlen++] = 0;
};
};
length = newlen;
result = digits[value] + result;
} while (newlen != 0);
return result;
}
In my case (cipher) the number will always fit within an int, so it works to do:
string tohex(string number) {
int num = std::stoi(number);
std::stringstream hexnumber;
hexnumber << std::hex << num;
return hexnumber.str();
}
This is better because it is simpler and uses the built-in std::hex method.
Related
it is my first question in SO, but I cannot find a good solution for this, not online nor from my brain.
I have a big string of number (over 100 digits) and I need to remove some of its digits to create a number divisible by 8. It is really simple...
However, lets say the only way to create this number is with a number that ends with '2'. In this case I would need to look for proper 10's and 100's digits and it is at this point I cannot find an elegant solution.
I have this:
bool ExistDigit(string & currentNumber, int look1) {
int currentDigit;
int length = currentNumber.length();
for (int i = length - 1; i >= 0; i--) {
currentDigit = -48;//0 in ASC II
currentDigit += currentNumber.back();//sum ASCII's value of char to current Digit
if (currentDigit == look1) {
return true;
}
else
currentNumber.pop_back;
}
return false;
}
It modify the string but since I check for 8's and 0's first, by the time I get to check 2's, the string is empty already. I solved this by creating several copies of the string, but I would like to know if there is a better way and what is it.
I know that if I use ExistDigit(string CurrentNumber, int look1), the string does not get modified, but in this case, it would not help with the 2, because after finding the two I need to look for 1's, 5's and 9's after the 2 in the original string.
What is the correct approach to these kind of problems? I mean, should I stick with changing the string or should I return a value for the position of the 2 (for example) and work from there? If it is good to change the string, how should I do it in order to be able to reuse the original string?
I am new to C++, and coding in general (just started actually) so, sorry if it is a really silly question. Thanks in advance.
EDIT: My call look like this:
int main() {
string originalNumber;//hold number. Must be string because number can be too long for ints
cin >> originalNumber;
string answer = "YES";
string strNumber;
//look for 0's and 8's. they are solutions by their own
strNumber = originalNumber;
if (ExistDigit(strNumber, 0)) {
answer += "\n0";
}
else {
strNumber = originalNumber;
if (ExistDigit(strNumber, 8)) {
answer += "\n8";
}
else {
strNumber = originalNumber;
//look for 'even'32, 'even'72, 'odd'12, 'odd'52, 'odd'92
//these are the possibilities for multiples of 8 ended with 2
if (ExistDigit(strNumber, 2)) {
if (ExistDigit(strNumber, 1)) {
}
}
else {
EDIT 2: In case you have the same problem, check the function find_last_of, it is really convenient and solves the problem.
The following code retains your design and should give at least a solution if one exists. The nested if and for can be simplified within a more elegant solution by using a recursive function. With such a recursive function, you could also enumerate all the solutions.
Instead of having multiple copies of the string, you could use an iterator that defines the start of the search. In the code the start variable is this iterator.
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
bool ExistDigit(const string & currentNumber, int& start, int look1) {
int currentDigit;
int length = currentNumber.length();
for (int i = length - 1 - start; i >= 0; i--) {
currentDigit = currentNumber[i] - '0';
if (currentDigit == look1) {
start = length - i;
return true;
}
}
return false;
}
int main() {
string originalNumber;//hold number. Must be string because number can be too long for ints
cin >> originalNumber;
stringstream answer;
answer << "YES";
//look for 0's and 8's. they are solutions by their own
int start = 0;
if (ExistDigit(originalNumber, start, 0)) {
answer << "\n0";
}
else {
start = 0;
if (ExistDigit(originalNumber, start, 8)) {
answer << "\n8";
}
else {
start = 0;
//look for 'even'32, 'even'72, 'odd'12, 'odd'52, 'odd'92
//these are the possibilities for multiples of 8 ended with 2
if (ExistDigit(originalNumber, start, 2)) {
for (int look2 = 1; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) { // 'odd'
for (int look3 = 1; look3 < 10; look3 += 2) {
int startAttempt2 = startAttempt1;
if (ExistDigit(originalNumber, startAttempt2, look3))
answer << "\n" << look3 << look2 << "2";
};
}
};
for (int look2 = 3; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) // 'even'
answer << "\n" << look2 << "2";
};
}
//look for 'odd'36, 'odd'76, 'even'12, 'even'52, 'even'92
//these are the possibilities for multiples of 8 ended with 2
else if (ExistDigit(originalNumber, start, 6)) {
for (int look2 = 3; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) { // 'odd'
for (int look3 = 1; look3 < 10; look3 += 2) {
int startAttempt2 = startAttempt1;
if (ExistDigit(originalNumber, startAttempt2, look3))
answer << "\n" << look3 << look2 << "6";
};
}
};
for (int look2 = 1; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) // 'even'
answer << "\n" << look2 << "6";
};
}
//look for 'even'24, 'even'64, 'odd'44, 'odd'84, 'odd'04
//these are the possibilities for multiples of 8 ended with 2
else if (ExistDigit(originalNumber, start, 6)) {
for (int look2 = 0; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) { // 'odd'
for (int look3 = 1; look3 < 10; look3 += 2) {
int startAttempt2 = startAttempt1;
if (ExistDigit(originalNumber, startAttempt2, look3))
answer << "\n" << look3 << look2 << "4";
};
}
};
for (int look2 = 2; look2 < 10; look2 += 4) {
int startAttempt1 = start;
if (ExistDigit(originalNumber, startAttempt1, look2)) // 'even'
answer << "\n" << look2 << "4";
};
}
}
}
cout << answer.str() << std::endl;
return 0;
}
Here is a solution when you are looking for a subword composed of successive characters in the decimal textual form.
#include <string>
#include <iostream>
bool ExistDigit(const std::string& number, int look) { // look1 = 2**look
// look for a subword of size look that is divisible by 2**look = 1UL << look
for (int i = (int) number.size()-1; i >= 0; --i) {
bool hasFound = false;
unsigned long val = 0;
int shift = look-1;
if (i-shift <= 0)
shift = i;
for (; shift >= 0; --shift) {
val *= 10;
val += (number[i-shift] - '0');
};
if (val % (1UL << look) == 0)
return true;
};
return false;
}
int main(int argc, char** argv) {
std::string val;
std::cin >> val;
if (ExistsDigit(val, 3) /* since 8 = 2**3 = (1 << 3) */)
std::cout << "have found a decimal subword divisible by 8" << std::endl;
else
std::cout << "have not found any decimal subword divisible by 8" << std::endl;
return 0;
}
If you are likely to find a subword of consecutive bits in the binary form of the number, you need to convert your number in a big integer and then to do similar search.
Here is a (minimal-tested) solution without any call to an external library like gmp to convert the text in a big integer. This solution makes use of bitwise operations (<<, &).
#include <iostream>
#include <string>
#include <vector>
int
ExistDigit(const std::string & currentNumber, int look) { // look1 = 2^look
std::vector<unsigned> bigNumber;
int length = currentNumber.size();
for (int i = 0; i < length; ++i) {
unsigned carry = currentNumber[i] - '0';
// bigNumber = bigNumber * 10 + carry;
for (int index = 0; index < bigNumber.size(); ++index) {
unsigned lowPart = bigNumber[index] & ~(~0U << (sizeof(unsigned)*4));
unsigned highPart = bigNumber[index] >> (sizeof(unsigned)*4);
lowPart *= 10;
lowPart += carry;
carry = lowPart >> (sizeof(unsigned)*4);
lowPart &= ~(~0U << (sizeof(unsigned)*4));
highPart *= 10;
highPart += carry;
carry = highPart >> (sizeof(unsigned)*4);
highPart &= ~(~0U << (sizeof(unsigned)*4));
bigNumber[index] = lowPart | (highPart << (sizeof(unsigned)*4));
}
if (carry)
bigNumber.push_back(carry);
};
// here bigNumber should be a biginteger = currentNumber
for (int i = 0; i < bigNumber.size()*8*sizeof(unsigned); ++i) {
// looks for look consective bits set to '0'
bool hasFound = true;
for (int shift = 0; hasFound && shift < look; ++shift)
if (bigNumber[(i+shift) / (8*sizeof(unsigned))]
& (1U << ((i+shift) % (8*sizeof(unsigned)))) != 0)
hasFound = false;
if (hasFound) { // ok, bigNumber has look consecutive bits set to 0
// test if we are at the end of the bigNumber
int index = (i+look) / (8*sizeof(unsigned));
for (int j = ((i+look+8*sizeof(unsigned)-1) % (8*sizeof(unsigned)))+1;
j < (8*sizeof(unsigned)); j++)
if ((bigNumber[index] & (1U << j)) != 0)
return i; // the result is (currentNumber / (2^i));
while (++index < bigNumber.size())
if (bigNumber[index] != 0)
return i; // the result is (currentNumber / (2^i));
return -1;
};
};
return -1;
}
int main(int argc, char** argv) {
std::string val;
std::cin >> val;
std::cout << val << " is divided by 8 after " << ExistDigit(val, 3) << " bits." << std::endl;
return 0;
}
I am trying to write a code that takes a binary number input as a string and will only accept 1's or 0's if not there should be an error message displayed. Then it should go through a loop digit by digit to convert the binary number as a string to decimal. I cant seem to get it right I have the fact that it will only accept 1's or 0's correct. But then when it gets into the calculations something messes up and I cant seem to get it correct. Currently this is the closest I believe I have to getting it working. could anyone give me a hint or help me with what i am doing wrong?
#include <iostream>
#include <string>
using namespace std;
string a;
int input();
int main()
{
input();
int decimal, x= 0, length, total = 0;
length = a.length();
// atempting to make it put the digits through a formula backwords.
for (int i = length; i >= 0; i--)
{
// Trying to make it only add the 2^x if the number is 1
if (a[i] = '1')
{
//should make total equal to the old total plus 2^x if a[i] = 1
total = total + pow(x,2);
}
//trying to let the power start at 0 and go up each run of the loop
x++;
}
cout << endl << total;
int stop;
cin >> stop;
return 0;
}
int input()
{
int x, x2, count, repeat = 0;
while (repeat == 0)
{
cout << "Enter a string representing a binary number => ";
cin >> a;
count = a.length();
for (x = 0; x < count; x++)
{
if (a[x] != '0' && a[x] != '1')
{
cout << a << " is not a string representing a binary number>" << endl;
repeat = 0;
break;
}
else
repeat = 1;
}
}
return 0;
}
I don't think that pow suits for integer calculation. In this case, you can use shift operator.
a[i] = '1' sets the value of a[i] to '1' and return '1', which is always true.
You shouldn't access a[length], which should be meaningless.
fixed code:
int main()
{
input();
int decimal, x= 0, length, total = 0;
length = a.length();
// atempting to make it put the digits through a formula backwords.
for (int i = length - 1; i >= 0; i--)
{
// Trying to make it only add the 2^x if the number is 1
if (a[i] == '1')
{
//should make total equal to the old total plus 2^x if a[i] = 1
total = total + (1 << x);
}
//trying to let the power start at 0 and go up each run of the loop
x++;
}
cout << endl << total;
int stop;
cin >> stop;
return 0;
}
I would use this approach...
#include <iostream>
using namespace std;
int main()
{
string str{ "10110011" }; // max length can be sizeof(int) X 8
int dec = 0, mask = 1;
for (int i = str.length() - 1; i >= 0; i--) {
if (str[i] == '1') {
dec |= mask;
}
mask <<= 1;
}
cout << "Decimal number is: " << dec;
// system("pause");
return 0;
}
Works for binary strings up to 32 bits. Swap out integer for long to get 64 bits.
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
string getBinaryString(int value, unsigned int length, bool reverse) {
string output = string(length, '0');
if (!reverse) {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << i)) != 0) {
output[i] = '1';
}
}
}
else {
for (unsigned int i = 0; i < length; i++) {
if ((value & (1 << (length - i - 1))) != 0) {
output[i] = '1';
}
}
}
return output;
}
unsigned long getInteger(const string& input, size_t lsbindex, size_t msbindex) {
unsigned long val = 0;
unsigned int offset = 0;
if (lsbindex > msbindex) {
size_t length = lsbindex - msbindex;
for (size_t i = msbindex; i <= lsbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << (length - offset));
}
}
}
else { //lsbindex < msbindex
for (size_t i = lsbindex; i <= msbindex; i++, offset++) {
if (input[i] == '1') {
val |= (1 << offset);
}
}
}
return val;
}
int main() {
int value = 23;
cout << value << ": " << getBinaryString(value, 5, false) << endl;
string str = "01011";
cout << str << ": " << getInteger(str, 1, 3) << endl;
}
I see multiple misstages in your code.
Your for-loop should start at i = length - 1 instead of i = length.
a[i] = '1' sets a[i] to '1' and does not compare it.
pow(x,2) means and not . pow is also not designed for integer operations. Use 2*2*... or 1<<e instead.
Also there are shorter ways to achieve it. Here is a example how I would do it:
std::size_t fromBinaryString(const std::string &str)
{
std::size_t result = 0;
for (std::size_t i = 0; i < str.size(); ++i)
{
// '0' - '0' == 0 and '1' - '0' == 1.
// If you don't want to assume that, you can use if or switch
result = (result << 1) + str[i] - '0';
}
return result;
}
I've almost solved this exercise:
Binary to Decimal and Back Converter - "Develop a converter to convert a decimal number to binary or a binary number to its decimal equivalent."
So, the binary to decimal converter works perfectly, but the other one doesn't. convertToBinary() function returns crap and I don't know why. Here is the code:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
char* convertToBinary(int dec);
int convertToDec(const char* bin);
int main()
{
std::cout << convertToBinary(100) << std::endl; // wtf!
return 0;
}
char* convertToBinary(int dec)
{
char binary[15] = "";
int result;
for(int i = 0; dec >= 1; dec /= 2, ++i)
{
result = !((dec % 2) == 0);
binary[i] = result + 48;
}
for(int i = strlen(binary); strlen(binary) % 4 != 0; ++i) // add some zeros to make it look cool
binary[i] = '0';
for(int i = 0, j = strlen(binary)-1; i < j; ++i, --j) // reverse the array
{
char temp = binary[i];
binary[i] = binary[j];
binary[j] = temp;
}
std::cout << binary << std::endl; // looking good!
return binary;
}
int convertToDec(const char* bin)
{
int dec = 0;
int size = strlen(bin);
for(int i = 0; *bin; ++i, ++bin)
{
int ch = *bin - 48;
dec += ch * pow(2, size - i - 1);
}
return dec;
}
Using c language
char *convertToBinary(int value)
{
char *binary;
size_t length;
size_t i;
length = 8 * sizeof(value);
binary = malloc(1 + length);
if (binary == NULL)
return NULL;
for (i = 0 ; i < length ; ++i)
binary[length - i - 1] = (value & (1 << i)) ? '1' : '0';
binary[length] = '\0';
return binary;
}
int binaryToDecimal(const char *binary)
{
int value;
size_t length;
size_t i;
value = 0;
length = strlen(binary);
for (i = 0 ; i < length ; i++)
value |= (binary[i] == '1') ? (1 << (length - i - 1)) : 0;
return value;
}
Using c++ language
std::string convertToBinary(int value)
{
std::string binary;
size_t length;
length = 8 * sizeof(value);
binary.resize(length);
for (size_t i = 0 ; i < length ; ++i)
binary[length - i - 1] = (value & (1 << i)) ? '1' : '0';
return binary;
}
int binaryToDecimal(const std::string &binary)
{
int value;
size_t length;
value = 0;
length = binary.length();
for (size_t i = 0 ; i < length ; i++)
value |= (binary[i] == '1') ? (1 << (length - i - 1)) : 0;
return value;
}
to convert from binary to decimal, you can use strtol of course.
Your mistake is returning a local variable, a local variable is automatically deallocated when the function returns, and hence the garbage you got.
When you do something like this:
char *toString(...)
{
char res[MAX_RES];
// fill res
return res;
}
you create the array res as a local array on the stack. This array goes out of scope when you return from the function; a pointer to this array is no longer valid and most likely will point to garbage.
If you want to use C-style char buffers, there are two ways to get around this:
Allocate the result on the heap.
char *toString(...)
{
char *res = malloc(MAX_RES);
// fill res
return res;
}
Data allocated on the heap with malloc will be valid until explicitly released with free. The advantage of this approach is that you can make the string as long as you wish. Thedrawback is that the allocation might fail. It is also worth noting that the caller now owns the string and is responsible for freeing it:
char *x = toString(...);
// do stuff with x
free(x);
**Pass the buffer and maximum length **
int toString(char *res, size_t max, ...)
{
// fill res
}
That is the approach many library functions use, notably snprintf. The caller has to provide their own buffer and information on the maximum allowable length in order to avoid buffer overflows. This approach must keep track of the buffer size and truncate the result if necessary, possibly maintaining the string null-terminated. Such functions could be void, but it is customary to return the actual string length or -1 as error indicator.
It is called like this:
char x[200];
toString(x, sizeof(x), ...);
// do stuff with x
I'm pretty new to C++ and am very confused as to what is happening here. The error is the line int len = strlen(strin);. Any suggestions how to fix this would be much appreciated.
BigNum::BigNum(const std::string& strin)
{
digits = NULL;
int len = strlen(strin);
if (len == 0)
{
BigNum zero;
*this = zero;
return;
}
used = len;
positive = true;
int i = 0;
if(strin[i] == '-')
{
positive = false;
i = 1;
used--;
}
else if(strin[i] == '+')
{
i = 1;
used--;
}
capacity = double_up_default(used);
digits = new unsigned int[capacity];
for(unsigned int k = 0; k < used; ++k)
{
digits[used - k - 1] = strin[i++] - '0';
}
trim();
}
strlen knows nothing about std::string. It is a C function that returns the length of a null-terminated string.
Fortunately std::string knows its own length. Try this instead:
int len = strin.size();
or, if you care about the range of sizes a string may have,
std::string::size_type len = strin.size();
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Can someone with a bit of time, he could explain to me how intensify very large numbers? I'm not talking here about a ready solution, and the only explanation of how to implement the arithmetic. Ideally, it was based on the class std::string.
#edit
I read something about shifts bit, but examples were only in the form of a listing, and I want an explanation of how it works.
You can represent a large number as a sequence of digits in some base, and separately the sign of the number. To do arithmetic, you simply implement the algorithms you learnt at primary school to do addition, long multiplication, etc. There's more efficient algorithms (for example Karatsuba) for doing some operations, but an initial implementation could use the simpler forms.
If you really have to use std::string, you can use the first char to store the sign ('+' or '-'), and then the digits in base 10 in ascii. It's not efficient, but it's perhaps an easy way to get started, and it certainly makes printing the numbers out easy.
Here is something I quickly wrote when I needed (do not remember when). It is:
Buggy;
Not complete;
Arbitrarily use 3 digits per array element while it could use more;
Can clearly be improved (any kind comments are welcome^^).
However, I hope this will be somehow useful.
typedef long long int lli;
class BigInt
{
public: // Methods
BigInt(lli s) : m_nbElements(100)
{
m_number.resize(m_nbElements);
for (lli i=0; i < m_nbElements; ++i)
{
m_number[i] = s%1000;
s /= 1000;
}
}
BigInt(const std::string &str) : m_nbElements(100)
{
m_number.resize(m_nbElements);
size_t sizeStr = str.size();
int i = str.size() - 1;
int thousands = 0;
for (; i >= 2; i -= 3, ++thousands)
{
std::string subStr = str.substr(i-2, 3);
unsigned int value;
std::istringstream(subStr) >> value;
m_number[thousands] = value;
}
// Handle the "first" 1 or 2 digits
if (i >= 0)
{
std::string subStr = str.substr(0, i+1);
unsigned int value;
std::istringstream(subStr) >> value;
m_number[thousands] = value;
}
}
BigInt operator*(lli s)
{
lli temp, remainder = 0;
for (lli i=0; i < m_nbElements; ++i)
{
temp = m_number[i] * s + remainder;
m_number[i] = temp % 1000;
remainder = temp / 1000;
}
return (*this);
}
BigInt operator/(lli s)
{
lli temp, remainder = 0;
for (int i=m_nbElements-1; i >= 0; --i)
{
temp = (m_number[i] + remainder) / s;
remainder = (m_number[i] % s)*1000;
m_number[i] = temp;
}
return (*this);
}
BigInt operator-(BigInt s)
{
lli temp;
for (unsigned int i=0; i < m_nbElements; ++i)
{
temp = m_number[i] - s.m_number[i];
if (temp < 0)
{
--m_number[i+1];
temp += 1000;
}
m_number[i] = temp;
}
return (*this);
}
BigInt operator+(BigInt s)
{
lli temp, remainder = 0;
for (lli i=0; i < m_nbElements; ++i)
{
temp = m_number[i] + s.m_number[i] + remainder;
m_number[i] = temp % 1000;
remainder = temp / 1000;
}
return (*this);
}
std::string ToString()
{
std::string result = "";
bool significantDigitsFound = false;
for (int i=m_nbElements-1; i >= 0 ; --i)
{
if (!significantDigitsFound)
{
if (m_number[i] > 0)
{
std::ostringstream ss;
ss << m_number[i];
result = ss.str();
significantDigitsFound = true;
}
}
else
{
std::ostringstream ss;
ss << std::setw(3) << std::setfill( '0' ) << m_number[i];
result += ss.str();
}
}
if (result == "")
{
result = "0";
}
return result;
}
private: // Attributes
int m_nbElements;
std::vector<lli> m_number;
};