Conditioning for the four cases of the signs of two numbers - c++

I have two numbers A and B. I would like to condition for the four cases of the signs of these two numbers. We could do
if ((A >= 0) && (B >= 0)){
// Do something
};
if ((A >= 0) && (B < 0)){
// Do something
};
if ((A < 0) && (B >= 0)){
// Do something
};
if ((A < 0) && (B < 0)){
// Do something
};
One could produce a function that outputs different values in each case and then use a switch{ case:} statement. For the functions I have thought this doesn't improve the number of comparisons, so there is no much gain.
Which way is recommended for doing this conditioning?
Well, I guess some of those if-s could be put inside else-s of the others so that not all the conditions have to be evaluated always.

if (A >= 0)
{
if (B >= 0)
{
}
else // B < 0
{
}
}
else // A < 0
{
if (B >= 0)
{
}
else // B < 0
{
}
}

Related

how to get rid of warning: control reaches end of non-void function c++

I wrote this code and don't understand why there´s a warning, as far as I can tell every branch has a return value. How could I fix this?
bool ValidDate(int d, int m, int a) {
if ((m < 1) || (m > 12)) {
return false;
} else {
if ((m == 1) || (m == 3) || (m == 5) || (m == 7) || (m == 8) || (m == 10) || (m == 12)) {
if (d >= 1 && d <= 31) {
return true;
} else {
return false;
}
} else if ((m == 4) || (m == 6) || (m == 9) || (m == 11)) {
if (d >= 1 && d <= 30) {
return true;
} else {
return false;
}
} else if (m == 2) {
if (a % 4 == 0) {
if (d >= 1 && d <= 29) {
return true;
} else {
return false;
}
} else {
if (d >= 1 && d <= 28) {
return true;
} else {
return false;
}
}
}
}
}
I undestand what the error means but can´t find where the problem is.
The warning arises because the compiler does not know that the else if (m == 2) condition will always be true when that condition is checked, as all other possibilities must have been exhausted. Since the compiler does not perform this kind of analysis, you as the programmer might as well help the compiler by explicitly saying so by just removing that check. You can still leave in a comment saying "m must be 2" to help human readers of the code.
The nested if-else branches can also be simplified considerably by noting the following equivalent constructs:
A check like
if (expr)
return true;
else
return false;
can always be replaced by
return expr;
Similarly, if you're returning at the end of a branch, the subsequent else is redundant. i.e.
if (expr1) {
// ...
return // ...;
}
else if (expr2) {
// ...
return // ...;
}
can be replaced by
if (expr1) {
// ...
return // ...;
}
if (expr2) { // the else is redundant here
// ...
return // ...;
}
Applying these transformations give a cleaner function:
bool ValidDate2(int d, int m, int a) {
if ((m < 1) || (m > 12))
return false;
if ((m == 1) || (m == 3) || (m == 5) || (m == 7) || (m == 8) || (m == 10) || (m == 12))
return d >= 1 && d <= 31;
if ((m == 4) || (m == 6) || (m == 9) || (m == 11))
return d >= 1 && d <= 30;
// Now m must be 2
return a % 4 == 0 ?
d >= 1 && d <= 29 :
d >= 1 && d <= 28;
}
Note that I've replaced the last if-else by a ternary operator ?:, though whether this makes the code more readable is subjective. Certainly nesting multiple ?: can make it harder to see the structure of the branches.
Here's a demo.
Another way of restructuring the code is to use a switch statement for all the different values of m. This reduces the complexity of the if conditionals, and can make the code easier to read:
bool ValidDate2(int d, int m, int a) {
switch(m) {
case 1: [[fallthrough]];
case 3: [[fallthrough]];
case 5: [[fallthrough]];
case 7: [[fallthrough]];
case 8: [[fallthrough]];
case 10: [[fallthrough]];
case 12: return d >= 1 && d <= 31;
case 4: [[fallthrough]];
case 6: [[fallthrough]];
case 9: [[fallthrough]];
case 11: return d >= 1 && d <= 30;
case 2: return a % 4 == 0 ?
d >= 1 && d <= 29 :
d >= 1 && d <= 28;
default: return false; // m < 1 or m > 12
}
}
Here's a demo.

How to make a loop to determine if 2 numbers belong in a given range

