2

I have a parameter num of int type, where the user can give it one of two values: 0 or 1.
I can check it using the obvious:

if (num < 0 || num > 1)
    print("The parameter value is incorrect.\n");

But I was wondering if there was a better (faster? less code?) to do this?

EDIT
This is some data flow code, so performance is of the essence. I am looking for a faster way to run this check.

Thanks

shapiro yaacov
  • 2,308
  • 2
  • 26
  • 39
  • 6
    It is ok to be verbose in code - it usually makes it more readable - hence maintainable – Ed Heal Aug 02 '15 at 10:26
  • 4
    What is the motivation for optimising this ? Why make the code less readable, harder to maintain and potentially less robust ? – Paul R Aug 02 '15 at 10:26
  • @PaulR - the motivation for this Q&A is that if someone needs to run this kind of check in a data flow path, where each extra `if`, `!=` or `<` takes up extra (valuable) time, they'll have somewhere to look it up. I haven't actually checked the running times for the different solutions suggested here, but I am pretty sure that `x & ~1` is faster than `x!=0 && x!=1`. – shapiro yaacov Aug 02 '15 at 10:36
  • 2
    Yes, please stop doing this kind of obfuscation. It's bad enough when you debug/maintain/enhnace your own code, but if you inherit this kind of stuff from someone else, you don't want to see anything except the blindingly obvious at source-code level. – Martin James Aug 02 '15 at 11:49
  • 3
    @shapiro.yaacov: your assumptions about performance are most likely wrong (depending on CPU and compiler), and you've committed the cardinal sin of not measuring performance first. This is generally known as premature optimisation, and there are many good reasons to avoid it. Profile first, identify hot spots, then optimise only if absolutely necessary. – Paul R Aug 02 '15 at 12:42
  • How about `if (x / 2 != 0)`? – Kerrek SB Aug 02 '15 at 13:06
  • @KerrekSB: It evaluates to `0` for `x = -1`, which doesn't sound right. – Grzegorz Szpetkowski Aug 02 '15 at 20:26
  • @GrzegorzSzpetkowski: Indeed, never mind. How about `(x * 3 - 1) / 4`? – Kerrek SB Aug 02 '15 at 21:10
  • @KerrekSB: This looks fine for me. The inequality of `-1 < (3x - 1)/4 <= 1` holds, for every real number `x`, such that `x ⋲ (-1; 1 + 2/3>`. – Grzegorz Szpetkowski Aug 02 '15 at 21:32

7 Answers7

8

I'd go on clearness instead of less characters:

if (num != 0 && num != 1){
    print("The parameter value is incorrect.\n");
}

when it's 2 AM and you're debugging a program, the last thing you want is to over-think about ranges and bitwise operations.

David Haim
  • 25,446
  • 3
  • 44
  • 78
5

Clear code over (naive) micro-optimizations

You are essentially making wrong assumptions about actual compiler's behavior. In both cases, that is:

if (num < 0 || num > 1) { ...

and

if (num != 0 && num != 1) { ...

an optimizing compiler will reduce it anyway into shortest form. You may see that, both generate the same assembly, that might look as (x86 platform):

cmp    $0x1,%eax
jbe    1e <foo+0x1e> # jump if below or equal

This is already fast enough, as cmp instruction on all major architectures has latency of one cycle.

The bottom line is to choose whatever code, that makes your intent clear for you, future maintainers and let the compiler do its job. Just make sure, that you set it with proper optimization level (e.g. -O2 or better).


Aid branch prediction

However, if performance is really crucial here (and you profiled it as so, don't you?), then you could think about another kind of optimization, that is at branch prediction level (assuming that your CPU has support for it). The GCC has __builtin_expect intrinsic, that allows to hint compiler, that in most cases branch will be taken or not.

You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (-fprofile-arcs), as programmers are notoriously bad at predicting how their programs actually perform. However, there are applications in which this data is hard to collect.

For instance, if you are confident, that function takes 0 or 1 in aproximately 99% number of cases, then you could write it as:

#define unlikely(x) __builtin_expect((x), 0)

if (unlikely(num != 0 && num != 1)) { ...
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Thanks for the answer. What I was thinking is that `num & ~1` will be faster. – shapiro yaacov Aug 02 '15 at 11:27
  • 2
    @shapiro.yaacov: It likely won't to be any faster. The `num & ~1` may be compiled as `test $0xfffffffe,%eax`, but still both `cmp` and `test` are very basic intructions, with latency of just one cycle. See [Agner's Instruction tables](http://www.agner.org/optimize/instruction_tables.pdf) for more reference. – Grzegorz Szpetkowski Aug 02 '15 at 11:35
3
if (!!num == num)
{
   /* value is either a zero or 1 */
}

!! will change other values into 0 or 1, so if you tried to pass 5:

if (1 == 5) // FALSE:
abelenky
  • 63,815
  • 23
  • 109
  • 159
2

you can use shift operator

if(num>>1) print("The parameter value is incorrect.\n");
Mauri
  • 1,185
  • 1
  • 13
  • 21
0

Since the only bit that can be lit up is the first one, checking the rest of the bits are switched off does the trick.

Also, since it's only 1, the negative of it is (in c syntax): ~1.

So:

if (num & ~1)
    print("The parameter value is incorrect.\n");
shapiro yaacov
  • 2,308
  • 2
  • 26
  • 39
  • 6
    Why would you want to obfuscate your code like this ? – Paul R Aug 02 '15 at 10:24
  • @PaulR: The question was about a simpler way to check, not if obfuscated or not IMHO, but the ppoint is that the answer is wrong! @shapiro: The code is wrong, maybe you intended use the right shift operator: `if (num >> 1) printf("The parameter value is incorrect.\n");` – Frankie_C Aug 02 '15 at 11:05
  • @Frankie_C - if I may ask, what is incorrect with the answer? The right shift operator could also be used, but for `0` or `1`, the error isn't printed. `1 &~1` gives `false` AFAIK – shapiro yaacov Aug 02 '15 at 11:06
  • 1
    @shapiro.yaacov: Sorry, you're answer is correct. My wrong. Anyway none of the downvote was mine. And I repeat that the answer is consistent with question: simpler check obfuscated or not... – Frankie_C Aug 02 '15 at 11:18
  • 2
    Corner case: With machines that use obscure non-2's complement, "Since the only bit that can be lit up is the first one" is incorrect as these systems may have 3 acceptable bit patterns 1, 0, -0. IMO if you are testing for a bit pattern, this is OK. If you are testing for a numeric value, use range comparison like `>=`. – chux - Reinstate Monica Dec 17 '15 at 22:35
0

There are a lot of ways of doing that. I think that the short ways are not always the right one. Think that there are times when probably you need to inform the user about his input, not just saying "The parameter value is incorrect". Me, I have my own Function, try this:

#include<stdio.h>

int checkInput(int min, int max);

int main(void){
    int number = checkInput(0,1);

    printf("\nYour number is\t%d\n",number);

    return 0;
}

int checkInput(int min, int max){
    int option,check;
    char c;

    do{
        printf("Please type a number beetwen %d and %d:\t",min,max);

        if(scanf("%d%c",&option,&c) == 0 || c != '\n'){
            while((check = getchar()) != EOF && check != '\n');
            printf("\tI sayed a Number please\n\n");
        }else if(option < min || option > max){
            printf("\tThe number has to be beetwen %d and %d\n\n",min,max);
        }else{
            break;
        }
    }while(1);

    return option;
}

Output:

Please type a number beetwen 0 and 1: 0k
    I sayed a Number please
Please type a number beetwen 0 and 1:   1j
    I sayed a Number please

Please type a number beetwen 0 and 1:   8
    The number has to be beetwen 0 and 1

Please type a number beetwen 0 and 1:   1

Your number is  1
Michi
  • 5,175
  • 7
  • 33
  • 58
0

Agree if (num < 0 || num > 1) { ... is the way to go

Thought I'd add a code golf-like answer

if (num > 1u) { ...

This converts int num into an unsigned before comparing to 1u.

A weakness to this approach is if num is made to a wider signed type than unsigned. In that case code could "lull" us into more obscurity

if (num > 1ull) { ...

In the end, using (num < 0 || num > 1) will

  1. Generate the fastest code or

  2. Generate poor code and OP really should be looking at a better compiler for overall performance improvement than such a small code optimization.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256