I'm maintaining some code and came across this snippet:
int num = 0;
float sum = 0.0;
bool value[rows][cols]; //initialized elsewhere in the code
for(int i = 0; i < rows; i++)
for(int j = 0; j < cols; j++)
if(value[i][j] == true) {
sum += value[i][j]; //shouldn't this be equivalent to "sum += 1;"
//as it is in the if block?
num++;
}
float ans = 1.0;
if(num > 12)
ans = sum / num;
Is the guy who wrote this code originally doing something fiendishly clever here, or should ans always be 1? As far as I can tell, num and sum should always be exactly the same value, no?
This will the same as sum += 1 since a true value will be converted to 1 this is covered in the draft C++ standard section 4.9 Floating-integral conversions which says:
If the source type is bool, the value
false is converted to zero and the value true is converted to one.
The additive operators will cause the usual arithmetic conversions to be performed on their operands. Which in this case will be covered by this case:
Otherwise, if either operand is float, the other shall be converted to float.
and we know that E1 += E2 is equivalent to E1 = E1 + E2 from section 5.17 Assignment and compound assignment operators which says:
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is
evaluated only once.[...]
The answer is not fiendlishly clever because the if statement is still present.
To be clever, one would do something like this:
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
sum += value[i][j]; // Add 1 if true, 0 if false.
num += value[i][j]; // Add 1 (increment) if true, add 0 if false
}
}
The assumption is that a bool type will convert to 1 if true, and 0 if false. This is how things were done in the dawn of computers.
If the true evaluates to some nonzero value other than 1, this code will not work correctly.
Upon further analysis, the sum and num will have the same value at the end of the loops.
So, only use num and convert to float at the end of the loop.
If value is a (two-dimensional) array of bool, then this is equivalent with sum += 1. In contrast with what some people think, a comparison with == true is not the same as an implicit conversion to bool (e. g. in the context of an if statement's condition). Any integer not equal to 1 will be considered different from true.
Related
In the following piece of code the output is 1 but I'm not sure why. Has i been implicitly changed to a boolean? How can an integer value be set to an expression like this?
#include <iostream>
using namespace std;
int main (int argc, const char *argv[])
{
int a = 1, b = 1, c = 1, i = 1;
i = b < a < c;
cout << i;
return 0;
}
Has i been implicitly changed to a boolean?
No. Rather, a boolean expression has been implicitly converted to int, then stored in i, as commented by #WhozCraig.
How can an integer value be set to an expression like this?
Because it follows the C++ Standard.
When you do:
i = b < a < c;
since the first < and the second < have the same operator precedence (since they are the same operator), so:
Operators that have the same precedence are bound to their arguments
in the direction of their associativity. For example, the expression a
= b = c is parsed as a = (b = c), and not as (a = b) = c because of right-to-left associativity of assignment, but a + b - c is parsed (a > + b) - c and not a + (b - c) because of left-to-right associativity of addition and subtraction.
as mentioned in C++ Operator Precedence, which means that this expression of yours will be parsed as if it was written like this:
i = (b < a) < c;
which will evaluate the condition inside the parentheses, which is False.
Now bool to int conversion is implicit:
ยง4.7/4 from the C++ Standard says (Integral Conversion)
If the source type is bool, the value false is converted to zero and the value true is converted to one.
which means that false will be converted to 0, and then we basically end up doing:
i = 0 < c;
which evaluates to true, since c is equal to 1. Now i is of type int, which means that another, second implicit conversion from boolean to integer takes place, eventually assigning 1 to i.
In the following code
#include <iostream>
using namespace std;
int main(void){
double *x, *y;
unsigned long long int n=2;
x = new double [2];
y = new double [2];
for(int i=0; i<2; i++){
x[i] = 1.0;
y[i] = 1.0;
//what is the following line doing exaclty?
x[i] = y[i]/=((double)n);
cout << "\n" << x[i] << "\t" << y[i];
}
delete [] x;
delete [] y;
printf("\n");
return 0;
}
I do not understand what the combination of = and /= is doing exactly, and why this is allowed (the code compiles and runs correctly under Valgrind).
This code
x[i] = y[i]/=((double)n);
is logically equivalent to this 2 lines:
y[i]/=((double)n);
x[i] = y[i];
and first line is logically equal to:
y[i] = y[i] / n;
note typecasting here is completely redundant.
The following 2 symbols: = and /= are assignment operators. They are used to set the variable on the right to the value or variable on the right. The = operator is simple; it does no operation on the value on the left. So, if we have a statement like:
int x = 5;
The equality assignment operator here simply sets x to 5.
The second operator in the line of code you are confused about is a part of the compound assignment operator group. This operator does 2 operations: it first takes the value stored in the variable on the left side of the operator, divides it by the value on the right side of the operator, and stores it again in the variable on the left side of the operator. Therefore, if we take this simple piece of code:
int y = 25;
y /= 5;
This piece of code declares a variable of type int, initialized to 25. The second line divides the value of y by 5, ad updates the variable y with the resulting value of the mathematical operation.
Now, we are not restricted to having a fixed value, a variable, or a function's return value as a statement on the right side of the assignment operator. We can very well evaluate an expression (like here we do y[i] /= ((double)/n), and then assign the updated value of y[i] to x[i]. The compiler merely evaluates the expression on the right first, and then moves on to assign it to the left-hand variable.
Now, having this explaination, we can summarize this line very easily:
x[i] = y[i]/=((double)n);
The compiler divides the value of y[i] by the value n, casted as a double (unrequired here as y itself is of type double), assigns the new value to y[i], and then assigns x[i] the updated value of y[i].
Both are assignment operators and assignment operators are evaluated from right to left. Therefore (assuming that n != 0) the combined assignment does the same as this:
y[i] /= ((double)n);
x[i] = y[i];
And of course the first statement can also be written as:
y[i] = y[i] / ((double)n);
I wrote this small function that will take and integer k, and return the product:
2(0)+1 . 2(1)+1 . 2(2)+1 . ... 2n+1 || for n=0,n<(k/2)-1
if k is even, (or 0, I'm not sure if technically zero is an even number) And 0 if k is odd.
This was part of a larger project but I was able to isolate the problem to this function, and I pulled it out to try and figure out what was going on. Here is my function.
double Product_2np1(int k)
{
int prod = 1;
if(k % 2 == 0)
{
for(int n = 0; n <(k/2);n++){
prod = prod * ((2*n)+ 1);
}
return prod;
}else return 0;
}
int main(){
for(int i=0; i<5;i++)
{
std::cout <<"k= " << i<< "==>" << Product_2np1(i) << std::endl;
}
return 0;
}
The output:
k= 0 ==> 2.64619e-260
k= 1 ==> 0
k= 2 ==> 2.64619e-260
k= 3 ==> 0
k= 4 ==> 2.64619e-260
k= 5 ==> 0
Now this was nonsense to me, so I went back into the function and threw in some prints to see what was going on. Changing Product_2np1 to this:
double Product_2np1(int k)
{
int prod = 1;
if(k % 2 == 0)
{
for(int n = 0; n <(k/2);n++){
std::cout << "(2*" << n << ")+ 1)" <<std:endl;
}
return 1;
}else return 0;
}
and In main I only had the k=4 case evaluate:
int main(){
Product_2np1(4);
return 0;
}
This gave me the output:
2(0)+1
2(1)+1
Using my handy-dandy TI-86 I punched this in to make sure I wasn't loosing it and I get
2(0)+1 = 0+1 =1
2(1)+1 = 2+1 =3
and multiplying those together should give me 3, not 2.64619e-260.
So I have to ask you folks what could possibly be going on here?
The problem is your datatype - your function double Product_2np1(int k) returns double while prod is an int. I do not know which compiler you are using (maybe Turbo C) - but you should have got at least a warning regarding this. Normally the type conversion happens from smaller to larger - hence is think the result here i undefined - see this Sample on Ideone. The problem is that we are trying a forced conversion from int to double which is the problem.
#include <cstdio>
int main()
{
printf("%lf", 2);
printf("\n%lf", 2.0);
return 0;
}
Output:
Success time: 0 memory: 3340 signal:0
0.000000
2.000000
From the C standard (1999):
6.3.1.4 Real floating and integer
1 When a finite value of real floating type is converted to an integer
type other than _Bool, the fractional part is discarded (i.e., the
value is truncated toward zero). If the value of the integral part
cannot be represented by the integer type, the behavior is undefined.
From the C++ standard (2003):
4.9 Floating-integral conversions [conv.fpint] 1 An rvalue of a floating point type can be converted to an rvalue of an integer type.
The conversion truncates; that is, the fractional part is discarded.
The behavior is undefined if the truncated value cannot be represented
in the destination type. [Note: If the destination type is bool, see
4.12. ]
I've been trying to understand how post and pre increments work lately and I've been over thinking it too much.
Does "Product" become 25 after one iteration?
Product *=5++
And does "Quotient" become 5/6 after one iteration?
Quotient /= ++x
5++ is just incorrect.
Quotient /= ++x; is the same as x = x + 1; Quotient = Quotient / x; (assuming these are just plain numbers).
Your code isn't valid C++, since the built-in post-increment operator may only be applied to lvalues, but literal integers are rvalues.
Beside that, the value of a (built-in) pre-increment expression is the incremented value, while the value of a post-increment expression is the original value.
Pre-increment modifies the variable and evaluates to the modified value.
Post-increment evaluates to the value of the variable and then increments the variable.
int a = 5;
int b = ++a; // a = a + 1; b = a
int c = a++; // c = a; a = a + 1
Consider these simple implementations of ++ for int
int& int::preincrement()
{
this->m_value += 1;
return *this;
}
int int::postincrement()
{
int before = this->m_value;
this->m_value += 1;
return before;
}
Does this result in undefined behaviour because the order of evaluation will be unspecified?
int i = 0, j = 0, k = 0;
int result = i++ + ++j + k++;
No, the result of the evaluation doesn't depend on the unspecified order of evaluation of the sub-expressions.
Undefined behavior only occurs in this situation if two side effects that affect the same object are unsequenced relative to each other or a side effect and a value computation of the same object are unsequenced. The side-effect and value computation of both prefix and postfix increment are explicitly sequenced.
The order of evaluation is unspecified, but who cares? Each operand acts on a completely distinct object. Nothing undefined here.
No, the behavior is perfectly well-defined: j is incremented, then addition is performed, then i and k are incremented. The only thing that is unspecified is the order in which the increments on i and k are performed. The postcondition is i==1, j==1, k==1, result==1.
The rule is that the results are unspecified if you modify a variable more than once. You haven't done that in your example.
It's fine here because you don't use the same variable twice.
What you have is equivalent to:
int i = 0, j = 0, k = 0;
++j;
int result = i + j + k;
++i;
++k;
If you were to have instead int result = i++ + ++i + i++; then you'd have a problem because the order of the increments is unspecified, and you depend on that order.
Here result will be always 1. The values of j, k, and i will be all 1. Also, note that separator for several variable declaration is ,, and not ;:
int i=0, j=0, k=0;
No, it's a classic/well known c++ sequence point issue, see link here for much more detail
http://en.wikipedia.org/wiki/Sequence_point
Here:
int result = i++ + ++j + k++;
Is Equivalent too:
<SP>
(a1)int t1 = i; // i++ part one: The result of post-increment is the original value
(a2) i = i + 1; // i++ part two: the increment part separated from the result
(b1) j = j + 1;
(b2)int t2 = j; // The result of pre-increment is the new value
(c1)int t3 = k; // k++ part one: The result of post-increment is the original value
(c2) k = k + 1;
(d) int t4 = t1 + t2;
(e) int t5 = t3 + t4;
(f) int result = t5;
<SP>
The constraints are:
(a1) is before (a2)
(a1) is before (d)
(b1) is before (b2)
(b2) is before (d)
(c1) is before (c2)
(c1) is before (e)
(d) is before (e)
(e) is before (f)
As long as the above constraints are maintained the instructions can be re-ordered as much as the compiler likes. But the constraints guarantee that the result is well formed.