Adventures in Science: Arduino Arithmetic Operators

How to use the various math operators and compound assignment operators in C/C++.

Favorited Favorite 1

Building on data types and literals from last week, we look at how we can add, subtract, multiply and divide literals and variables in C and C++ (specifically, in the Arduino environment).

There are six main arithmetic operators in C and C++:

  • = is the assignment operator. It does not necessarily show equality but is used to set values to variables.
  • + is for addition. You can add two numbers or values in variables together.
  • - is subtraction, and it is used to subtract one number from another.
  • * is multiplication for multiplying two numbers together.
  • / is division. Note that when using integers, you don’t get fractions or a remainder from this operation.
  • % is the modulo operator, and it is used to get the remainder from a division operation.

If you need a fractional result from division, you can use the float data type. If you’re using literals to perform the division, make sure you add some kind of decimal to one of the numbers. For example, 19 / 5 should be 19.0 / 5.

To make writing and reading code easier, you can use compound assignment operators. These perform some math operation on a variable and then store the result back in the same variable.

OperatorMeaningExample
a += ba = a + ba += 3
a -= ba = a - ba -= 3
a *= ba = a * ba *= 3
a /= ba = a / ba /= 3
a %= ba = a % ba %= 3
a++a = a + 1a++
a--a = a - 1a--

The Arduino Reference Guide is still a good place to see which operators the Arduino supports.

While this video is intended as a reference for beginners, what slick tricks have you used or seen with operators? Any tips for good overloading practices? Please share your thoughts in the comments below.


