Why do i get 0 instead of negative number when subtracting? - c++

I was trying to solve "codewars" kata. And it looked pretty easy at first. When I wrote the program, it was working correctly only with a positive return value. So, when the result is a positive number, it's OK, however, when trying to subtract, I always get 0 instead of a negative number. I thought that the problem could be with type of the int. So I tried to change it to signed int. But it didn't help.
So, the task sounds like this: you have to make addition and subtracting on a given string. The return value must also be a string.
Examples:
"1plus2plus3plus4" --> "10"
"1plus2plus3minus4" --> "2"
Here is my code:
#include <string>
std::string calculate(std::string str)
{
std::string temp; signed int result = 0;
for (auto& x : str)
{
if (std::isdigit(x) && result == 0 )
result = std::stoi(std::string(1,x));
if (std::isdigit(x) && result !=0 )
{
if (temp == "plus") // if it's operation PLUS than add
{
result += std::stoi(std::string(1,x)); // c++always get 0 instead of signed int
}
else // if operation MINUS than subtract
{
result -= std::stoi(std::string(1,x)); // here always get result as 0
}
temp = "";
}
if (std::isalpha(x)) temp += x;
}
return std::to_string(result-1);
}

Your loop should not be checking for result == 0/result != 0 to know if result has a value. Think of what happens if the running result is actually 0 halfway through the iteration, ie "1plus1minus...".
If you step through your code with a debugger, you would see that on the very 1st iteration, x is '1', so if (std::isdigit(x) && result == 0 ) is true, so result gets set to 1, but then the following if (std::isdigit(x) && result !=0 ) is now true. But temp has not been set to anything yet, so if (temp == "plus") is false, and the loop falls into the code that subtracts from result, thus making it 0, when it should not be changing result at all.
Try something more like this instead:
#include <string>
std::string calculate(const std::string &str)
{
std::string temp;
int result = 0;
if (!str.empty() && std::isdigit(str[0]))
{
result = str[0] - '0';
for (size_t i = 1; i < str.size(); ++i)
{
char x = str[i];
if (std::isdigit(x))
{
int num = (x - '0');
if (temp == "plus")
{
result += num;
}
else if (temp == "minus")
{
result -= num;
}
temp = "";
}
else if (std::isalpha(x))
temp += x;
}
}
return std::to_string(result);
}
Demo

Related

For reversing a number in C++ which ends with zeros

I want to write a program for reversing a number. For reversing a number like 2300 to 32 so that the ending zeros are not printed, I found this method:
#include<iostream>
using namespace std;
int main()
{
int l;
cin>>l;
bool leading = true;
while (l>0)
{
if ((l%10==0)&& (leading==true))
{
l /= 10;
leading = false; // prints 032 as output
continue;
}
// leading = false; this prints correct 32
cout<<l%10;
l /= 10;
}
return 0;
}
The instruction of assigning boolean leading false inside the if statement is not giving a valid answer, but I suppose assigning it false should give 32 as output whether we give it outside or inside if statement as its purpose is just to make it false once you get the last digit to be a non zero.
Please tell the reason of difference in outputs.
The reason for the difference in output is because when you make leading = false inside the if statement, you are making it false right after encountering the first zero. When you encounter the remaining zeroes, leading will be false and you will be printing it.
When you make leading = false outside the if statement, you are basically waiting till you encounter all zeroes before making it false.
If you are looking to reverse a number, this is the well known logic to do so:
int reverse(int n)
{
int r; //remainder
int rev = 0; //reversed number
while(n != 0)
{
r = n%10;
rev = rev*10 + r;
n /= 10;
}
return rev;
}
EDIT:
The above code snippet is fine if you just want to understand the logic to reverse a number. But if you want to implement the logic anywhere you have to make sure you handle integer overflow problems (the reversed number could be too big to be stored in an integer!!).
The following code will take care of integer overflow:
int reverse(int n)
{
int r; //remainder
int rev = 0; //reversed number
while(n != 0)
{
r = n%10;
if(INT_MAX/10 < rev)
{
cout << "Reversed number too big for an int.";
break;
}
else if(INT_MAX-r < rev*10)
{
cout << "Reversed number too big for an int.";
break;
}
rev = rev*10 + r;
n /= 10;
}
if(n != 0)
{
//could not reverse number
//take appropriate action
}
return rev;
}
First, rewrite without continue to make the flow clearer,
while (l > 0)
{
if ((l % 10 == 0) && (leading == true))
{
l /= 10;
leading = false; // prints 032 as output
}
else
{
// leading = false; this prints correct 32
cout << l % 10;
l /= 10;
}
}
and move the division common to both branches out of the conditional,
while (l > 0)
{
if ((l % 10 == 0) && (leading == true))
{
leading = false; // prints 032 as output
}
else
{
// leading = false; this prints correct 32
cout << l % 10;
}
l /= 10;
}
and now you see that the only difference between the two is the condition under which the assignment leading = false happens.
The correct version says, "If this digit is non-zero or a non-leading zero, remember that the next digit is not a leading zero, and print this digit. Then divide."
Your broken version says, "If this is a leading zero, the next digit is not a leading zero." which is pretty obviously not the case.
Just try this ,
#include <iostream>
using namespace std;
int main() {
int n, reversedNumber = 0, remainder;
cout << "Enter an integer: ";
cin >> n;
while(n != 0) {
remainder = n%10;
reversedNumber = reversedNumber*10 + remainder;
n /= 10;
}
cout << "Reversed Number = " << reversedNumber;
return 0;
}
Working for me...
When reversing digits of numbers or generally when working with digits and the actual
value does not matter then treating the number as an array of digits is simpler than working with the whole int. How to treat a number as an array of digits conveniently? std::string:
#include <iostream>
#include <string>
#include <sstream>
int reverse_number(int x) {
std::string xs = std::to_string(x);
std::string revx{ xs.rbegin(),xs.rend()};
std::stringstream ss{revx};
int result;
ss >> result;
return result;
}
int main() {
std::cout << reverse_number(123) << "\n";
std::cout << reverse_number(1230) << "\n";
}
std::to_string converts the int to a std::string. std::string revx{ xs.rbegin(),xs.rend()}; constructs the reversed string by using reverse iterators, and eventually a stringstream can be used to parse the number. Output of the above is:
321
321