I am having problems making a loop which stops when both x and y are in the range/interval [0,1] in c++.
double x;
double y;
while(condition)
{
if(x < 0)
{
x = -x;
}
else
{
x = 2 - x;
}
if(y < 0)
{
y = -y;
}
else
{
y = 2 - y;
}
}
This method with 2 loops works:
while((x < 0) || (x > 1)) {do sth}
while((y < 0) || (y > 1)) {do sth}
This doesn't work:
while(!((x >= 0) && (x <= 1)) && !((y >= 0) && (y <= 1))) {do sth}
And this doesn't work either:
while(((x < 0) || (x > 1)) && ((y < 0) || (y > 1))) {do sth}
This makes an infinite loop (in my case):
while(((x < 0) || (x > 1)) || ((y < 0) || (y > 1))) {do sth}
Note: {do sth} changes x and y if needed so they will eventually go in that interval (same as in the first block of code).
Note 2: By doesn't work I mean it never goes in the loop when x is in the interval and y < 0 (and some other cases).
while ( !( (x>=0 && x<=1) && (y>=0 && y<=1) ) ) should be the combined conditional check.
I'd go for a dedicated function with a speaking name: so you can still understand your code in a couple of weeks :-), e.g.
auto check_outside_interval_0_1 = [] (double const a) {
return a < 0.0 or 1.0 < a;
};
while( check_outside_interval_0_1(x) or
check_outside_interval_0_1(y) ) {
// ... do your things here
}

How can I reduce the time complexity of the following block of code?

I am taking 1 to n digits and finding count of numbers that are divisible by a or b but not divisible by both.
I want to reduce time complexity of this block by some logical change.
cin >> n >> a >> b >> k;
for(int i = 1; i <= n; i++) {
if(i % a == 0 && i % b==0) {
count++;
} else if(i % b == 0 && i % a != 0) {
count++;
}
}
Calculate the count of numbers divisible by a, add it to the count of numbers divisible by b, subtract it with twice the count of numbers divisible by the lcm (lowest common multiple) of a,b.
Time complexity: O(log(min(a,b)))
Because to calculate Lowest common multiple you calculate gcd (Greatest common divisor) which can be calculated in O(log(min(a,b)))
Note: If you include bits/stdc++.h, you can use the inbuilt function to calculate gcd: __gcd(int , int )
int lcm(int a, int b) {
return (a * b)/__gcd(a,b);
}
cin>>n>>a>>b>>k;
int divisible_by_a = n / a;
int divisible_by_b = n / b;
int divisible_by_both = n / lcm(a,b);
ans = divisible_by_a + divisible_by_b - 2*divisible_by_both;
It seems to me that your code don't work as you describe: it counts for every number divisible by b. You should check if i is multiple of a or b
if (i % a == 0 && i % b != 0) {...
} else if (i % a != 0 && i % b == 0) {...
}
I also suggest to you a different approach: find multiples of a and b untill you reach n and count that numbers. remove same numers in lists from the sum (better if you do that before the final sum)
Before optimizing it, make sure it works first.
Right now, you're checking if a number is divisible by only b or by both a and b. To make it a or b but not both, you need to switch i % b==0 to i % b!=0 in the first condition:
for(int i = 1; i <= n; i++) {
if(i % a == 0 && i % b!=0) {
count++;
} else if(i % b == 0 && i % a != 0) {
count++;
}
}
One small thing you can do to speed things up is to do the divisibility check just once each and save the result instead of twice. Then you can use a single XOR for the final result.
for(int i = 1; i <= n; i++) {
int div_a = (i % a == 0);
int div_b = (i % b == 0);
if (a ^ b) {
count++;
}
}
Let's start with this:
temp = a;
while(temp < n) {
if(temp%b != 0) {
count++;
}
temp += a;
}
temp = b;
while(temp < n) {
if(temp%a != 0) {
count++;
}
temp += b;
}
Next, consider some cheats. If a%b == 0 then any number divisible by a will also be divisible by b; and similar for b%a == 0. In both cases the count must be zero.
If a == 0 then no number is divisible by a; and similar for b == 0; and if both a and b are zero then the count must be zero.
Finally; don't forget that (in C) the behavior of x%0 is undefined and you need to guard against that.
Combining all of the above you get something like:
if( (a == 0) && (b == 0) ) {
return 0;
}
if( (a != 0) && (b != 0) ) {
if( (a%b == 0) || (b%a == 0) ) {
return 0;
}
}
count = 0;
if(a != 0) {
temp = a;
while(temp < n) {
if(temp%b != 0) {
count++;
}
temp += a;
}
}
if(b != 0) {
temp = b;
while(temp < n) {
if(temp%a != 0) {
count++;
}
temp += b;
}
}
return count;
Next round of cheats:
If n <= 1 then the count must be zero.
If a == 1 or a == -1 then all numbers are divisible by a.
If b == 1 or b == -1 then all numbers are divisible by b.
To deal with these I'd move to "nested switch" to minimise the number of branches, like:
switch(a) {
case 0:
switch(b) {
case 0:
...
break;
case -1:
case 1:
...
break;
default:
...
break;
}
break;
case -1:
case 1:
switch(b) {
case 0:
...
break;
case -1:
case 1:
...
break;
default:
...
break;
}
break;
default:
switch(b) {
case 0:
...
break;
case -1:
case 1:
...
break;
default:
...
break;
}
break;
}

