In Dart, how do the /, ~/ and % operators differ on int operands, and what do ~/ and % give for negative numbers?
answer
- one of them never returns int
- rounding toward zero, not down
- Euclidean, never negative
- remainder() keeps the dividend's sign
- n /= 2 on an int
basics
~20 sIn Dart, / always returns a double, ~/ returns an int truncated toward zero (-7 ~/ 2 is -3), and % is Euclidean modulo whose result is never negative (-5 % 3 is 1); remainder() gives the sign-following remainder.
solid answer
~40 s`/` is declared as `double operator /(num other)`, so `4 / 2` is `2.0`, never an `int`. `~/` is truncating division: it returns an `int` rounded toward zero, so `-7 ~/ 2` is `-3`, not `-4`. `%` is Euclidean modulo: the result is always between `0` and `b.abs()`, so `-5 % 3` is `1`, which makes it the right tool for wrapping an index. The truncated remainder is the `remainder()` method, where `(-5).remainder(3)` is `-2`, and it pairs with `~/` so that `a == (a ~/ b) * b + a.remainder(b)`. Compound forms follow the same types: `n /= 2` on an `int` does not compile, `n ~/= 2` does.
code
dart · 15 linesvoid main() {
print(7 / 2); // 3.5
print(4 / 2); // 2.0 (a double)
print(-7 ~/ 2); // -3 (toward zero)
print(-5 % 3); // 1 (Euclidean)
print((-5).remainder(3)); // -2
const pageCount = 5;
var page = 0;
page = (page - 1) % pageCount; // wraps to 4
print(page);
var seconds = 135;
print('${seconds ~/ 60}m ${seconds % 60}s'); // 2m 15s
}go deeper
Recall the three operators and their result types: / gives a double, ~/ gives an int, % gives the modulo. Have one negative example ready for each.
Explain truncation toward zero versus Euclidean modulo, name remainder() as the sign-following alternative, and show why n /= 2 on an int is a compile error.
Show where the choice bites in real code: wrapping carousel or ring-buffer indices with %, splitting signed durations with ~/ and remainder(), and guarding ~/ against a zero divisor.
Frame numeric operators as a correctness and portability concern: lint for toInt() after /, and remember that web builds use JavaScript numbers, so bitwise and large-integer results can differ from native.
## The three division-family operators Dart gives integer arithmetic **three** related operators, and interviewers use them to check whether a candidate has actually written Dart rather than guessing from another language. | Operator | Name | Result type | `7 op 2` | `-7 op 2` | |---|---|---|---|---| | `/` | division | always `double` | `3.5` | `-3.5` | | `~/` | truncating division | always `int` | `3` | `-3` | | `%` | Euclidean modulo | `int` if both operands are `int`, else `double` | `1` | `1` | - **`/` never returns an `int`.** `num` declares `double operator /(num other)`, so even `4 / 2` is the double `2.0`. Code that expects an index or a count from `/` does not compile once the result reaches an `int` variable. - **`~/` truncates toward zero.** The SDK documents it as division "where a fractional result is converted to an integer by rounding towards zero". `-7 ~/ 2` is `-3`, not `-4`: it is not a floor. - **`%` is Euclidean, not a truncated remainder.** The result is never negative: `-5 % 3 == 1` and `5 % -3 == 2`. The SDK doc comment states the rule as `a == b * q + r` with `0 <= r < b.abs()`. ## `remainder()` is the other remainder Because `%` is Euclidean, Dart keeps the truncated remainder as a method, `num.remainder`. Its sign follows the dividend: `(-5).remainder(3) == -2`. It pairs with `~/` through the identity documented on `~/`: ```dart a == (a ~/ b) * b + a.remainder(b) ``` The parentheses in `(-5).remainder(3)` matter. Member access binds tighter than unary minus, so `-5.remainder(3)` means `-(5.remainder(3))`. It happens to give the same `-2` here, but only by coincidence. When to use which: 1. **Wrapping an index into a range** (a carousel page, a ring buffer, a weekday offset): use `%`. `(index - 1) % length` stays in `0..length-1` even when `index` is `0`. 2. **Splitting a quantity into whole units and a rest** (seconds into minutes and seconds): use `~/` for the units and `%` for the rest when the value is non-negative. With negative values, pair `~/` with `remainder()`, because `~/` rounds toward zero while `%` is Euclidean, so the two only pair up for non-negative values. 3. **Anything fractional** (averages, ratios, progress): use `/` and keep a `double`. ## Edge cases worth knowing - **Doubles in `~/`**: if either operand is a `double`, the other is converted and the result is `(a / b).truncate()`. `7.5 ~/ 2` is `3`, still an `int`. - **Dividing by zero**: `5 / 0` is `double.infinity` and does not throw. `5 ~/ 0` throws an `UnsupportedError`, because no finite integer exists; the deprecated `IntegerDivisionByZeroException` also implements `UnsupportedError`, so catching that type covers both. - **The `use_truncating_division` lint** flags `(a / b).toInt()` and asks for `a ~/ b`, which is shorter and can be faster on some platforms. ## Increment and compound assignment Every binary arithmetic operator has a compound form: `+=`, `-=`, `*=`, `/=`, `~/=`, `%=`, plus the bitwise and shift forms `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`. `a op= b` means `a = a op b`, and the result must still be assignable to `a`'s type. That makes one line a classic trap: ```dart int n = 10; n /= 4; // compile-time error: double can't be assigned to int n ~/= 4; // fine: n == 2 ``` Prefix and postfix increment differ only in the value of the expression. `++a` increments first and yields the new value; `a++` yields the old value and then increments. After `var a = 0; var b = a++;`, `a` is `1` and `b` is `0`. ## Bitwise and shift operators in brief On `int`, Dart has `&`, `|`, `^`, `~` (complement), `<<`, `>>` (arithmetic shift, keeps the sign) and `>>>` (unsigned shift, fills with zeros; language version 2.14 or later). `(-9) >>> 2` is positive, while `-9 >> 2` stays negative. A negative shift amount is an error. Typical Flutter-side uses are packing flags into an `int` and masking bits out of a raw value. On the web, integers are JavaScript numbers and these operators work on 32 bits, so results for large or negative operands can differ from native. ## What an interviewer listens for - That `/` always yields a `double` and `~/` always yields an `int`. - That `~/` truncates toward zero and that `%` is never negative, with a concrete negative example. - That `remainder()` exists for the truncated case. - That `n /= x` on an `int` does not compile, and `~/=` is the fix.
- Why does `int n = 10; n /= 4;` fail to compile in Dart, and what do you write instead?A compound assignment `n /= 4` means `n = n / 4`, and `/` always produces a `double`. A `double` cannot be assigned to an `int` variable, so the analyzer rejects it. Use `n ~/= 4` for integer division (giving `2`), or declare `n` as `double` or `num` if you really want the fraction.
- What happens in Dart when you divide by zero with / and with ~/?`5 / 0` follows floating-point rules and yields `double.infinity` without throwing. `5 ~/ 0` must produce an `int`, and no finite integer exists, so it throws an `UnsupportedError`. The old `IntegerDivisionByZeroException` is deprecated and implements `UnsupportedError`, so catching `UnsupportedError` covers both. Better still, check the divisor first.
- When would you use remainder() instead of % in Dart?Use `remainder()` when you need the result to pair with `~/` for possibly negative values, for example splitting a signed duration into whole minutes and the rest so that `(a ~/ b) * b + a.remainder(b) == a`. Use `%` when you need a non-negative result, such as wrapping a list index or a day-of-week offset.
saying these in an interview costs you the question
- Thinks 4 / 2 gives the int 2 in Dart
- Says ~/ rounds down, so -7 ~/ 2 is -4
- Expects -5 % 3 to be -2 as in a truncated remainder
- Uses (a / b).toInt() everywhere instead of ~/
- Believes n /= 2 on an int silently truncates