C++ I need to check if a two-digit number contains a 0 or not

I am making a program where I need to check if a two-digit number like 76 or 70 contains a 0 or not.
with 76 the outcome would be false
with 70 true
I can't seem to make something up and I am still stuck with nothing not knowing how to start.
you can convert the number to string and check if first or second char is '0'
bool containsZero (int x) {
string tmp = to_string(x);
if (tmp[0] == '0' || tmp[1] == '0')
return true;
return false;
}
or divide the number on 10 twice and check if every digit is 0 or not
bool containsZero (int x) {
while (x != 0)
{
if (x % 10 == 0)
return true;
x = x / 10;
}
return false;
}
The only two-digit numbers that contain zeros are those divisible by 10, so
bool has_zero = number % 10 == 0;
Suppose the number is x
You can check easily for a two digit number by using the condition:
if((x%10==0)||(x/10)%10==0))
{
//number has zero
}
else
{
//number does not have zero
}
If you want to check digit by digit, Then the initial logic could be:
Convert Number to string (To iterate over it)
Loop over the number
Check if the single-digit is equal to '0' or not
#include <iostream>
#include <string>
using namespace std;
int main() {
bool ischeck = false;
int x = 67;
string a = to_string(x);
for(int i=0;i <a.length();i++)
{
if(a[i]=='0')
{
ischeck = true;
break;
}
}
if(ischeck)
{
cout<<"True\n";
}
else{
cout<<"False\n";
}
}
Else the Logic Explained by #freakish is best. In that case program would be
#include <iostream>
#include <string>
using namespace std;
int main() {
int x = 70;
if(x%10==0)
{
cout<<"True";
}
else{
cout<<"False";
}
}
The 2nd logic will not work in case of Numbers like "05" or "07" but 1st logic will work in everycase.
If it is only for a two-digit number you can do the following inside a function which's return parameter would be a boolean value:
bool contains_zero(int num) {
int rem = num % 10;
return rem == 0;
}

accumulate with custom sum

The function below convert a string to integer, making use of std::accumulate.
It first checks the presence of a sign and skips it.
The parameter c of lambda is fine as it just goes through all the remaining characters of input string s. But what about the first lambda parameter sum? How does it know that it should initialise sum to zero? And does the order of these lambda parameters matter?
int string2int(const string &s)
{
return (s[0] == '-' ? -1 : 1) *
accumulate(begin(s) + (s[0] == '-' || s[0] == '+'), end(s), 0,
[](int sum, char c) {
return sum * 10 + c - '0';
});
}
Btw, equivalent code without using std::accumulate would look something like this:
int string2int(const string &s)
{
int sign = (s[0] == '-' ? -1 : 0);
sign = (s[0] == '+' ? 1 : sign);
int index = 0;
if(sign != 0)
{
++index;
}
int result = 0;
for (auto i = index; i < s.size(); ++i)
{
result = result * 10 + (s[i] - '0');
}
sign = (sign < 0 ? -1 : 1);
return result * sign;
}
The parameter between end(s) and the lambda is the initial value.
Could be 1, for example, if you wanted product.
The first lambda parameter is the accumulated data, the second is the current element of the sequence.

add strings without using builtin library function, what am i doing wrong?