Why doesn't this output "Please try again" when loop runs again?

Hello I am trying to learn c++ and I wanted to give a little practice with a program. However I'm having trouble using cout within the loop.
This is the loop I'm trying to output text from. When the user enters a number that isn't valid it is supposed to say "Sorry try again!"
while (datecheck)
{
bool check(false);
if (check)
std::cout<<"Sorry try again!"<<std::endl;
std::cin>>c;
if (c >= 1)
{
if (b == 2 && c <= 28)
datecheck = false;
if (b == 2 && a % 4 == 0 && c <= 29)
datecheck = false;
if (b == 4 || b == 6 || b == 9 || b == 11 && c <= 30)
datecheck = false;
if (c <= 31)
datecheck = false;
}
check = true;
}
When it outputs and I purposely keep myself in the loop it doesn't output anything
Year: -20
-20
-20
You declare a fresh new variable check at every iteration. And you initialize that variable to false every time. So move that declaration before the while loop.
Change this:
while (datecheck)
{
bool check(false);
...
check = true;
}
to this:
bool check(false);
while (datecheck)
{
...
check = true;
}
The problem is with declaration of bool check(false);. This keeps on re-assigning value to false at beginning of each iteration.
A simple fix could be to get-rid of use of check variable and use only datecheck.
bool datecheck(true);
while (true)
{
std::cin>>c;
if (c >= 1)
{
if (b == 2 && c <= 28)
datecheck = false;
if (b == 2 && a % 4 == 0 && c <= 29)
datecheck = false;
if (b == 4 || b == 6 || b == 9 || b == 11 && c <= 30)
datecheck = false;
if (c <= 31)
datecheck = false;
}
if (datecheck)
{
std::cout<<"Sorry try again!"<<std::endl;
}
else
{
break;
}
}

If statement with 3 conditions (triangleExists)

Check if TriangleExists: it is when every 1 of its side is smaller than the sum of the 2 others.
I tried a lot of options:
float a=3, b=15, c=7; //its still taking 'y'
bool triangleExists(float a, float b, float c)
{
if ((a < (b + c)) || (b < (a + b)) || (c < (a + b)))
{
std::cout << "y" << std::endl;
return true;
}else
std::cout << "n" << std::endl;;
return false;
}
Options I tried (they were also tried with && marks):
if ((a < (b + c)) || (b < (a + b)) || (c < (a + b)))
if ( a < (b + c) || b < (a + b) || c < (a + b))
if ((a < (b + c))==true || (b < (a + b))==true || (c < (a + b))==true)
if (a < b + c || b < a + b || (c < a + b)
I'm probably missing something simple. I'll be glad if you can help.
In your middle condition, you have b < (a + b), when it should be b < (a + c)
Along with the typo that #Zackary Murphy already pointed out, you have a more fundamental problem with your logic.
In particular, your function should return true only if all three conditions are passed. With the middle term corrected to b < (a + c), it still returns true (and prints y) even though the numbers you've specified can't form a triangle.
For example:
#include <iostream>
bool triangleExists(float a, float b, float c)
{
if ((a < (b + c)) || (b < (a + c)) || (c < (a + b)))
{
std::cout << "y" << std::endl;
return true;
}
else
std::cout << "n" << std::endl;;
return false;
}
int main() {
float a = 3, b = 4, c = 500; //its still taking 'y'
triangleExists(a, b, c);
}
... prints y, even though sides of 3, 4 and 500 can't form a triangle.
To get correct behavior, you can change from using || to && (i.e., from or to and). Alternatively, you can invert the test and invert the results--that is, if a > (b + c) || b > (a + c) || c > (a + b), then return false. Only otherwise, return true.