1

This is my first post here. Learning C for the first time to build a robot! :)

Are switch statements a better alternative to express the multiple if-else statements below? I mean this snippet of code works fine. But I'm just really curious about switch statements and want to learn about them.

If yes, I'm not exactly sure how to do them. I've googled extensively but just feel more and more intimidated by the complex programs out there. :/

while(1)
{
    signed float A;

    A = get_angle();    

    if (A > 540 && A <= 700)
    {
        put_speed(200, 600);       //function to specify duty cycle and speed
    }
    else if (A > 1 && A <= 180)
    {
        put_speed (600, 200);
    }   
    else if (A > 180 && A <= 360)
    {
        put_speed(600, 100);
    }   
    else if (A > 360 && A <= 540)
    {
        put_speed(100, 600);
    }   
    else
    {
        put_speed(600, 600);
    }
}   // End of While
tshepang
  • 12,111
  • 21
  • 91
  • 136
Michael Reed
  • 13
  • 1
  • 5
  • Possible duplicate of http://stackoverflow.com/questions/2158759/case-vs-if-else-if-which-is-more-efficient – Jeyaram Jun 28 '13 at 09:24
  • You might find you can make it tidier if you can find a way to calculate your speed values from the angle mathematically. Alternatively, if you have *lots* of else cases you might find a look-up table of some kind to be better. There are certainly ways of using the maths of angles to make things easier to handle. – Joe Jun 28 '13 at 09:33
  • 1
    @Jeyaram, It may not be. What if the OP is looking for code clarity? That post you linked to talks about the *performance* differences. – Anish Ramaswamy Jun 28 '13 at 09:34
  • Why did you not sort the angle ranges? You start with [540,700] followed by [1,180], [180,360], ... – meaning-matters Jun 28 '13 at 09:43
  • there's such a thing as an unsigned float? – Tom Tanner Jun 28 '13 at 09:45
  • "I'm just really curious about switch statements and want to learn about them" -- Any introductory text or course, or tutorial about C will have fairly thorough coverage of switch and case statements. – Jim Balter Jun 28 '13 at 11:08

4 Answers4

3

No, that code is not possible to write with a switch.

The values for case must be constant, and integer. You can have case 4611: but not `case a > 360".

So, unless you want hundreds of case statements (you don't) the code is not easily translatable to use a switch.

UPDATE One way to make it (in my opinion) more elegant is to order the ranges, and reduce repeat by relying on the lower bound already having been checked in all else ifs:

while(1)
{
    const float A = get_angle();

    if (A > 1 && A <= 180)
    {
        put_speed (600, 200);
    }   
    else if (A <= 360)
    {
        put_speed(600, 100);
    }   
    else if (A <= 540)
    {
        put_speed(100, 600);
    }   
    else if (A <= 700)
    {
        put_speed(200, 600);
    }
    else
    {
        put_speed(600, 600);
    }
}

This new version assumes that get_angle() never returns a negative value, it will pick the wrong choice if that happens. You can fix this by adding an additional if first, to capture negative values.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • That was quick! Haha! Thanks!! Okays I'll stick to this then. It's simple enough to understand anyways. :) Btw Is there any alternative to make the code.. erm.. more "elegant"? – Michael Reed Jun 28 '13 at 09:27
  • Just for my deeper understanding of programming. :) – Michael Reed Jun 28 '13 at 09:32
  • @MichaelReed I edited your code to demonstrate that spacing can help elegance. Other thing: Don't use TABs, set your editor preferences to insert 4-spaces when typing a TAB. – meaning-matters Jun 28 '13 at 09:41
  • @PeterMiehle how do you order the ranges? like define them to be constant at the start of the program or via a #define? – Michael Reed Jun 28 '13 at 09:49
2

Firstly, your ranges aren't sorted, which makes what you might want to do a little confusing. Rearranging your code a little:

if      (A >   1 && A <= 180)
{
    put_speed (600, 200);
}   
else if (A > 180 && A <= 360)
{
    put_speed(600, 100);
}   
else if (A > 360 && A <= 540)
{
    put_speed(100, 600);
}   
else if (A > 540 && A <= 700)
{
    put_speed(200, 600);       //function to specify duty cycle and speed
}
else
{
    put_speed(600, 600);
}

You can see that the ranges are more or less multiples of 180. However, the end of the range isn't quite what I'd have thought (I would have expected 720, not 700).

As your code is, it'd be difficult / counter productive to write this as a switch, but you could use a division on, especially if the 700 is a typo:

switch ((int)(floor((a - 1) / 180)))
{
   case 0: //1 to 180
       put_speed(600, 200);
       break;

   case 1: //181 to 360
       put_speed(600, 100);
       break;

   case 2: //361 to 540
       put_speed(100, 600);
       break;

   case 3: //541 to 720
       if (a <= 700) //Odd
       {
           put_speed(200, 600);
           break;
       }
       //fallthrough for 701 to 720 (v. strange)

   default:
       put_speed(600, 600);
}
Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
1

You can use switch case. Just divide angle with 180 (keep it in integer). ex: if(A>=1 & A <180) then dividing with 180 will return 0. if(A>=180 & A<360) then dividing with 180 will return 1.

or if you have condition such as

if(A>1 & A<=180) then divide by 181. it will still result in 0 and then you can use switch case.

Note: In this case If-else will be more efficient,but you wanted to learn it so it is my suggestion.

mvv1277
  • 246
  • 2
  • 4
1

If you want to avoid if-else you can work over an array of coords, note also that you have to suffix with f all those literals

#include <stdio.h>

int main(void)
{
    const float a[][4] = {
        {540.f,700.f,200.f,600.f},
        {1.f,180.f,600.f,200.f},
        {180.f,360.f,600.f,10.f},
        {360.f,540.f,100.f,600.f},
        {0.f,0.f,600.f,600.f}
    };
    size_t i, count = sizeof(a) / sizeof(a[0]);
    float A = 200.f;

    for (i = 0; i < count; i++) {
        if ((A > a[i][0] && A <= a[i][1]) || (i == count - 1)) {
            printf("%.0f %.0f\n", a[i][2], a[i][3]);
            break;      
        }
    }
    return 0;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94