HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Fastest way to find if N numbers are even or odd

Submitted by: @import:stackexchange-codereview··
0
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.

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 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) == 0 and (number % 2) == 0 seem 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::string or std::stringstream and then write just once to std::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 of std::endl will prevent flushing. '\n' has some performance benefits but you won't have a single flush because we're also reading from std::cin. The use of std::stringstream is the way to avoid flushing. Note that it is implementation dependent if this useless flush() will impact performance or not for std::cout (when std::cout.sync_with_stdio(false) is called.) In general I'd suggest to use it (measure...) but still stay on std::stringstream if 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.