patterncppModerate
Fastest way to find if N numbers are even or odd
Viewed 0 times
arenumberswayfastestfindevenodd
Problem
I want to find if 'N' numbers are even or odd in the fastest way possible.
Here's the following code which produces the desired output, but I do not know how efficient it is.
Can this code be improved in any way to get faster results?
Here's the following code which produces the desired output, but I do not know how efficient it is.
int main() {
int N,x;
scanf("%d",&N);
while(N--){
scanf("%d",&x);
x&1 ? cout << "No" << endl : cout << "Yes" << endl;
}
return 0;Can this code be improved in any way to get faster results?
Solution
Given that 99.9% of time is spent in
What it may be improved is readability of your code. First of all your're mixing C style I/O (
Do not ever add
In C++ there is no need to declare all variables at the top of your method.
I think ternary operator
If you have a loop I think
This example is pretty small but for more complex code you may want to extract some functions:
If you're already using Boost you may use
I'd stop here (but read notes) for this code however if your scenario is (or it will be) more complex you will probably need to introduce more classes:
EDIT
Few notes:
Just a proof of concept:
scanf, cout and waiting for user input then there isn't much you can do about performance (but see notes).What it may be improved is readability of your code. First of all your're mixing C style I/O (
scanf) with C++ I/O (std::cout). Let's move to C++ std::cin.Do not ever add
using namespace std; (Why is “using namespace std” considered bad practice?)In C++ there is no need to declare all variables at the top of your method.
I think ternary operator
?: is usually used for its result, not for side-effects of called code (here you're ignoring returned values). At first this usage is confusing for caller.If you have a loop I think
for is more clear (in intent) than while. Do not worry about extra variable, compiler will optimize it for you.int main()
{
int numbersToRead;
std::cin >> numbersToRead;
for (int i=0; i > number;
bool isEven = (number & 1) == 0;
std::cout << (isEven ? "Yes" : "No") << std::endl;
}
return 0;
}This example is pretty small but for more complex code you may want to extract some functions:
int main()
{
for (int i=readNumberOfValuesToRead(); i > 0; --i)
std::cout << (isEven(readValue()) ? "No" : "Yes") << std::endl;
return 0;
}If you're already using Boost you may use
boost::irange (let me also show that you may/should move formatting to a proper manipulator (for simplicity in this example I use standard one which prints true/false instead of Yes/No):int main()
{
std::cout << std::boolalpha;
for (auto i : boost::irange(0, readNumberOfValuesToRead()))
std::cout << isEven(readValue()) << std::endl;
return 0;
}I'd stop here (but read notes) for this code however if your scenario is (or it will be) more complex you will probably need to introduce more classes:
ValuesReader base class (with a StandardInputValuesReader concrete class) to read values from an input stream and ValuesWriter (same...) to write output somewhere (using a ValueProcessor or ValueConverter and a custom stream manipulator?) Also remember that proper classes will make your life incredibly more easy during testing (because an abstract base class can be easily mocked while to read from std::cin you need much more code in your tests - and they can't be well-tested in isolation.)EDIT
Few notes:
- As Snowhawk04 noted I/O synchronization (between C and C++ functions) may slow down execution (or it may even not).
(number & 1) == 0and(number % 2) == 0seem to have the same performance (and generated assembly output), at least on GCC. Pick the one you feel more comfortable with.
- Flushing output buffer (because of newline) may make it slower (but again consider that you're waiting user input). A different approach may help (concatenate results into
std::stringorstd::stringstreamand then write just once tostd::cout). It's not a good approach if your application is interactive but it may be viable if it's intended to be used from command line with I/O redirection.
Just a proof of concept:
int main()
{
std::ostringstream output;
output << std::boolalpha;
for (int i : boost::irange(0, readNumberOfValuesToRead(), 0))
output << isEven(readValue()) << std::endl;
std::cout << output.str();
return 0;
}- Someone noted
'\n'instead ofstd::endlwill prevent flushing.'\n'has some performance benefits but you won't have a single flush because we're also reading fromstd::cin. The use ofstd::stringstreamis the way to avoid flushing. Note that it is implementation dependent if this uselessflush()will impact performance or not forstd::cout(whenstd::cout.sync_with_stdio(false)is called.) In general I'd suggest to use it (measure...) but still stay onstd::stringstreamif you want to avoid multiple flushes (not for interactive use.)
- I am just half joking but for a non-interactive use if you really need to squeeze maximum performance from this program then you may want to write it in C (in practice dropping C++ I/O and strings...)
Code Snippets
int main()
{
int numbersToRead;
std::cin >> numbersToRead;
for (int i=0; i < numbersToRead; ++i)
{
int number;
std::cin >> number;
bool isEven = (number & 1) == 0;
std::cout << (isEven ? "Yes" : "No") << std::endl;
}
return 0;
}int main()
{
for (int i=readNumberOfValuesToRead(); i > 0; --i)
std::cout << (isEven(readValue()) ? "No" : "Yes") << std::endl;
return 0;
}int main()
{
std::cout << std::boolalpha;
for (auto i : boost::irange(0, readNumberOfValuesToRead()))
std::cout << isEven(readValue()) << std::endl;
return 0;
}int main()
{
std::ostringstream output;
output << std::boolalpha;
for (int i : boost::irange(0, readNumberOfValuesToRead(), 0))
output << isEven(readValue()) << std::endl;
std::cout << output.str();
return 0;
}Context
StackExchange Code Review Q#141125, answer score: 19
Revisions (0)
No revisions yet.