Substring to Int C++ - c++

I am trying to convert a string that is only 1s and 0s to a decimal value. The variable value is initialized to 0 and is never updated. I suspect the problem is that binaryString[i] is treated as a string and therefore the athematic function doesn't work. How can I fix this?
void binaryToDec(string binaryString, int value)
{
int binaryStringLength = binaryString.length();
for (int i = 0; i < binaryStringLength; i++)
{
value += pow(2,i)+ binaryString[i];
}
}
I tried to use basic type casting like int(binaryString[i]) but that doesn't work.

Firstly binaryString[i] is a character, not an integer. To convert a digit character to an integer you can just subtract '0'.
binaryString[i] - '0'
Secondly pow(2,i) returns a floating point number, when you want an integer. This is inefficient, and even more seriously might be subject to rounding errors. Instead you should use a shift operator, which efficiently and accurately calculates integer powers of two.
1 << i
Thirdly you have + where you need *. The two terms should be multiplied not added.
Putting all that together you get
value += (1 << i) * (binaryString[i] - '0');
But the most serious error of all is that your function does not return a value. It should look like this
int binaryToDec(string binaryString)
{
int value = 0;
...
return value;
}
Your version passes value as a parameter, that's the wrong way round, binaryString is a parameter, but value should be returned from the function. Not sure why but this is a difference a lot of newbies struggle with.

You could construct a bitset from the string and then back to a ullong.
But, limiting the solution to a maximum binary string size.
[Demo]
#include <bitset>
#include <fmt/core.h>
#include <stdexcept> // out_of_range
auto binaryToDec(const std::string& binary) {
if (binary.size() > 64) {
throw std::out_of_range{ "binary string is too big" };
}
return std::bitset<64>{binary}.to_ullong();
}
int main() {
try {
std::string binary_1{"101010"};
fmt::print("binary: {}, decimal: {}\n", binary_1, binaryToDec(binary_1));
std::string binary_2{
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1"
};
fmt::print("{}\n", binaryToDec(binary_2));
} catch (const std::exception& e) {
fmt::print("Error: {}.\n", e.what());
}
}
// Outputs:
//
// binary: 101010, decimal: 42
// Error: binary string is too big.

Related

Is there a way to convert a number, represented as a string, to its binary equivalent?

