Calculation
suggest changeBatch scripts can do simple 32-bit integer arithmetic and bitwise manipulation using SET /a command. The largest supported integer is 2147483647 = 2 ^ 31 - 1. The smallest supported integer is -2147483648 = - (2 ^ 31), assignable with the trick of set /a num=-2147483647-1
. The syntax is reminiscent of the C language.
Arithmetic operators include *, /, % (modulo), +, -. In a batch, modulo has to be entered as "%%".
Bitwise operators interpret the number as a sequence of 32 binary digits. These are ~ (complement), & (and), | (or), ^ (xor), << (left shift), >> (right shift).
A logical operator of negation is !: it turns zero into one and non-zero into zero.
A combination operator is ,: it allows more calculations in one set command.
Combined assignment operators are modeled on "+=", which, in "a+=b", means "a=a+b". Thus, "a-=b" means "a=a-b". Similarly for *=, /=, %=, &=, ^=, |=, <<=, and >>=.
The precedence order of supported operators, is as follows:
( )
* / % + -
<< >>
&
^
|
= *= /= %= += -= &= ^= |= <<= >>=
,
Literals can be entered as decimal (1234), hexadecimal (0xffff, leading 0x), and octal (0777, leading 0).
The internal bit representation of negative numbers is two's complement. This provides a connection between arithmetic operations and bit operations. For instance, -2147483648 is represented as 0x80000000, and therefore set /a num=~(-2147483647-1) yields 2147483647, which equals 0x7FFFFFFF (type set /a num=0x7FFFFFFF to check).
As some of the operators have special meaning for the command interpreter, an expression using them needs to be enclosed in quotation marks, such as this:
set /a num="255^127"
set /a "num=255^127"
- Alternative placement of quotation marks.
set /a num=255^^127
- Escape ^ using ^ instead of quotation marks.
Examples:
set n1=40 & set n2=25
set /a n3=%n1%+%n2%
- Uses the standard percent notation for variable expansion.
set n1=40 & set n2=25
set /a n3=n1+n2
- Avoids the percent notation around variable names as unneeded for /a.
set /a num="255^127"
- Encloses "^" in quotation marks to prevent its special meaning for the command interpreter.
set /a n1 = (10 + 5)/5
- The spaces around = do not matter with /a. However, getting used to it lends itself to writing "set var = value" without /a, which sets the value of "var " rather than "var".
if 1==1 (set /a n1=(2+4)*5)
- Does not work: the arithmetic brackets within grouping brackets cause trouble.
if 1==1 (set /a n1=^(2+4^)*5)
- Escaping the arithmetic brackets with caret (^) works, as does enclosing "n1=2+(4*5)" in quotation marks.
set /a n1=2+3,n2=4*7
- Performs two calculations.
set /a n1=n2=2
- Has the same effect as n1=2,n2=2.
set n1=40 & set n2=25 & set /a n3=n1+n2
- Works as expected.
set /a n1=2,n2=3,n3=n1+n2
- Works as expected.
set n1=40 & set n2=25 & set /a n3=%n1%+%n2%
- Does not work unless n1 and n2 were set previously. The variable specifications %n1%" and "%n2"% get expanded the first set command is executed. Dropping percent notation makes it work.
before
- Does not work unless n1 and n2 were set previously. The variable specifications %n1%" and "%n2"% get expanded the first set command is executed. Dropping percent notation makes it work.
set /a n1=2,n2=3,n3=%n1%+%n2%
- Does not work unless n1 and n2 were set previously, for the reason stated in the previous example.
set /a n1=0xffff
- Sets n1 using hexadecimal notation.
set /a n1=0777
- Sets n1 using octal notation.
set /a n1=%random%
- A pseudo-random number from 0 to 32767 = 2^15-1.
set /a n1="%random%>>10"
- A pseudo-random number from 0 to 31 = 2^5-1. The shift right operator drops 10 out of 15 bits, keeping 5 bits.
set /a n1=%random%%50
- A pseudo-random number from 0 to 49. Uses the % modulo operator. In a batch, %% is needed for modulo:
set /a n1=%random%%%50
. Because of this particular use of the modulo, the result is not perfectly uniform; it is uniform if the 2nd modulo operand--above 50--equals to a power of 2, e.g. 256 = 2^8.
- A pseudo-random number from 0 to 49. Uses the % modulo operator. In a batch, %% is needed for modulo:
set /a n1="(%random%<<15)+%random%"
- A pseudo-random number from 0 to 1073741823 = 2^30 - 1. Combines the two 15-bit random numbers produced by %random% alone to produce a single 30-bit random number..
set /a n1="((%random%<<15)+%random%)%1000000"
- As above, but again using modulo, this time to achieve the range 0 to 999999.
An example calculation that prints prime numbers:
@echo off
setlocal
set n=1
:print_primes_loop
set /a n=n+1
set cand_divisor=1
:print_primes_loop2
set /a cand_divisor=cand_divisor+1
set /a cand_divisor_squared=cand_divisor*cand_divisor
if %cand_divisor_squared% gtr %n% echo Prime %n% & goto :print_primes_loop
set /a modulo=n%%cand_divisor
if %modulo% equ 0 goto :print_primes_loop & REM Not a prime
goto :print_primes_loop2
Links: