Skip to content
VLSI Mentor

Tcl Part I · Module 4 · Operators and Expressions

Arithmetic Operators

Module 3 established that arithmetic happens inside expr and that expr has an expression language of its own. This module goes through that language operator by operator, starting with the arithmetic you already use. Most of it behaves exactly as you expect, so this chapter spends its time on the parts that do not: how the remainder operator signs its result, why raising to a power associates the opposite way from everything else, and two cases where the answer is a whole number when you were expecting a fraction.

Foundation12 min readTclPart IOperatorsArithmeticexpr

Part I · Module 4 · Chapter 4.1 · Arithmetic Operators

1. The Six

Azvya Education Pvt. Ltd.VLSI Mentor
six.tcl
puts "7 + 3   = [expr {7 + 3}]"
puts "7 - 3   = [expr {7 - 3}]"
puts "7 * 3   = [expr {7 * 3}]"
puts "7 / 3   = [expr {7 / 3}]"
puts "7 % 3   = [expr {7 % 3}]"
puts "2 ** 10 = [expr {2 ** 10}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
7 + 3   = 10
7 - 3   = 4
7 * 3   = 21
7 / 3   = 2
7 % 3   = 1
2 ** 10 = 1024

Add, subtract, multiply, divide, remainder, power. Every expression is braced, for the reasons in Chapter 3.8.

2. Unary Minus and Plus

Azvya Education Pvt. Ltd.VLSI Mentor
unary.tcl
set a 5

puts "negate:        [expr {-$a}]"
puts "negate twice:  [expr {- -$a}]"
puts "unary plus:    [expr {+$a}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
negate:        -5
negate twice:  5
unary plus:    5

Note the space in - -$a. Without it, --$a is not a decrement — Tcl has no ++ or -- operators at all. Counting up is incr, which is Chapter 3.9.

3. Division Is Covered Elsewhere

7 / 3 is 2 because both operands are whole numbers. That is important enough to have its own chapter — Chapter 3.10 — and this chapter does not repeat it.

The one-line version: if you want a fraction, make one operand a real number before dividing.

4. The Remainder, Including Negatives

% gives what is left after whole-number division:

Azvya Education Pvt. Ltd.VLSI Mentor
modulo.tcl
puts "7 % 3 = [expr {7 % 3}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
7 % 3 = 1

With negatives it is less obvious, so here is the complete table rather than one example:

Azvya Education Pvt. Ltd.VLSI Mentor
modulo-signs.tcl
foreach pair {{7 3} {-7 3} {7 -3} {-7 -3}} {
    lassign $pair a b
    puts [format "%3s %% %3s = %3s      %3s / %3s = %3s" \
        $a $b [expr {$a % $b}] $a $b [expr {$a / $b}]]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  7 %   3 =   1        7 /   3 =   2
 -7 %   3 =   2       -7 /   3 =  -3
  7 %  -3 =  -2        7 /  -3 =  -3
 -7 %  -3 =  -1       -7 /  -3 =   2

The remainder takes the sign of the divisor. -7 % 3 is 2, not -1.

This follows from Tcl rounding division toward negative infinity, which Chapter 3.10 §6 covers. C truncates toward zero instead and gives -1 here, so code translated from C needs checking.

% works on whole numbers only:

Azvya Education Pvt. Ltd.VLSI Mentor
modulo-float.tcl
puts [catch {expr {7.5 % 2}} m]
puts $m
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1
can't use floating-point value as operand of "%"

If you need the remainder of a real number, fmod() is in Chapter 4.8.

5. The Power Operator Has Two Surprises

It associates to the right. Every other arithmetic operator groups left to right. ** does not:

Azvya Education Pvt. Ltd.VLSI Mentor
power-assoc.tcl
puts "2 ** 3 ** 2  = [expr {2 ** 3 ** 2}]"
puts "(2 ** 3) ** 2 = [expr {(2 ** 3) ** 2}]"
puts "2 ** (3 ** 2) = [expr {2 ** (3 ** 2)}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
2 ** 3 ** 2  = 512
(2 ** 3) ** 2 = 64
2 ** (3 ** 2) = 512

2 ** 3 ** 2 is 2 to the power 9, not 8 squared. This matches ordinary mathematical notation, and it is the opposite of what you get by reading left to right.

Unary minus binds tighter than it does in most languages:

Azvya Education Pvt. Ltd.VLSI Mentor
power-unary.tcl
puts "-2 ** 2 = [expr {-2 ** 2}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-2 ** 2 = 4

Tcl computed (-2) ** 2, which is 4. Python and several other languages compute -(2 ** 2), which is -4.

6. Powers Follow the Integer Rule Too

Azvya Education Pvt. Ltd.VLSI Mentor
power-integer.tcl
puts "2 ** -1    = [expr {2 ** -1}]"
puts "2.0 ** -1  = [expr {2.0 ** -1}]"
puts "4 ** 0.5   = [expr {4 ** 0.5}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
2 ** -1    = 0
2.0 ** -1  = 0.5
4 ** 0.5   = 2.0

2 ** -1 is one half, which as a whole number is 0. Two whole-number operands give a whole-number answer, exactly as with division.

The fix is the same: make one operand real, or use sqrt() and the other functions in Chapter 4.8.

One more, because the error is clear and worth recognising:

Azvya Education Pvt. Ltd.VLSI Mentor
power-domain.tcl
puts [catch {expr {(-8) ** (1.0/3)}} m]
puts $m
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1
domain error: argument not in valid range

Raising a negative number to a fractional power has no real answer, and Tcl says so rather than returning something meaningless.

7. Big Numbers Still Work

From Chapter 3.5 §8:

Azvya Education Pvt. Ltd.VLSI Mentor
big.tcl
puts [expr {2 ** 64}]
puts [expr {3 ** 40}]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
18446744073709551616
12157665459056928801

Whole-number arithmetic has arbitrary precision, so powers do not overflow. If you want the real-number version, write a real operand.

8. Common Mistakes

Expecting / to give a fraction. Chapter 3.10.

Expecting -7 % 3 to be -1. It is 2. §4.

Reading 2 ** 3 ** 2 left to right. It is right-associative. §5.

Expecting -2 ** 2 to be -4. Tcl negates first. §5.

Using % on a real number. Use fmod(). §4.

Looking for ++ or --. They do not exist. Use incr.

9. Exercises

Exercise 1 — the six. Compute, predict first: 9 + 4, 9 - 4, 9 * 4, 9 / 4, 9 % 4, 9 ** 2.

Exercise 2 — the sign table. Without running, fill in -9 % 4, 9 % -4 and -9 % -4. Then check with the §4 loop. Which rule did you have to apply?

Exercise 3 — wrap an index. Write one expression that turns any integer i into a value between 0 and 6, and test it with i equal to 3, 10, -1 and -8. You should not need an if.

Exercise 4 — two power surprises. Predict 3 ** 2 ** 2 and -3 ** 2, then check. Rewrite both with parentheses so that a reader does not need to know the rules.

Exercise 5 — fix a fraction. expr {5 ** -2} gives 0. Produce 0.04 in two different ways.

Exercise 6 — the remainder of a real number. expr {7.5 % 2} fails. Find the answer another way, then say why Tcl refuses the operator form.

10. Remember

  • Six operators: + - * / % **, all inside expr.
  • There is no ++ or --. Use incr.
  • Whole-number division discards the fraction — Chapter 3.10.
  • % takes the sign of the divisor. -7 % 3 is 2, where C gives -1.
  • That makes $i % $n safe for wrapping an index, including negative i.
  • % rejects real numbers. Use fmod().
  • ** associates to the right: 2 ** 3 ** 2 is 512.
  • Unary minus binds tighter than **: -2 ** 2 is 4, not -4.
  • Parenthesise every power expression. Two surprises in one operator is enough.
  • 2 ** -1 is 0, by the same whole-number rule as division.

Next: the order Tcl applies all of these in, and the habit that makes the order stop mattering.

Where this fits

Part of the Tcl curriculum.