A shell of the desired code:
#include <iostream>
#include <string>
std::string str_to_bin(const std::string& str)
{
//...
}
int main()
{
std::string str = "123";
std::cout << str_to_bin(str); //would print 1111011
}
Question title says it all. I've been stuck on this for a while. Is there a solution for this in the STL? Or something simple that I'm missing? If not, how would I go about doing this? Maybe a direction you could point me to? Also, speed is of great importance.
EDIT: The number can be of any size (larger than long long as well), so std::stoi and std::bitset<> are off the table.
You can do it using GMP (GNU Multi-Precision). Something like this:
#include <gmpxx.h>
std::string str_to_bin(const std::string& str)
{
mpz_class bignum;
int rc = bignum.set_str(str, 10);
if (rc != 0)
throw std::invalid_argument("bad number: " + str);
return bignum.get_str(2);
}
Or using the traditional C API:
#include <gmp.h>
std::string str_to_bin(const std::string& str)
{
mpz_t bignum;
int rc = mpz_set_str(bignum, str.c_str(), 10);
if (rc != 0)
throw std::invalid_argument("bad number: " + str);
char* rawstr = mpz_get_str(nullptr, 2, bignum);
std::string result(rawstr);
free(rawstr);
return result;
}
Okay let's break down the process you require here. (only one of an infinite number of ways to do this)
Conversion of a number represented as a string type into an integer type.
Conversion of the intermediary integer type into a binary number which is held in another string type. (judging by the return type of your function, which could just as easily return an integer by the way and save the headache of representing the binary equivalent as a string)
For step 1:
Use the standard library function stoi(). It does what you might imagine, extracts the numerical data from the string and stores it in an integer.
std::string numberstr = "123";
int numberint = std::stoi(numberstr);
std::cout << numberint << "\n";
Now you have the number as an integer.
For step 2:
This process involves the conversion of a number from base 10 (decimal) to base 2 (binary).
Divide the number by 2.
Store the remainder and the quotient of this division operation for further use.
The remainder becomes part of the binary representation, while the quotient is used as the next dividend.
This process repeats until the dividend becomes 1, at which point it too is included in the binary representation.
Reverse the string, and voila! You now have the binary representation of a number.
If you want to handle negative numbers (which I imagine you might), simply perform a check before the conversion to see if the converted integer is negative, and set a flag to true if it is.
Check this flag before reversing, and add a negative sign to end of the string before reversing.
The final function looks like this:
std::string str_to_bin(const std::string& str)
{
std::string binarystr = ""; // Output string
int remainder;
int numberint = std::stoi(str);
bool flagnegative = false;
// If negative number, beginning of binary equivalent is 1
if (numberint < 0)
{
numberint = abs(numberint);
flagnegative = true;
}
// If number is 0, don't perform conversion simply return 0
if (numberint == 0)
{
binarystr = "0";
return binarystr;
}
std::cout << numberint << "\n";
while (numberint != 1)
{
remainder = numberint % 2;
numberint /= 2;
std::ostringstream convert; // stream used for the conversion
convert << remainder; // insert the textual representation of 'remainder' in the characters in the stream
binarystr += convert.str();
}
std::ostringstream final;
final << numberint; // To insert the last (or rather first once reversed) binary number
binarystr += final.str();
if (flagnegative == true)
binarystr += "-";
std::reverse(binarystr.begin(), binarystr.end());
return binarystr;
}
Other people have posted the STL method using bitset, which might be of value to you, but I believe there's no fun in simply copy pasting a function found online.
This way, you understand exactly whats going on under the hood!
However I cannot provide a guarantee for speed, especially since this is using streams. Bit operations would definitely be more efficient.
Anywho, hope this helps! I had quite a bit of fun writing this.

Recursive Function practice

I am studying for an upcoming exam and one of the questions on the study guide is:
Write a recursive C++ function for converting a string of digits into the integer it represents. For
example, “13531” represents the integer 13531. Your function should return the integer value.
I am able to convert the string to an integer but am having trouble on what the base case should be for the function to be recursive. Any suggestions or help would be much appreciated.
The base case is an empty string.
Each step of your recursion converts one character in the string to an integer. And the recursive step passes in the remainder of the string.
As yourself how you might "work your way" through the starting string?
My gut feel tells me from "1357" I would would start with "7", leaving "135", then "5", leaving "13", and so on. And what are you eventually left with? An empty string!
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
int convert(string x)
{
int c=x[0]-'0';//to get the numeric value of the first char in string
if(x.size()==1)//base case
return c;
//in each time return the char with "x.size()-1" digits of zero and the first digit is for the number
return c*pow(10,x.size()-1)+convert(x.substr(1));
}
int main(){
string x;
getline(cin,x);
cout<<convert(x);
}
"12345" will be returned as no=10000+2000+300+40+5
Not sure whether you mean 'edge case' by 'base case'.
The edge case should be one that doesn't need any recursion any more and thus can be worked out directly. Thus it can be when the 'string' has only one digit (return str[0]-'0';) or has zero digit (return 0;) I think. The zero digit case might be a little more general.
Just a little more about the 'base' of the number if it could be other than base-10 number.
You might have to test the base of the number first. For c++11,
decimal-literal (base 10), octal-literal (base 8) and hex-literal
(base 16) are supported, e.g. -0x123, -0123, -123. You can do
the test according to cpp_integer_literal.
What about without any usage of pow, like:
#include <iostream>
#include <string>
int str_to_int(const std::string& str)
{
if (str.size() == 0)
return 0; // base case, end recursion
else
return (str[str.size() - 1] - '0') +
10 * str_to_int(str.substr(0, str.size() - 1));
}
int main()
{
std::cout << str_to_int("1234");
}
tailed recursion edition
#include<iostream>
#include<string>
void str2int(const std::string& s, int &result, int n = 0)
{
if (n == s.size())
{
return;
}
result *= 10;
result += s[n] - '0';
return str2int(s, result, n + 1);
}
int main()
{
int n = 0;
str2int("1234", n);
std::cout << n;
}
Using iterators seems to be more elegant and has the advantage that the conversion function can be applied on sub-strings.
#include <string>
#include <stdio.h>
using namespace std;
int str2int(string::const_iterator s, string::const_iterator e)
{
if(s==e) return 0;
--e;
return str2int(s,e)*10+*e-'0';
}
int main()
{
string s="12345";
printf("%d\n",str2int(s.begin(),s.end()));
}

