Doing quick arithmetic from the command prompt

Date:May 4, 2006 / year-entry #155
Tags:tipssupport
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20060504-13/?p=31313
Comments:    64
Summary:The command processor CMD.EXE comes with a mini-calculator that can perform simple arithmetic on 32-bit signed integers: C:\>set /a 2+2 4 C:\>set /a 2*(9/2) 8 C:\>set /a (2*9)/2 9 C:\>set /a "31>>2" 7 Note that we had to quote the shift operator since it would otherwise be misinterpreted as a "redirect stdout and append" operator....

The command processor CMD.EXE comes with a mini-calculator that can perform simple arithmetic on 32-bit signed integers:

C:\>set /a 2+2
4
C:\>set /a 2*(9/2)
8
C:\>set /a (2*9)/2
9
C:\>set /a "31>>2"
7

Note that we had to quote the shift operator since it would otherwise be misinterpreted as a "redirect stdout and append" operator.

For more information, type set /? at the command prompt.


Comments (64)
  1. Peter Ritchie says:

    Cool.  But, a function of SET?  Weird.

  2. Puckdropper says:

    Cool… Just missed going in my research paper by one day, though.  Yet another tool at your finger tips on the command line. :-)

  3. BryanK says:

    Cool?  Yes; almost as cool as $((…)) in bash.  ;-)

    (FWIW, I think bash’s version is better because you can use the result in another command, instead of only being able to print it.  To get it to print, you have to "echo $((…))"; to assign it to a variable, you can just "var=$((…))".  Yes, the first is slightly easier in cmd — but the second doesn’t seem possible at all, unless cmd has the equivalent of backticks.)

  4. You get backtick-ish behaviour from for /f:

    for /f %f in (‘set /a 2+2’) do echo %f

  5. richard says:

    I will be another to chime in cool!

    Nice to know I don’t have to leave the command prompt.

  6. meneame.net says:

    Tantos años usando la linia de comandos de Windows XP (cmd.exe) y ahora me entero que se pueden hacer pequeños calculos con una precision de un numero entero de 32-bits sin tener que usar la calculadora de Windows.

  7. Adam says:

    BrianK:

    Try:

    set /A foo=2+2

    echo %foo%

    (Also note that "set /A" does not print the result from a batch file, only from the command line)

  8. I forgot my posting name (really) says:

    Had to really lough hard, when reading this, because of the spots a friend sent me yesterday

    http://movies.apple.com/movies/us/apple/getamac_ads1/ilife_480x376.mov

    is the culprit

    (Apple computer) tells (Windows computer) what he has preinstalled (iLive suit)

    (Windows computer): And I’ve got a calculator

  9. Dave says:

    re: setting variables:

    C:>SET /a FOUR=2+2

    4

    C:>echo %FOUR%

    4

    granted, you have to suppress the output of SET if you don’t want it, but it does work to directly set variables.

  10. I didn’t say "fancy arithmetic using floating point values greater than 4 billion", I said "quick arithmetic".

    I don’t use this trick myself but I thought others might find it helpful. If you don’t find it helpful, that’s fine.

  11. Alun Jones says:

    Why is it "weird" that it’s a function of ‘set’?  Where else should it go?  A separate "eval" or "expr" or "calc" command?

    Already, SET is where expressions of other kinds are parsed, evaluated and set.

    Me, I like "SET /P" – to prompt for a value to put into an environment variable.

    As for a "real programming language" – yeah, sure, if you need to do real things, you use a real language.  If you’re at the batch file, and don’t want to start up an instance of your favourite language just to add a few numbers, you don’t have to.  Four-byte signed arithmetic is all you’re likely to need in most batch files, surely?  If not, as you point out, you’re free to call others.

    For the Mac advert, sorry, I wasn’t able to watch it, because it uses a proprietary video format that isn’t installed on my system – but I’m intrigued as to how "iLive suit" (uh, is that "suite"?) compares to Windows Movie Maker, etc – or is the iMac trying to compare its consumer software to server products?

  12. Andrew Feldstein says:

    I use the Google toolbar since my browser is always running anyway.

  13. Eli says:

    Yeah but the Google toolbar doesn’t do bit shifts.

  14. Adam says:

    Anders:

    C would do the same thing. Are you seriously trying to claim that C is not "a real programming language"?

  15. Ritchie says:

    Personally I use calc (great for hex / dec conversion) but I can forsee a time when this will come in handy. Thanks.

  16. Wow – it’ll do hex-to-decimal conversion, too:

    C:>set /a 0x1234

    4660

  17. Lee Houghton says:

    It’s cool, and on occasion I have used it – but I don’t use it any more. I have a button on my keyboard for calculator (MS Internet Keyboard). I seem to be using calculator a lot more recently.

    PS. I was totally hoping you’d used the KBD tag there :-P

    PPS. Anders Munch: ruby -e "p 50000*50000" :D

  18. Anders Munch says:

    Raymond, I know you’re just being helpful posting this information, I certainly meant no offense to you.  I was just commenting in the context of your recent posts on using the ever-present command interpreter instead of something requiring download+installation.

    However: Signaling an error when the problem at hand exceeds your capacity to solve it isn’t "fancy", it’s a basic requirement. SET could have set errorlevel or un-set the target environment variable, but I checked, it does neither on my W2K.

    PS: Who said anything about floating point?

  19. Slaven says:

    Anders, the post clearly says "32-bit signed integers"; I don’t think we need to compare the command prompt with Python to show that Python is better, but a lot of people still rely on the command prompt for many legacy reasons.

  20. dg says:

    it does octal-to-decimal too (in case someone uses base-8, I’m guessing):

    C:>set /a 0543

    355

  21. Anders Munch says:

    Adam: The C programming language does not require overflow checks for reasons of efficiency.

    cmd.exe doesn’t have that excuse. Just

    the time spent by SET converting between binary numbers and text strings exceeds the time for the actual computation by orders of magnitude.

    Oh, and saying cmd.exe isn’t a real programming language was not intended as a slight on cmd.exe!  After all cmd.exe wasn’t designed to be a general-purpose programming language.  I just want to use the right tool for the job.

  22. Adam says:

    Anders: Again, C does not signal an error on overflow; it just wraps around.

    Hmmmm …. bignum support required, automatic overflow checking "a basic requirement". Please tell, what other features do you require of "a real programming language"?

    /me stifles grin

  23. Garry Trinder says:

    So, how’d you get the colloquial phrase "The expression evaluator is pretty simple" (from "SET /?")  passed the User Documentation Police?

  24. James Risto says:

    CMD.EXE just gets better and better with each release. I have taken to reading the help of all the commands on each OS and SP release. I totally missed the SET /P one! Sheesh! Is there a forum to request new features? I would love for it to save history across invokations.

  25. hepwori says:

    "Note that we had to quote the shift operator".

    Alternatively, you can escape the > signs with the cmd.exe escape character ^.

    C:>set /a 31^>^>2

    7

  26. Anders Munch says:

    Adam: I’m glad you’re having fun, but what you’re laughing at is a straw man. I never purported to define a set of required features for programming languages, but since you ask, if I were to write one, data structures and subroutines would be at the top of the list.

    C unsigned int implements modulo UINT_MAX+1 arithmetic. C signed int arithmetic has undefined behaviour, if the result is not representable as a signed int. A C implementation is perfectly entitled to trap signed arithmetic overflow, and I would expect a C interpreter to do just that.

  27. Anders Munch says:

    I wouldn’t want to use bash or GNU expr for programming either (Rich, try bigger numbers with bash). But at least the limitations of bash expressions are clearly documented. man bash tells me:

    "Evaluation is done in fixed-width integers with no check for overflow".

  28. DOS Fogey says:

    Bah.  All these spoiled kids with their newfangled scripting languages.  I always say you’re not really a man until you’ve written a Texas Hold’em game in DOS Batch.

  29. moefh says:

    Rich: I guess you’re using a 64-bit machine, no?

    Bash and Perl do integer arithmetic in native integer precision.  I don’t know about bc, though.

  30. moefh says:

    Erm… Perl does arithmetic in floating point… oops! :-)

    Bash does it in native integer precision.

  31. Any way to get hex back out of this as an argument?

    That would just make my day.

  32. That doesn’t quite read as I intended.  What I meant was:

    "Is there any argument that might indicate to SET that one wishes to receive hex as a result of the calculation?"

  33. Jonathan says:

    Our build script uses this to increment the build number automatically.

    set /a newbuildnum=%buildnum%+1

  34. Anders Munch says:

    Adam: The "you said then I said then you said.." game doesn’t accomplish anything. EOT

  35. Anders Munch says:

    C:>set /a 50000*50000

    -1794967296

    I’ll take a real programming language please, thank you all the same. Even if it does take an extra install.

    C:>python -c "print 50000*50000"

    2500000000

  36. Michael Puff says:

    But the question is: Why only signed integers and not floats?

  37. Any way to get hex back out of this as an argument?

    Sure, just run the output through something like this (negative numbers not tested)

    rem tohex.bat

    @echo off

    if (%1) == () goto USAGE

    setlocal

    set in=%1

    :LOOP

    if (%in%) == (0) goto ENDLOOP

    set /a hexit=%in% %% 16

    set /a in=%in% / 16

    if (%hexit%) == (10) set hexit=A

    if (%hexit%) == (11) set hexit=B

    if (%hexit%) == (12) set hexit=C

    if (%hexit%) == (13) set hexit=D

    if (%hexit%) == (14) set hexit=E

    if (%hexit%) == (15) set hexit=F

    set out=%out%%hexit%

    goto LOOP

    :ENDLOOP

    if (%out%) == () set out=0

    echo 0x%out%

    endlocal

    goto END

    :USAGE

    echo USAGE: tohex positive-number

    :END

  38. Heh.  Spot-the-bug!  I only tested this with palindromic hex numbers, It seems :)

  39. Mike says:

    I still think what Amiga OS did over two decades ago is more logical: Eval.

    That MS-DOS (and therefore NT cmd.exe) never understood "ticks" is a larger problem, and one that can’t be easily fixed. Claiming "for /f" *can* solve some of these issues is, while techincally correct, a path down infuriation-and-"fsck-off-you-bl**dy-interpreter"-lane. :-)

  40. Fixed the bug and added support for negative numbers.

    Source here:

    http://channel9.msdn.com/ShowPost.aspx?PostID=189460

  41. If cmd.exe has no excuse then neither do many other programs.

    $ echo $[50000*50000]

    -1794967296

    $ expr 50000 ‘*’ 50000

    -1794967296

    % @ x = 50000 * 50000; echo $x

    -1794967296

  42. Rich says:

    Raymond: the first two work for me.

    bash$ echo $((50000 * 50000))

    2500000000

    zsh$ echo $((50000 * 50000))

    2500000000

    $ expr 50000 ‘*’ 50000

    2500000000

    $ perl -e ‘print 50000 * 50000’

    2500000000

    $ python -c ‘print 50000 * 50000’

    2500000000

    $ echo 50000 ‘*’ 50000 | bc

    2500000000

    I’m not sure what your last example was.

  43. Adam says:

    How is it a straw man?

    Having shown that the expression evaluator wraps on arithmetic overflow, you said "I’ll take a real programming language please, thank you all the same.", and pointed out that your language of choice uses bignums. That’s a direct implication that any "real programming language" should use bignums.

    "Signaling an error when the problem at hand exceeds your capacity to solve it isn’t "fancy", it’s a basic requirement." is also a direct attack on the lack of such handling in the expression evaluator.

    These are both things you clearly believe should be in a "real programming language". I don’t see how what you’ve said can be taken differently. C does not implement either of these features. Therefore, you clearly believe that C is not a "real programming language".

    Ah, but "The C programming language does not require overflow checks for reasons of efficiency." and "C signed int arithmetic has undefined behaviour".

    So, "reasons of efficiency" and "writing down that it’s undefined" are circumstances in which the rules for "real programming languages" can be ignored? Well, the cmd.exe expression evaluation already qualifies on the second, as Raymond pointed out. As for the first, why is "ease of implementation" not just as valid an excuse for implementing something? Especially as "ease of implementation" is more likely to be the original rationale for C’s lack of tightly-defined overflow semantics. In which case cmd.exe wins on that score too.

    I apologise for the amusement, but you do seem to be attempting to create a definition of "real programming languages" which excludes most languages generally considered "real", but them claiming that those rules don’t need to apply to *those* languages.

    (Also, I’d expect a C program run by an interpreter to have the same semantics as the same program compiled and run as a binary. There are some circumstances where it can be handy to *rely* on overflow.)

  44. Kuwanger says:

    "Bash … [does] integer arithmetic in native integer precision.  I don’t know about bc, though."

    Uh, no.  Bash does interger arithmetic in signed 64-bit integer precision (easily testable with echo $((2**63-1)) and $((2**63))).  bc offers infinite (ie, memory space limited) precision.  Personally, it’s the lack of floating point numbers that frquently cause me to use bc more than worries of integer overflowing; I’m not sure how well I’d handle doing everything through set though :).

  45. Bangwhistle says:

    I use my TI-36 calculator which I keep on my desk.  It took me years to let go of my slide rule for a calculator, it’s going to take more years to use these new-fangled tricks.

  46. Interesting, but JScript and VBScript just provides so much more and are installed on every Windows since years :)

    Too bad CScript doesn’t handle stdin as the script source and requires a file:

    C:> echo WScript.StdOut.Write(50000*50000) > temp.js

    C:> CScript /NoLogo temp.js

    C:> del temp.js

    However, it makes it possible to build an eval utility for CMD:

    [eval.js]

    WScript.StdOut.Write (eval(WScript.StdIn.ReadAll()));

    [eval.cmd]

    @CScript.exe /NoLogo eval.js

    eval can then be used in CMD pipelines:

    C:> echo 50000*50000 | eval.cmd | more

  47. milowg says:

    What good is doing this in a DOS window, if to copy the results, I have to:

    1. right click on the window

    2. select Mark

    3. highlight the text

    4. hit the enter key.

    What ever happened to the cmd window in windows 2000 where you could highlight anytime you wanted?

  48. oakfed says:

    Yoo can highlight any time you want in both XP command windows and Win2K command windows – provided the properties for the window have "Quick Edit" mode set. I’m not sure what the default is in either OS, though.

  49. What ever happened to the cmd window in windows 2000 where you could highlight anytime you wanted?

    You mean the Quick Edit Mode you can enable in the console window properties? (right click on its title bar > properties).

    Changing from Raster Fonts to Lucida Console also makes the console window much more comfortable, especially with ClearType.

  50. milowg says:

    Wow! Quick Edit is exactly what I was looking for.

    I knew I read this blog for a reason :)

  51. moefh says:

    "Bash does interger arithmetic in signed 64-bit integer precision […]".

    Not here (32-bit machine):

    $ uname -m

    i686

    $ echo $BASH_VERSION

    2.05.8(1)-release

    $ echo $((1<<31))

    -2147483648

    $ echo $((0xffffffff))

    -1

    Strangely, the manual of this version says:

    "Evaluation  is  done  in  long integers with no check for overflow […]"

    (which would make you right), but appears to be wrong.

    On another box (64-bit):

    $ uname -m

    x86_64

    $ echo $BASH_VERSION

    3.00.16(1)-release

    $ echo $((1<<31))

    2147483648

    $ echo $((0xffffffff))

    4294967295

    The manual of this version says:

    "Evaluation is done in fixed-width integers with no check for overflow […]".

    (Seems like they gave up on specifying a precision :-))

    PS: calculating $((2**63)) in 32 bits overflows to 0 as early as $((2**32)), which (I guess) is calculated as $((1<<32)).

  52. GEL says:

    This batch file seems to work pretty well:

     @echo off

     SET /A result = %*

     SET result

    Not my original, I got it here:

    [url]http://www.robvanderwoude.com/useless.html[/url]

  53. Norman Diamond says:

    Thursday, May 04, 2006 3:19 PM by Adam

    > (Also, I’d expect a C program run by an

    > interpreter to have the same semantics as

    > the same program compiled and run as a

    > binary.

    It does.  The code under discussion has no semantics at all, whether run by an interpreter or compiled and run as a binary.  Undefined means undefined.

    > There are some circumstances where it can be

    > handy to *rely* on overflow.)

    Here are two ways to accomplish that:

    1.  Use unsigned types.

    2.  Use a known dialect of C, in which the vendor of the interpreter or compiler added implementation extensions to define meanings for some expressions which were otherwise undefined.  Maybe the vendor offers these extensions when you set a flag or maybe the vendor offers these extensions always, it doesn’t matter which, but if that’s what you need then that’s what you need to use.

  54. Adam says:

    Norman: Good catch. I forgot that signed overflow is undefined.

  55. If you’re not happy with the expression support in cmd.exe, give Microsoft’s new PowerShell a try. Here are a couple of examples.

    Basic expressions just work:

    PS (1) > 50000*50000

    2500000000

    You also have direct access to all of the math stuff in .NET from powershell:

    PS (2) > [math]::sqrt(50000*50000 )

    50000

    And full floating point support

    PS (3) > function sqr ($x) {$x * $x}

    PS (4) > sqr 12.4

    153.76

    PS (5) > 7/3

    2.33333333333333

    PS (6) > [math]::sin(3.14)

    0.00159265291648683

    PS (7) > 0x55aa

    21930

    And operations on other data types like chars

    PS (8) > ([int][char] "a") + 1

    98

    PS (9) > [char] (([int][char] "a") + 1)

    b

    Of course, since it is a shell, you can mix and match commands and expressions. Here’s an example that calculates the total length of all of the files in the current directory:

    PS (10) > $total = 0

    PS (11) > dir | foreach {$total += $_.length}

    PS (12) > $total

    37574

    -bruce



    Bruce Payette

    Technical Lead

    Windows PowerShell

  56. I’m happy to see that JScript can also achieve the same result, even if it requires some more typing, especially for the last piece.

    Basic expression:

    MAS (1)> ?5000*50000

    250000000

    Using JScript Math stuff:

    MAS (2)> ?Math.sqrt(5000*5000)

    5000

    Floating point support:

    MAS (3)> function sqr (x) { return x*x }

    MAS (4)> ?sqr(12.4)

    153,76

    MAS (5)> ?7/3

    2,33333333333333

    MAS (6)> ?Math.sin(3.14)

    1,59265291648683E-03

    MAS (7)> ?0x55aa

    21930

    Operations on chars:

    MAS (8)> ?"a".charCodeAt(0)+1

    98

    MAS (9)> ?String.fromCharCode("a".charCodeAt(0)+1)

    b

    Total length of all the files in the current directory… This definitely shows the power of PowerShell scripting language though:

    MAS (10)> total = 0

    MAS (11)> f = new Enumerator(new ActiveXObject("Scripting.FileSystemObject").GetFolder(location).Files)

    MAS (12)> for (;!f.atEnd();f.moveNext()) { total+= f.item().Size }

    MAS (13)> ?total

    Note this isn’t pure JScript, lines starting with ‘?’ are evaluated and their result displayed, instead of executed.

    This is an extra feature of a little command shell based on script engine I’m coding.

  57. I realized VBScript can actually be shorter for several of these operations, so if anyone is interested, here it is.

    Basic expression:

    MAS (1)> ?50000*50000

    2500000000

    Using VBScript Math functions:

    MAS (2)> ?Sqr(5000*5000)

    Floating point support:

    MAS (3)> Function Sqrx (x): Sqrx = x*x: End Function

    MAS (4)> ?Sqrx(12.4)

    153,76

    MAS (5)> ?7/3

    2,33333333333333

    MAS (6)> ?Sin(3.14)

    1,59265291648683E-03

    MAS (7)> ?&h55aa

    21930

    Operations on chars, much shorter than in JScript:

    MAS (8)> ?Asc("a")+1

    98

    MAS (9)> ?Chr(Asc("a")+1)

    b

    Total length of all the files in the current directory, shorter than in JScript, but still far from PowerShell script:

    MAS (10)> total = 0

    MAS (11)> Set f = CreateObject("Scripting.FileSystemObject").GetFolder(location).Files

    MAS (12)> For each i in f: total = total+i.Size: Next

    MAS (13)> ?total

    All in all, PowerShell is much more efficient. I believe this is due to its design, which enforces pipes in every command and thus makes evaluation or execution the same thing, and its syntax being very well designed.

    But it’s good to know we can get some results using current script engines if needed :)

  58. A cool stuff that dint get my attention all these days….thx for ticking it !!!

  59. Anonymous Coward says:

    Thursday, May 04, 2006 12:56 PM by hepwori

    >Alternatively, you can escape the > signs with the cmd.exe escape character ^.

    Wow.  This is too cool!  Now I can finally generate HTML tags with the ECHO command.

  60. Now I can finally generate HTML tags with the ECHO command.

    I wouldn’t drop ISAPI, ASP and ASP.NET for that new CGI.BAT technology you’re talking about :)

    However, this can be cool to generate rich reports for batch / CMD scripts.

  61. Well, that’s integer division for you. :)

  62. John B says:

    Great but if this is really true what good is it?

    C:>set /a 2*(9/2)

    8

    In my school 2*(9/2) is the same as (2*9)/2  which is still 9.  It never equals 8

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index