The resultnum value of this function is "01" if i try to add two strings x and y with values "0" "1". If i tried using resultnum.find_first_of("0") it returns position as -1 instead of 0 .... i just want to get rid of that leading zero and i am unable to get rid of it... Maybe i am doing some silly mistake but please help me identify why it is returning -1 for position of 0 in result.
string addStrings(string num1, string num2) {
char carry = {0},x={0},y={0},z={0};
std::string resultnum;
long loopUnitl=std::max(num1.size(),num2.size());
long maxSize = loopUnitl+1;
resultnum.reserve(maxSize);
std::string::reverse_iterator rnum1_it=num1.rbegin();
std::string::reverse_iterator rnum2_it=num2.rbegin();
while(loopUnitl)
{
if(rnum1_it != num1.rend())
{
x = *rnum1_it;
rnum1_it++;
}
else
{
x = '0';
}
if(rnum2_it != num2.rend())
{
y = *rnum2_it;
rnum2_it++;
}
else
y = '0';
z = (x -'0') + (y - '0') + carry;
if (z > 9)
{
carry = 1;
z -= 10;
}
else
{
carry = 0; //Else no carry was generated
}
resultnum[loopUnitl] = (z+'0');
loopUnitl=loopUnitl-1;
if(loopUnitl==0)
{
resultnum[loopUnitl] = carry+'0';
resultnum[maxSize]='\0';
}
}
return resultnum;
}
You need to use resultnum.resize() instead of resultnum.reserve().
Your use of operator[] to insert chars into resultnum is undefined behavior, because the valid range for accessing characters is [0, size()), not [0, capacity()) (had you used the at() method instead of operator[], your code would have raised exceptions warning you about indexes being out of range).
Alternatively, if you want to keep using reserve(), you should use the insert() method to add characters to the front of the string on each loop iteration, instead of using operator[].
A string's size() and capacity() are two different things. The capacity() is how much memory the string has physically allocated to hold characters, but the size() is how many of those characters are actually valid data. Operations like searching act on size(), not capacity().
Since the string's size() is never > 0, that is why find_first_of() returns -1.
Thank you so much for your suggestions and reply. I did change the above code to not use [] operator and just added to the string and finally reversed the string and now code works perfectly.I am so thankful to you :) .
string addStrings(string num1, string num2) {
char carry = {0};
std::string resultnum;
char x={0},y={0};
char z={0};
long loopUnitl=std::max(num1.size(),num2.size());
long maxSize = loopUnitl+1;
resultnum ="";
std::string::reverse_iterator rnum1_it=num1.rbegin();
std::string::reverse_iterator rnum2_it=num2.rbegin();
while(loopUnitl)
{
if(rnum1_it != num1.rend())
{
x = *rnum1_it;
rnum1_it++;
}
else
{
x = '0';
}
if(rnum2_it != num2.rend())
{
y = *rnum2_it;
rnum2_it++;
}
else
y = '0';
z = (x -'0') + (y - '0') + carry;
if (z > 9)
{
carry = 1;
z -= 10;
}
else
{
carry = 0; //Else no carry was generated
}
resultnum += (z+'0');
loopUnitl=loopUnitl-1;
if(loopUnitl==0)
{
if(carry)
resultnum += (carry+'0');
}
}
std::reverse(resultnum.begin(),resultnum.end());
return resultnum;
}

Decimal to Binary Signed in C++

This is what I have:
string decimal_to_binary(int n){
string result = "";
while(n > 0){
result = string(1, (char) (n%2 + 48)) + result;
n = n/2;
}
return result; }
This works, but it doesn't work if I put a negative number, any help?
Just
#include <bitset>
Then use bitset and to_string to convert from int to string
std::cout << std::bitset<sizeof(n)*8>(n).to_string();
It works for negative numbers too.
Well I would recommend calling a separate function for negative numbers. Given that, for example, -1 and 255 will both return 11111111. Converting from the positive to the negative would be easiest instead of changing the logic entirely to handle both.
Going from the positive binary to the negative is just running XOR and adding 1.
You can modify your code like this for a quick fix.
string decimal_to_binary(int n){
if (n<0){ // check if negative and alter the number
n = 256 + n;
}
string result = "";
while(n > 0){
result = string(1, (char) (n%2 + 48)) + result;
n = n/2;
}
return result;
}
This works, but it doesn't work if I put a negative number, any help?
Check whether the number is negative. If so, call the function again with -n and return the concatenated result.
You also need to add a clause to check against 0 unless you want to return an empty string when the input is 0.
std::string decimal_to_binary(int n){
if ( n < 0 )
{
return std::string("-") + decimal_to_binary(-n);
}
if ( n == 0 )
{
return std::string("0");
}
std::string result = "";
while(n > 0){
result = std::string(1, (char) (n%2 + 48)) + result;
n = n/2;
}
return result;
}