asin
function from the cmath
library to compute our value.
Now, the arcsine is only defined for values between negative 1 and
1, so if the user enters a value outside of this range we should
print an error message. Doing this with what we know so far is
ugly:
if (x <= 1.0)
{
if (x >= -1.0)
{
cout << "arcsine of " << x << " = " << asin(x) << endl;
}
else
{
cout << "Error! Value outside of [-1,1]!" << endl;
}
}
else
{
cout << "Error! Value outside of [-1,1]!" << endl;
}
We want to be able to say in our test condition that x must be
less than or equal to 1 AND greater than or equal to -1.
In C++ the operator &&
is "and". So our
program fragment becomes:
if (x <= 1.0 && x >= -1.0)
{
cout << "arcsine of " << x << " = " << asin(x) << endl;
}
else
{
cout << "Error! Value outside of [-1,1]!" << endl;
}
... which is substantially simpler. More to the point, this does
a much better job of reflecting what we're thinking.
&&
as an opearator on objects of type bool
&&
looks like something
mysterious and new. It's not. It's an operator just like +, *,
and >>, all of which we've used a lot already. It takes two
objects of type bool
and evaluates to an object of
type bool
. We have an intuitive idea of what "and"
means, and it coincides with C++'s technical, exact definition of
what &&
means:
Expression | Result |
false && false | false |
false && true | false |
true && false | false |
true && true | true |
x <= 1.0 && x >= -1.0
makes
sense because x <= 1.0
evaluates to a
bool
and x >= -1.0
evaluates to a
bool
, and then the &&
operates on the
two bool
values.
&&
and ||
follow short circuit
evaluation rules.
This means that the left-hand operand expression is evaluated
first, and if the truth or falsity of the expression can be
determined based only on the left-hand side, the right-hand
operand expression is never even evaluated.
So, for example, this code:
(x = y) || (x = 1)is interesting. If y is non-zero, the left-hand operand is evaluated setting x to y's value. The expression when cast as a bool yields true. At this point, the || expression is necessarily true, so the right-hand side is never even evaluated, and the expression results in true. If y is zero, when the left-hand operand is evaluated it results in x being set to zero, and the expression when cast to a boolean yields false. This means the right-hand side of the || must be evaluated as well to determine the value of the || expression. This results in x being set to 1.
So ... right now this is more of a curiousity than anything. However, later in the semester, this behavior becomes very important.
&&
(and), the ||
operator (or), and the
!
(not) operator.
The ||
operator is much like &&
, it
takes two objects of type bool
and evaluates to an
object of type bool
. The result is
true
if either or both are true
, and
false
otherwise.
Expression | Result |
false || false | false |
false || true | true |
true || false | true |
true || true | true |
The !
operator is a unary operator.
Instead of operating on left and right-had values, it operates
on a single value - the value following it on the right. It
evaluates to the not of the value following, so if the value
following is true
, the !
expression is
false
.
Expression | Result |
!false | true |
!true | false |
But, of course, the problem is the test condition// Read char char c; cout << "Enter a letter: "; cin >> c; // Decide: Letter or not a letter? if (
c is a letter) { cout << "Letter" << endl; } else { cout << "Not a Letter" << endl; }
c
is a letter. Letters
come in two flavors, uppercase and lowercase. So a refinement of
our program would be:
From the ASCII table we would see that uppercase letters range from// Read char char c; cout << "Enter a letter: "; cin >> c; // Decide: Letter or not a letter? if (
c is an uppercase letter || c is a lowercase letter) { cout << "Letter" << endl; } else { cout << "Not a Letter" << endl; }
'A'
(65) to 'Z'
(90).
So c
is an uppercase letter
boils down to (c >= 65 && c <= 90)
.
Similarly, because lowercase letters range from
'a'
(97) up to 'z'
(122), we know that
c
is a lowercase letter
boils down to
(c >= 97 && c <= 122)
. Put it all
together and we get:
// Decide: Letter or not a letter?
if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122))
{
cout << "Letter" << endl;
}
else
{
cout << "Not a Letter" << endl;
}
Note that I wrapped my uppercase and lowercase tests in
parentheses, because I wanted to be sure that the
&&
's were evaluated before the ||
. Is
that necessary? (Think about how you would decide this!) Even if
it isn't, adding the ()'s makes the meaning clear to everyone.
In fact, we can avoid having to even look at an ASCII table
by replacing the
actual ASCII constants 65, 90, 97, and 122 with the corresponding
char
constants for the letters
'A'
, 'Z'
, 'a'
, and 'z'
.
This also makes it much more clear how the code works:
// Decide: Letter or not a letter?
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
{
cout << "Letter" << endl;
}
else
{
cout << "Not a Letter" << endl;
}
Check out this complete solution.
// Decide: Letter or not a letter?
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
cout << "Letter" << endl;
else
cout << "Not a Letter" << endl;
Once again, this is just a shortcut to save keystroks and screen
space, but you will see this shortcut often. If you try to drop
the {}'s when you have more than one thing in the block, you'll
run into trouble. In this case:
// Decide: Letter or not a letter?
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
cout << "Letter" << endl;
cout << "Way to follow directions!" << endl;
else
cout << "Not a Letter" << endl;
your compiler will complain and give you a "parse error". As far
as the compiler is concerned, that "else
" doesn't
belong to any "if
"! It's not impressed with the fact
that the cout << "Way to follow directions!" << endl;
is indented as if it belonged to the else-block. It interprets
the above as
// Decide: Letter or not a letter?
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
{
cout << "Letter" << endl;
}
cout << "Way to follow directions!" << endl;
and thinks that we're dealing with an "if
" from which
the else-block has been dropped. Therefore, it is unhappy when it
sees the "else
" from out of nowhere!
else if
x
of type
double
that I know is between 0 and 1, and suppose I
want to print out for the user
x is in [0,1/3]
,
x is in [1/3,2/3]
, or
x is in [2/3,1]
x
. Our first shot would
probably be:
if (x <= 1.0/3.0)
{
cout << x << " is in [0,1/3]" << endl;
}
else
{
if (x <= 2.0/3.0)
{
cout << x << " is in [1/3,2/3]" << endl;
}
else
{
cout << x << " is in [2/3,1]" << endl;
}
}
However, our "cout
" statements are if-blocks and
else-blocks consisting of a single statement, so Shortcut #1 tells
us we can drop the {}'s surrounding those statments, which would
give us:
if (x <= 1.0/3.0)
cout << x << " is in [0,1/3]" << endl;
else
{
if (x <= 2.0/3.0)
cout << x << " is in [1/3,2/3]" << endl;
else
cout << x << " is in [2/3,1]" << endl;
}
However, an "if
" statement is a single statement,
so Shortcut #1 tells us that we can drop the {}'s surrounding the
scond "if
" statement, which would give us:
if (x <= 1.0/3.0)
cout << x << " is in [0,1/3]" << endl;
else
if (x <<= 2.0/3.0)
cout << x << " is in [1/3,2/3]" << endl;
else
cout << x << " is in [2/3,1]" << endl;
However, the C++ compiler is not sensitive to to
formatting, so it doesn't distinguish between "if-newline-else"
and "if-space-else", so we could rewrite things to look like this:
if (x <= 1.0/3.0)
cout << x << " is in [0,1/3]" << endl;
else if (x <<= 2.0/3.0)
cout << x << " is in [1/3,2/3]" << endl;
else
cout << x << " is in [2/3,1]" << endl;
People refer to the "else if
" as if it were a new programming
construct (which in some languages, it is), but you see it is just the
same code with the same meaning as our original ... it just looks a little
prettier, saves keystrokes, and takes up a little less screen real estate.
There's nothing new here! All we did was to take advantage of Shortcut #1
and to use some nice formatting. It sure looks prettier though. Once
again, this is just a shortcut to save keystrokes and screen space, and
to make your code easier to read - but you will see this shortcut often.
The "if else
" formatting is particularly nice when you have
disjoint cases to distinguish. For example:
d
of type string
that contained a day of the
week name (e.g. Thursday), and
int
k
that you wanted to set to the number of the day d
(e.g. 5 for
Thursday).
else if
". It makes a huge difference in terms of
how easy the code is to understand!
&&, ||, !
are evaluated?
|
|
if( y != 0 && x != 0 )or
if( !( y ==0 || x == 0 ) )