Read integer from string

I have a string in form "blah-blah..obj_xx..blah-blah" where xx are digits. E.g. the string may be "root75/obj_43.dat".
I want to read "xx" (or 43 from the sample above) as an integer. How do I do it?
I tried to find "obj_" first:
std::string::size_type const cpos = name.find("obj_");
assert(std::string::npos != cpos);
but what's next?
My GCC doesn't support regexes fully, but I think this should work:
#include <iostream>
#include <string>
#include <regex>
#include <iterator>
int main ()
{
std::string input ("blah-blah..obj_42..blah-blah");
std::regex expr ("obj_([0-9]+)");
std::sregex_iterator i = std::sregex_iterator(input.begin(), input.end(), expr);
std::smatch match = *i;
int number = std::stoi(match.str());
std::cout << number << '\n';
}
With something this simple you can do
auto b = name.find_first_of("0123456789", cpos);
auto e = name.find_first_not_of("0123456789", b);
if (b != std::string::npos)
{
auto digits = name.substr(b, e);
int n = std::stoi(digits);
}
else
{
// Error handling
}
For anything more complicated I would use regex.
How about:
#include <iostream>
#include <string>
int main()
{
const std::string test("root75/obj_43.dat");
int number;
// validate input:
const auto index = test.find("obj_");
if(index != std::string::npos)
{
number = std::stoi(test.substr(index+4));
std::cout << "number: " << number << ".\n";
}
else
std::cout << "Input validation failed.\n";
}
Live demo here. Includes (very) basic input validation (e.g. it will fail if the string contains multiple obj_), variable length numbers at the end, or even more stuff following it (adjust the substr call accordingly) and you can add a second argument to std::stoi to make sure it didn't fail for some reason.
Here's another option
//your code:
std::string::size_type const cpos = name.find("obj_");
assert(std::string::npos != cpos);
//my code starts here:
int n;
std::stringstream sin(name.substr(cpos+4));
sin>>n;
Dirt simple method, though probably pretty inefficient, and doesn't take advantage of the STL:
(Note that I didn't try to compile this)
unsigned GetFileNumber(std::string &s)
{
const std::string extension = ".dat";
/// get starting position - first character to the left of the file extension
/// in a real implementation, you'd want to verify that the string actually contains
/// the correct extension.
int i = (int)(s.size() - extension.size() - 1);
unsigned sum = 0;
int tensMultiplier = 1;
while (i >= 0)
{
/// get the integer value of this digit - subtract (int)'0' rather than
/// using the ASCII code of `0` directly for clarity. Optimizer converts
/// it to a literal immediate at compile time, anyway.
int digit = s[i] - (int)'0';
/// if this is a valid numeric character
if (digit >= 0 && digit <= 9)
{
/// add the digit's value, adjusted for it's place within the numeric
/// substring, to the accumulator
sum += digit * tensMultiplier;
/// set the tens place multiplier for the next digit to the left.
tensMultiplier *= 10;
}
else
{
break;
}
i--;
}
return sum;
}
If you need it as a string, just append the found digits to a result string rather than accumulating their values in sum.
This also assumes that .dat is the last part of your string. If not, I'd start at the end, count left until you find a numeric character, and then start the above loop. This is nice because it's O(n), but may not be as clear as the regex or find approaches.

Trouble getting character classification information from map

I have a program that maps the ctype identification of a character to a textual representation. I use a std::map to map a value of the mask (ctype_base::mask) to a string that represents the type of character in a string. The trouble I'm having is that when I attempt to print out the value, nothing gets printed to output. Why is this?
#include <iostream>
#include <map>
#include <vector>
class mask_attribute
{
private:
typedef std::ctype_base base_type;
public:
mask_attribute()
{
mask_names[base_type::space] = "space";
mask_names[base_type::alpha] = "alpha";
mask_names[base_type::digit] = "digit";
}
std::string get_mask_name(base_type::mask mask) const
{
std::string result = (*mask_names.find(mask)).second;
return result;
}
private:
std::map<base_type::mask, std::string> mask_names;
};
int main()
{
std::string a = "abc123";
std::vector<std::ctype_base::mask> v(a.size());
auto& f = std::use_facet<std::ctype<char>>(std::locale());
f.is(&a[0], &a[0] + a.size(), &v[0]);
for (unsigned i = 0; i < v.size(); ++i)
std::cout << mask_attribute().get_mask_name(v[i]) << std::endl;
}
The output I expected was:
alpha
alpha
alpha
digit
digit
digit
but instead nothing is printed. What did I do wrong here and how do I fix it?
Print out v[i] as integer in hex, that might prove illuminating.
You expect ctype::is to produce exactly one bit for each character. That is not what normally happens. For example, for 'a' you are likely to see alpha | lower | print. You don't have an entry for this in mask_names, so find returns mask_names.end(), which you promptly dereference, whereupon your program exhibits undefined behavior.

sprintf too many/few decimals

I must convert decimal numbers using a non-scientific (ie. no mantissa/exponent/E's) character string. My code looks like this:
/*!
\brief Converts a <em>XML Schema Decimal</em>
*/
char *ToDecimal(double val) const
{
const size_t nMax = 200;
char *doubleStr = new char[nMax];
sprintf(doubleStr, "%1.6f", val);
return doubleStr;
}
The problem is that when the input val is 1 then the function returns 1.000000 but I was hoping for a output of 1. Also, if I change the code to sprintf(doubleStr, "%1.0f", val); then it correctly outputs 1, but if the input val is changed to 0.000005 the output is 0, and I was hoping the output would then be 0.000005. So basically I want all output to be as short as possible and remove all unnessesary 0's. Is this possible with sprintf? I would like to support 3.4E +/- 38 range with this function.
It turns out that c++ iostreams (specifically, ostringstream) are better suited for your task than sprintf.
Use the std::fixed manipulator to disable scientific notation. Use std::setprecision to specify precision (number of characters after decimal dot). In your case, precision of 45 places seems enough to represent all float numbers.
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
std::string convert(double x)
{
std::ostringstream buffer;
buffer << std::fixed << std::setprecision(45) << x;
std::string result = buffer.str();
return result;
}
In addition, to clean-up the result, remove any trailing zeros.
size_t i = result.find_last_not_of('0');
if (result[i] != '.')
++i;
result.erase(i);
Note: the clean-up of trailing zeros will only work for numbers that are exactly representable (like 0.75 or 0.03125): for example, the number 0.1 is converted to 0.10000000000000000555111512312578270211815834. One could use non-constant precision (depending on the magnitude of the number), but this is very tricky to get right.
Instead, it's possible to use the following ugly (and slow) hack: try converting the start of the string back to double, and cut the string if the result is equal to the initial number.
size_t i;
for (i = 1; i < result.size(); ++i)
{
std::istringstream cut(result.substr(0, i));
double temp;
cut >> temp; // the verbose syntax could fit into one line
if (temp == x) // by using boost::lexical_cast
break;
}
Since this is tagged C++, I assume you can use C++ features that are not available in C (if not, tell me and I'll delete this answer).
First, I suggest using a std::string instead of char* (this frees you from memory managing the buffer)? Second, I suggest using a ostringstream for the conversion:
#include <sstream>
std::string ToDecimal(double val) {
std::ostringstream oss;
oss << val;
return oss.str();
}