Probably a very simple question but I'm interested in what options there are. I have three conditions each of which should produce a different output
// special cases
if(!A && B)
return -1;
if(A && !B)
return 1;
if(!A && !B)
return 0;
// general case
return someOtherFunction(x, y);
Which I can get down to -
if(!A) {
if(!B)
return 0;
return -1;
}
if(A && !B)
return 1;
return someOtherFunction(x, y);
Can I simplify this further? This is in C++ so I am limited to using language specific operators and functions (including STL) etc.
return (!A ? (!B ? 0 : -1) : (!B ? 1 : someOtherFunction(x, y)));
This is using nested ternary operator.
Use look-up table:
int lookup[2][2] = {
{ 0, -1}
, { 1, 100}
};
...
bool A, B;
A = ...
B = ...
...
int res = lookup[A][B];
// When A && B, call other function
return res != 100 ? res : someOtherFunction(a, b);
Note: If A and B are not Boolean, convert them to logical values with the double-negation trick:
return lookup[!!A][!!B];
I would suggest you to keep it as is for the sake of readability and understanding by the fellow programmer (which might be you). Don't optimize unnecessarily unless really needed. In this case, you don't get any real advantage.
One thing you could do is to store result of A and B into variables (if they are function calls).
So interestingly the case if (A and B) is not defined.
I would use following solution, since boolean can be converted to ints.
return A - B;
Edit: the original question changed. In that case I would do:
if (!A or !B)
return A - B;
return someOtherFunction(A, B);
Related
I have a statement computing a multiply-accumulate operation that looks something like this:
return A->set(A->get() + B->get() * C->get());
Now, A, B, and C may not be unique, and I want to minimize redundant get()s. The only way I can think of optimizing this is with
if (A == B && B == C) {
double a = A->get();
return A->set(a + a * a);
} else if (A == B) {
double a = A->get();
return A->set(a + a * C->get());
} else if (A == C) {
double a = A->get();
return A->set(a + B->get() * a);
} else if (B == C) {
double b = B->get();
return A->set(A->get() + b * b);
} else {
return A->set(A->get() + B->get() * C->get());
}
Is there a more efficient way? What about generalizing this to more than three arguments??
You can store them in a map. The solution can be extended easily to arbitrarily many pointers, but I've used three here for concreteness.
std::unordered_map<MyType *, double> computed_values;
for (MyType *p: {A, B, C}) {
if (computed_values.find(p) == computed_values.end()) {
computed_values[p] = p->get();
}
}
double result = computed_values[A] + computed_values[B] * computed_values[C];
A->set(result);
As others have pointed out, make sure you profile to make sure this is actually worth the overhead of std::unordered_map lookups.
Assuming get() methods are really costly to the extent of producing measurable performance difference,
double a,b,c;
a = A->get();
b = (B==A?a:B->get());
c = (C==B?b:(C==A?a:c->get()));
return A->set(a+b*c);
Assuming the get() methods are reasonably cheap, you'd be better off just doing:
return A->set(A->get() + B->get() * C->get());
The other approach simply inserts a bunch of conditional jumps into your code, which could easily end up being more expensive than the original code.
We have two unsigned counters, and we need to compare them to check for some error conditions:
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a/2 > b) {
perror("Error happened!");
return -1;
}
The problem is that a and b will overflow some day. If a overflowed, it's still OK. But if b overflowed, it would be a false alarm. How to make this check bulletproof?
I know making a and b uint64_t would delay this false-alarm. but it still could not completely fix this issue.
===============
Let me clarify a little bit: the counters are used to tracking memory allocations, and this problem is found in dmalloc/chunk.c:
#if LOG_PNT_SEEN_COUNT
/*
* We divide by 2 here because realloc which returns the same
* pointer will seen_c += 2. However, it will never be more than
* twice the iteration value. We divide by two to not overflow
* iter_c * 2.
*/
if (slot_p->sa_seen_c / 2 > _dmalloc_iter_c) {
dmalloc_errno = ERROR_SLOT_CORRUPT;
return 0;
}
#endif
I think you misinterpreted the comment in the code:
We divide by two to not overflow iter_c * 2.
No matter where the values are coming from, it is safe to write a/2 but it is not safe to write a*2. Whatever unsigned type you are using, you can always divide a number by two while multiplying may result in overflow.
If the condition would be written like this:
if (slot_p->sa_seen_c > _dmalloc_iter_c * 2) {
then roughly half of the input would cause a wrong condition. That being said, if you worry about counters overflowing, you could wrap them in a class:
class check {
unsigned a = 0;
unsigned b = 0;
bool odd = true;
void normalize() {
auto m = std::min(a,b);
a -= m;
b -= m;
}
public:
void incr_a(){
if (odd) ++a;
odd = !odd;
normalize();
}
void incr_b(){
++b;
normalize();
}
bool check() const { return a > b;}
}
Note that to avoid the overflow completely you have to take additional measures, but if a and b are increased more or less the same amount this might be fine already.
The posted code actually doesn’t seem to use counters that may wrap around.
What the comment in the code is saying is that it is safer to compare a/2 > b instead of a > 2*b because the latter could potentially overflow while the former cannot. This particularly true of the type of a is larger than the type of b.
Note overflows as they occur.
uint32_t a, b;
bool aof = false;
bool bof = false;
if (condition_to_increase_a()) {
a++;
aof = a == 0;
}
if (condition_to_increase_b()) {
b++;
bof = b == 0;
}
if (!bof && a/2 + aof*0x80000000 > b) {
perror("Error happened!");
return -1;
}
Each a, b interdependently have 232 + 1 different states reflecting value and conditional increment. Somehow, more than an uint32_t of information is needed. Could use uint64_t, variant code paths or an auxiliary variable like the bool here.
Normalize the values as soon as they wrap by forcing them both to wrap at the same time. Maintain the difference between the two when they wrap.
Try something like this;
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a or b is at the maximum value) {
if (a > b)
{
a = a-b; b = 0;
}
else
{
b = b-a; a = 0;
}
}
if (a/2 > b) {
perror("Error happened!");
return -1;
}
If even using 64 bits is not enough, then you need to code your own "var increase" method, instead of overload the ++ operator (which may mess your code if you are not careful).
The method would just reset var to '0' or other some meaningfull value.
If your intention is to ensure that action x happens no more than twice as often as action y, I would suggest doing something like:
uint32_t x_count = 0;
uint32_t scaled_y_count = 0;
void action_x(void)
{
if ((uint32_t)(scaled_y_count - x_count) > 0xFFFF0000u)
fault();
x_count++;
}
void action_y(void)
{
if ((uint32_t)(scaled_y_count - x_count) < 0xFFFF0000u)
scaled_y_count+=2;
}
In many cases, it may be desirable to reduce the constants in the comparison used when incrementing scaled_y_count so as to limit how many action_y operations can be "stored up". The above, however, should work precisely in cases where the operations remain anywhere close to balanced in a 2:1 ratio, even if the number of operations exceeds the range of uint32_t.
When programming, I'm usually dealing with two sets of conditions combined together, like:
if (A && B){...}
else if (!A && B){...}
else if (A && !B){...}
else if (!A && !B){...}
It can also be resolved using nested if statements.
if (A){
if (B) {...}
else {...}
}
else {
if (B) {...}
else {...}
}
EDIT: Some new thoughts, what about I firstly evaluate both A and B and store as temporary variable (then do as the first approach) in case that the evaluation of A and B both have no side-effect?
So my question is there any performance difference between them and what about their readability?
I code in C++, if matters.
The two cases are not the same. In the second case, A and B will each be evaluated exactly once. In the first case, A and B will evaluated a number of times, depending upon their value.
While this almost certainly won't affect the optimization of the typical case, it will matter if A or B have side effects.
There's no way to predict which code generation strategy the compiler will choose in cases like that (and it can actually depend on surrounding context). This makes your question unanswerable in general case. One should normally expect the compiler to be smart enough to recognize the equivalence of both of your constructs (assuming they are indeed equivalent) and choose the most optimal one automatically.
The most optimal code generation strategy might be something else altogether, e.g.
// Assuming A and B are either 0 or 1
switch ((A * 2) + B) {
case 0: ...; break;
case 1: ...; break;
case 2: ...; break;
case 3: ...; break;
}
Just choose whatever makes your code more readable.
It's a hard question; honestly, I think everyone looks at this a little bit differently. As people have mentioned here it does not matter as a compiler should generate the same output for both (should! not necessarily will — it honestly depends on the code).
Yet, for example, let's look at this code:
int Nested(int a)
{
if(a > 0)
{
if( a > 1)
{
if( a % 2 == 0)
{
if( a % 10 == 4)
{
printf("a is valid");
return 1;
}
else
{
printf("a's last digit inst 4");
}
}
else
{
printf(" a is not odd");
}
}
else
{
printf(" a is not bigger than 1");
}
}
else
{
printf(" a is not bigger than 0");
}
return 0;
}
int NotNested(int a)
{
if(a <= 0)
{
printf(" a is not bigger than 0");
return 0;
}
if(a <= 1)
{
printf(" a is not bigger than 1");
return 0;
}
if(a % 2 != 0)
{
printf(" a is not odd");
return 0;
}
if( a % 10 != 4)
{
printf("a's last digit inst 4");
return 0;
}
printf("a is valid");
return 1;
}
I personally think that NotNested in my example is much more readable,
yet it's my personal opinion and both of these functions should do the same.
So yeah, in terms, of readability try to avoid nesting.
My C++ code looks like this:
int f(int i){
if (i > 0) return 1;
if (i == 0) return 0;
if (i < 0) return -1;
}
It's working but I still get:
Warning: No return, in function returning non-void
Even though it is obvious that all cases are covered. Is there any way to handle this in "proper" way?
The compiler doesn't grasp that the if conditions cover all possible conditions. Therefore, it thinks the execution flow can still fall through past all ifs.
Because either of these conditions assume the others to be false, you can write it like this:
int f(int i) {
if (i > 0) return 1;
else if (i == 0) return 0;
else return -1;
}
And because a return statement finally terminates a function, we can shorten it to this:
int f(int i) {
if (i > 0) return 1;
if (i == 0) return 0;
return -1;
}
Note the lack of the two elses.
Is there any way to handle this in "proper" way?
A simple fix is to get rid of the last if. Since the first two are either called or not the third case must be called if you get to it
int f(int i){
if (i > 0) return 1;
if (i == 0) return 0;
return -1;
}
The reason we have to do this is that the compiler cannot guarantee that your if statements will be called in every case. Since it reaches the end of the function and it might not have executed any of the if statements it issues the warning.
Just help the compiler to understand your code. Rewrite the function the following way
int f(int i){
if (i > 0) return 1;
else if (i == 0) return 0;
else return -1;
}
you could also write the function for example like
int f( int i )
{
return i == 0 ? 0 : ( i < 0 ? -1 : 1 );
}
Another way to write the function in one line is the following
int f( int i )
{
return ( i > 0 ) - ( i < 0 );
}
The compiler doesn't know that all options are covered, because in terms of your function's syntax there's nothing to suggest it.
A simplified example:
int f(int i)
if if if
(int > int), return (int == int), return (int < int), return
A clearer structure like if/else with a return in each yields an Abstract-Syntax-Tree which clearly shows there's a return in each case. Yours, however, is dependent on the evaluation of nodes in the AST, which isn't covered in the syntax check (by which you're being issued a warning).
Beyond pure syntax, if the compiler were to rely on "possible" evaluations as well in trying to figure out the behavior of your program, it would ultimately need to entangle itself and probably hitting the halting problem. Even if it managed to cover some cases, this would probably spawn more questions from users than it would answer, and also risk an entirely new level of bugs.
I am making an integer called bondPositionCounter that is supposed to return an integer based on conditions where one of the two conditions in if statements are met. However, even if one of those conditions is true, the integer method always returns 1. Without the final return line, I get an error claiming that the method must return something of type int. Why is that?
My code is below.
int bondPositionCounter(int i, int j) {
if ((g.grid.cells[i][j].isOccupied == true) && (g.grid.cells[i + 1][j].isOccupied == true)) {
g.grid.bondsh[i][j].bondUsage = true;
return 8 * i + j;
} else if ((g.grid.cells[i][j].isOccupied == true) && (g.grid.cells[i][j + 1].isOccupied == true)) {
g.grid.bondsv[i][j].bondUsage = true;
return 56 + 8 * i + j;
}
return 1;
}
In the case of a series of if-else if statements, the compiler has no way of knowing if all of them could be false. If that happens, it would reach the end of the method without returning a value, which violates its contract.
So, in this case, your return 1 happens only if your two if conditions are false. It would be semantically equivalent to end the if/else if block with an else clause that returned a value as well:
int bondPositionCounter(int i, int j) {
if (...) {
return valueA;
} else if (...) {
return valueB;
} else {
return default;
}
}
In which case you can remove the free-standing return 1 and the compiler would be happy. Essentially, for any method with a return type, for all valid code paths it must return a value.
If your intention is not for there to be a default return value, you could instead raise an Exception (I'd link, but you don't specify language and you could be either C/C++ or Java based on code) as the default case.
Without the final return line, I get an error claiming that the method
must return something of type int. Why is that?
because when you declare a method with a return type it is mandatory for a method to return something
Lets take an example
public int checkHowReturnStatementWorks(){ // this method will return int
if(condition a){ // condition going to be resolved at runtime
return 1;
}
else if(condition b){
return 2;
}
}
Now suppose at runtime both the conditions are not met then what your method will return ,
no idea
, the same doubt comes to compiler that is why compiler is giving error at compiler time only that you need to add a return statement .
A piece of suggestion
if ((g.grid.cells[i][j].isOccupied == true)
&& (g.grid.cells[i + 1][j].isOccupied == true)) {
}
can be replaced by
if ((g.grid.cells[i][j].isOccupied)
&& (g.grid.cells[i + 1][j].isOccupied )) {
}