Operators
An operator is a symbol that tells Pebble to do something with one or
two values. You already know + for adding and * for multiplying --
Pebble has many more. Think of operators like the buttons on a calculator:
each one performs a specific action.
Arithmetic Operators
These work on numbers (int and float). When you mix an int with a
float, the result is always a float.
| Operator | Name | Example | Result |
|---|---|---|---|
+ |
Addition | 3 + 2 |
5 |
- |
Subtraction | 5 - 2 |
3 |
* |
Multiplication | 4 * 3 |
12 |
/ |
Division | 7 / 2 |
3.5 |
// |
Floor division | 7 // 2 |
3 |
% |
Modulo | 7 % 3 |
1 |
** |
Exponentiation | 2 ** 3 |
8 |
Division: / vs //
The / operator is true division -- it always gives you a float,
even when the numbers divide evenly:
The // operator is floor division -- it rounds down to the nearest
whole number. If both inputs are int, the result is an int. If either
input is a float, the result is a float:
print(7 // 2) # prints: 3 (both int → int result)
print(7.0 // 2) # prints: 3.0 (float involved → float result)
Exponentiation: **
The ** operator raises a number to a power. Think of 2 ** 3 as
"2 times itself 3 times" (2 × 2 × 2 = 8):
print(2 ** 3) # prints: 8
print(5 ** 0) # prints: 1 (anything to the power of 0 is 1)
print(4.0 ** 0.5) # prints: 2.0 (square root!)
Right-Associativity
When you chain ** operators, they group from right to left. This is
different from + and *, which group from left to right:
# 2 ** 2 ** 3 means 2 ** (2 ** 3) = 2 ** 8 = 256
print(2 ** 2 ** 3) # prints: 256
# Use parentheses to change grouping:
print((2 ** 2) ** 3) # prints: 64
Negative Exponents
A negative exponent produces a float:
Really Big Numbers
A whole number (int) can be very big indeed: up to 1,000,000 bits
(binary digits), which is about 300,000 ordinary digits. So 10 ** 400
is fine, and so is doing sums with it. A few things can't be done with a
number that big, and each stops your program with an error you can
catch with try/catch:
| What you tried | Example | Error |
|---|---|---|
Making a whole number of more than 1,000,000 bits, with any operator or with pow |
print(2 ** 10 ** 9) |
"Number is too large (more than 1,000,000 bits)" |
Printing a number with more than 4,300 digits (or turning it into text with str or "{a}") |
print(10 ** 5000) |
"Number is too long to turn into text (more than 4,300 digits)" |
| Mixing a float with a whole number bigger than about 1.8 × 10308, the biggest float there is | print(10 ** 309 + 0.5) |
"Number is too large to turn into a float" |
| A float power too big for a float | print(10.0 ** 400) |
"Exponentiation result is too large" |
| Turning one that big into a float | float(10 ** 309) |
"Number is too large to turn into a float" |
| Turning infinity or "not a number" into a whole number | int(10.0 ** 308 * 10) |
"Cannot convert inf to int" |
Floats have two strange values of their own. A float sum too big for a
float, like 10.0 ** 308 * 10, gives inf (infinity), and inf - inf
gives nan ("not a number"). You can print them, but no whole number is
infinity, so int() refuses them. The math module
has the same rules for its functions.
/ always gives a float, so dividing two huge whole numbers works when
the answer fits: 10 ** 400 / 10 ** 390 is 10000000000.0.
Why have a limit at all? Without one, 2 ** 10 ** 9 would make Pebble
try to build a number with a billion bits. That takes ages and eats all
the computer's memory, so the program would just freeze. Instead, **,
* and << (and the math module's pow)
work out how big the answer would be before making it, and stop at
once if it's too big. So does a loop that keeps squaring a number:
let x = 3
try {
while true {
x = x * x
}
} catch e {
print(e) # prints: Number is too large (more than 1,000,000 bits)
}
The limit never stops an answer that fits: 1 << 999999 (exactly
1,000,000 bits) is allowed, and 1 << 1000000 is not. 0, 1 and -1
stay small whatever power you raise them to, so 1 ** (10 ** 5000) is
just 1. Floats have their own limits (see above), and the 4,300-digit
limit on turning a number into text is a separate, smaller one.
Unary Operators
Unary operators work on a single value (unlike + and * which need
two values).
| Operator | Name | Example | Result |
|---|---|---|---|
- |
Negate | -5 |
-5 |
not |
Logical NOT | not true |
false |
~ |
Bitwise NOT | ~5 |
-6 |
The - sign binds less tightly than **, so -2 ** 2 means
-(2 ** 2) = -4, not (-2) ** 2 = 4. Use parentheses if you mean
something different:
print(-2 ** 2) # prints: -4 (power first, then negate)
print((-2) ** 2) # prints: 4 (negate first, then power)
Comparison Operators
These compare two values and return true or false. You can compare
int with float -- Pebble handles the conversion for you:
| Operator | Name | Example | Result |
|---|---|---|---|
== |
Equal to | 3 == 3 |
true |
!= |
Not equal to | 3 != 4 |
true |
< |
Less than | 3 < 5 |
true |
<= |
Less than or equal | 3 <= 3 |
true |
> |
Greater than | 5 > 3 |
true |
>= |
Greater than or equal | 5 >= 5 |
true |
print(3 < 3.5) # prints: true (int vs float works fine)
print(3.0 == 3) # prints: true (same value, different types)
Chained Comparisons
Sometimes you want to check whether a number falls between two values --
a range check. Instead of writing two comparisons joined with and,
Pebble lets you chain them together:
Under the hood, Pebble rewrites 1 < x < 10 as (1 < x) and (x < 10).
Both comparisons must be true for the whole expression to be true.
How It Works
Think of it like a sentence: "1 is less than x, which is less than 10." If any link in the chain breaks, the whole thing is false:
let x = 0
print(1 < x < 10) # prints: false (1 < 0 is false)
let x = 15
print(1 < x < 10) # prints: false (15 < 10 is false)
Inclusive Boundaries
Use <= to include the boundary values:
let x = 1
print(1 <= x <= 10) # prints: true (x equals the lower bound)
print(1 < x < 10) # prints: false (1 is not strictly less than 1)
Mixing Operators
You can mix any comparison operators in a chain:
let x = 5
print(1 <= x < 10) # prints: true (at least 1, but less than 10)
print(10 > x > 1) # prints: true (descending range check)
Longer Chains
Chains can have more than two comparisons. Each pair of neighbours is checked:
This works with all six comparison operators: <, <=, >, >=,
==, and !=.
Note: Because
1 < x < 10is rewritten as(1 < x) and (x < 10), a middle value is written into the expression twice, so it is evaluated twice whenever the first comparison is true. (If the first comparison is false,andshort-circuits and the second copy is never evaluated.) This is fine for variables and simple expressions -- the typical use case -- but a middle value with a side effect, like1 < next() < 10, would runnext()twice. Making the middle value evaluate exactly once (as Python does, using a temporary) is a great exercise to try yourself.
Logical Operators
Logical operators combine true / false values. They're like the words
"and", "or", and "not" in English:
| Operator | Meaning | Example | Result |
|---|---|---|---|
and |
Both must be true | true and false |
false |
or |
At least one must be true | true or false |
true |
not |
Flip true to false (and back) | not true |
false |
Bitwise Operators
Bitwise operators work on the individual bits (the 1s and 0s) inside an
integer. They only work on int values -- using them on float or bool
gives an error.
Imagine each number as a row of light switches (bits). Bitwise operators flip, combine, or shift those switches:
| Operator | Name | Example | Result | What it does |
|---|---|---|---|---|
& |
Bitwise AND | 5 & 3 |
1 |
Both bits must be on |
\| |
Bitwise OR | 5 \| 3 |
7 |
Either bit can be on |
^ |
Bitwise XOR | 5 ^ 3 |
6 |
Exactly one bit is on |
~ |
Bitwise NOT | ~5 |
-6 |
Flip all the bits |
<< |
Left shift | 1 << 3 |
8 |
Slide bits left |
>> |
Right shift | 16 >> 2 |
4 |
Slide bits right |
How Bitwise AND Works (Example)
Let's see 5 & 3 step by step. First, write each number in binary:
AND keeps a bit only if both numbers have it on:
So 5 & 3 = 1.
Shifting
Left shift (<<) slides all the bits to the left, filling empty spots with
zeros. Each shift left doubles the number:
Right shift (>>) does the opposite -- slides bits to the right. Each shift
right halves the number (rounding down):
You cannot shift by a negative amount -- that gives an error. Nor can
you shift so far that the answer would have more than 1,000,000 bits
(1 << 10 ** 20): that's the error "Number is too large (more than
1,000,000 bits)" (see Really Big Numbers).
Operator Precedence
When you write 2 + 3 * 4, does Pebble compute (2 + 3) * 4 = 20 or
2 + (3 * 4) = 14? Precedence rules decide the order, just like
the "PEMDAS" rule you might know from maths class.
Higher numbers in this table mean "do this first":
| Level | Operators | Name | Associativity |
|---|---|---|---|
| 12 | - not ~ |
Prefix unary | -- |
| 11 | ** |
Exponentiation | right |
| 10 | * / // % |
Multiplicative | left |
| 9 | + - |
Additive | left |
| 8 | << >> |
Shifts | left |
| 7 | & |
Bitwise AND | left |
| 6 | ^ |
Bitwise XOR | left |
| 5 | \| |
Bitwise OR | left |
| 4 | < <= > >= |
Comparison | left |
| 3 | == != |
Equality | left |
| 2 | and |
Logical AND | left |
| 1 | or |
Logical OR | left |
Examples
# Multiplication before addition (level 10 > level 9)
print(2 + 3 * 4) # prints: 14 (not 20)
# Power before multiplication (level 11 > level 10)
print(2 ** 3 * 2) # prints: 16 (8 * 2, not 2 ** 6)
# Bitwise AND before bitwise OR (level 7 > level 5)
print(1 | 2 & 3) # prints: 3 (1 | (2 & 3) = 1 | 2)
# Shifts before bitwise AND (level 8 > level 7)
print(1 & 3 << 1) # prints: 0 (1 & (3 << 1) = 1 & 6)
# Use parentheses when in doubt!
print((2 + 3) * 4) # prints: 20
Associativity
When operators have the same precedence, associativity decides the order. Most operators are left-associative (group left to right):
The ** operator is the exception -- it's right-associative (group
right to left):
Summary
| Concept | Analogy |
|---|---|
| Operator | A button on a calculator |
/ vs // |
Exact sharing vs whole-piece sharing |
** |
"Times itself" repeated multiplication |
| Bitwise ops | Flipping individual light switches |
<< / >> |
Sliding a row of switches left or right |
| Chained comparisons | Checking if a number is between two values |
| Precedence | The order-of-operations rule from maths |
| Parentheses | "Do this part first!" |