Comments 23 comments

  • Just FYI, in your list of operations with bullet points, you have the wrong slash for division.

  • Since you listed =, it would be good to add a description for ==. For anyone who doesn’t know, (a == b) will be true (or 1) if a is equal to b, otherwise it will be false (or 0). And you might as well add at least !, &&, and || (maybe also bit-wise operators). And again for anyone reading this who doesn’t know, you can use these in assignments, not just for conditional statements.

    int a = 3;        // set a to 3
    int b = 10 / a;   // set b to 10 / 3 (which is 3 when using integer math)
    int c = (a == b); // c equals a==b, so since a and b are each 3, c is true or 1
    
    • Don’t worry, I’m saving comparison and boolean operators for a future episode :)

    • false equals 0.
      true equals not 0 (typically 1 is used).
      ! means not. If 'a' is true, !a is false. If 'a' is false, !a is true.
      && means and. (a && b) will only be true if both 'a' and 'b' are true.
      || means or. (a || b) will be true if 'a' and/or 'b' is true.
      
      • true equals not 0 (typically 1 is used).

        Because true equaling not zero allows streamlining code. Lets say you want to do something with someRandomVariable only if that variable isn’t zero. Then instead of writing:

        if (someRandomVariable != 0) {}
        

        you can short cut it and just write:

        if (someRandomVariable) {}
        

        for example:

        if (someRandomVariable)
        {
            Serial.println(5.0 / someRandomVariable);
        }
        else
        {
            Serial.println(F("Sorry, I don't have an ALU that can handle calculus so I can't divide by zero. Have a good day."));
        }
        

        Silly example, I know, but an example is an example.

        Even if that isn’t your personal coding style, recognizing this would help understand other people’s code.

  • Good video, Shawn! I like the explanation of the difference between the “mathematical” use of the equal sign and the “programming” use of the equal sign. In my experience, this often confuses beginners. (This is why early versions of BEGINNER’S All-purpose Symbolic Instruction Code [“BASIC”] used “LET A = 5”, and also why Pascal used “:=” rather than just “=”.)

    I see that Member #394180 beat me to the pre-increment/decrement constructs. (If someone wants to hear the history behind the pre- & post- things, I can fill them in.)

    Besides the speed issues for using int rather than float, there’s also the issue of “exactness”. For instance, I’ve seen times when

    float a;
    float b;
    float c;
    a = 1.0;
    b = a;
    a = a / 3.0;
    c = a; // avoid optimizing out
    a = a / 5.0;
    c = a;
    a = 0.0;
    for ( int i = 1; i <= 15; i++ )
      a = a + c;
    if ( a == b )
      Serial.println( "true" );
    else
      Serial.println( "false" );
    

    I haven’t actually run this example, but it should print “false”, even though, had we done the math by hand, we’d get “true”. The reason is “round-off error”.

    Oh, one other tidbit: you might want to add a little more horizontal spacing between the columns in the text – things are a bit mashed together, at least in my browser.

    • This makes me think I should do a whole episode on floating point, since there are so many gotchas!

      I would actually be curious about the history of the pre- and post-increment operators. I know they exist, but I just assumed they were always a part of C.

      Thanks for the heads up on the table. It should be fixed now, so let me know if it’s still wonky.

      • I agree that it’s probably worth (at least) one episode on just floating point.

        As for pre- and post- increment and decrement operators, here’s the historical reason why they’re in C:

        The original purpose for the C language was to assist in writing a new operating system for the DEC PDP-11, what eventually became “Unix”. At the time, the vast majority of code for the typical OS was written in assembly language, which, at its best, is a tedious task. The developers (K&R, and others) wanted a somewhat higher level language, but at the time, the existing “higher level” languages made “bit twiddling” VERY difficult (which also meant that such code was slow – not good in an OS). So they ended up designing C (the name is derived from the fact that at the time, IIRC, there was a language called “A” and one called “ABCD”). They included operators and syntax that would cover all of the PDP-11’s machine codes, which included a “pre-decrement” and a “post-increment” (meant for using a register as an offset into an array, and thereby walking through the array). However, the developers were dissatisfied with this asymmetry, and so added “pre-increment” and “post-decrement”. Because of the complete coverage (and thus ease of “bit twiddling”), it’s fairly rare to have to drop into assembly language, especially with today’s optimizing compilers.

        Most programmers don’t realize it, but you can actually include assembly code in your C programs, though it’s been so long since I’ve done it, I’d have to research how to do it. The big downside of doing this is that it restricts portability. Once in a very great while you might see it in code for the kernel or a driver (stuff that’s highly machine-dependent anyway), but not often. (I have some idea of writing “portable code” – I one time wrote about 35,000 lines of code that had to be portable between VMS and Sun-OS – and someone requested a one-line change that would allow it to work on an IBM mainframe [before IBM went to using Linux].)

        Anyway, you are correct in that the operators were always a part of C, assuming that you mean “always” as beginning when it was shared outside the original development team.

        • Interesting! I didn’t realize that the increment and decrement operations were originally a machine language function that made its way into C.

          Not sure about “A,” but I do know there was a “B” (by Ken Thompson and Dennis Ritchie) that was a precursor to C.

          You can use the asm command to sneak assembly into your C programs. I’ve done it once or twice when writing something for a PIC (although I don’t remember what).

          • Microsoft used to be notorious for dropping into assembly language in Windows back in the 90’s. Anytime they wanted exclusive access to a shared resource they’d throw in an asm cli to disable all interrupts (including, thanks to some rotten hardware design the non-maskable interrupt). Then, when they were done, they’d throw in an asm sti to re-enable them - usually. There were many non-deterministic paths to bypass the re-enable, so there were a lot of times when the computer would just hang after a particular set of operations.

            They were violently weaned of this dubious habit by Dave Cutler when he jumped ship from DEC to come to MS to lead the effort of developing Windows NT, which had to run on both Intel and DEC hardware. He had the crew do the DEC Alpha build every morning before the Intel build and if it failed to build because of embedded Intel assembly language, he would hold a shouting session that involved throwing chairs and kicking trash cans. Raw terror eventually overcame ignorance and the MS crew used the semaphores (which they called spinlocks) that real OS developers had been using since 1962 and asm cli faded away.

          • One example of assembly in Arduino/C that I’ve seen (and is used quite often) is the Neopixel library for WS2812 addressable LEDs. With its timing based protocol and predictable clock speeds on AVR boards, it brute forces timing by actually including “nop” (No OPeration) commands to take an exact number of clock ticks between commands. The downside is definitely a lack of portability, the library is pretty sizable since there is different assembly code for different processors and even differing clock speeds.

  • Can you spread out the columns in your table a little? At least in FireFox it’s all running together as “OperatorMeaningExample”. The examples are clumped together as well.

    • Should be fixed now; thanks for catching that! It looked right in my preview, but it seems that our blog isn’t rendering markdown tables exactly right, so I made it a manual HTML table. Let me know if it still looks weird for you.

  • You missed ++a and –a; They’re the same as a++ and a– except for when the operation occurs. The prefix operators happen before the variable is accessed, the postfix after.

    a = 5; b = a++;

    leaves a equal to 6 and b equal to 5.

    a = 5; b = ++a;

    leaves a and b both equal to 6.

    This lets you do some really slick stuff with loops and such.

    Edit - oops, sgrace beat me to it

    • Thanks! I rarely use the pre-increment statement, so I figured it was best left out for the sake of beginners. But yes, they are useful for doing some slick tricks in C/C++.

  • A little “gotcha” the pre and post increment statements: http://stackoverflow.com/a/4706239

    • Definitely good tips to remember if you’re trying to assign the output of the increment/decrement operators.

  • One slick trick is to replace multiply and divide operators with the shift operators when the multiplicand and dividend are integers and the multiplier and divisor are powers of 2. In the good old days this would radically speed up the operation.

    These days, between crazy fast hardware and super-optimizing compilers, it’s just a stunt to amaze and amuse (and sometimes confuse) your friends with. In fact. all good compilers now make the substitution for you, and in many cases, the hardware will do it if the compiler didn’t.

    • Heh, I still do things like a = a << 1; to multiply by 2 knowing full well that modern compilers will optimize for that. Old habits die hard, I guess.

Related Posts

The Gameduino

Recent Posts

Tags


All Tags