cint university / 201 / ced, the cint editor
201-04: division and rounding
This is lesson 201-04 of CU-201.2, checked against cint 0.2.0.
You will split a bill so the parts add up to the cent, and name the rounding rule wherever a result is not a whole number.
the program
// Split a restaurant bill exactly, in cents, with an 18 percent tip.
void main() {
I64 bill = 10_000;
I64 tip = muldiv(I64, bill, 18, 100, half_even);
I64 total = bill + tip;
I64 people = 3;
I64 share = total / people;
I64 left = total % people;
"bill {bill:/100}, tip {tip:/100}, total {total:/100}\n";
for p in 1..=people {
I64 pays = share;
if (p <= left) { pays += 1; }
"person {p} pays {pays:/100}\n";
}
}
run it
$ cint run bill.ci
bill 100.00, tip 18.00, total 118.00
person 1 pays 39.34
person 2 pays 39.33
person 3 pays 39.33
The three shares add up to 118.00 exactly. The cent that does not divide evenly goes to the first person, and the program says so in one line.
division in cint
/ rounds toward negative infinity, and % takes the sign of the divisor. Together they keep a == (a / b) * b + a % b for every division that does not fault. This is Python's rule, not C's.
void main() {
I64 a = -7;
I64 b = 2;
"a / b = {a / b} a % b = {a % b}\n";
"div_trunc = {div_trunc(a, b)} rem_trunc = {rem_trunc(a, b)}\n";
"div_euclid = {div_euclid(a, b)} rem_euclid = {rem_euclid(a, b)}\n";
"floor {div_round(a, b, floor)} ceil {div_round(a, b, ceil)} trunc {div_round(a, b, trunc)} away {div_round(a, b, away)}\n";
"half_even {div_round(a, b, half_even)} half_away {div_round(a, b, half_away)} half_trunc {div_round(a, b, half_trunc)} half_up {div_round(a, b, half_up)} half_down {div_round(a, b, half_down)}\n";
}
a / b = -4 a % b = 1
div_trunc = -3 rem_trunc = -1
div_euclid = -4 rem_euclid = 1
floor -4 ceil -3 trunc -3 away -4
half_even -4 half_away -4 half_trunc -3 half_up -3 half_down -4
div_truncandrem_truncare C's division: toward zero.div_euclidandrem_euclidkeep the remainder between 0 and|b| - 1.div_round(a, b, mode)rounds the exact quotient, -3.5 here, by a named mode. There are nine modes. Four round in one direction:floor,ceil,truncandaway. Five round to the nearest integer and differ only on ties:half_even,half_away,half_trunc,half_upandhalf_down.
Division by zero faults with E_DIV_ZERO. I64.min / -1, whose exact result is one past I64.max, faults with E_OVERFLOW.
muldiv
muldiv(I64, bill, 18, 100, half_even) computes bill * 18 / 100 with the product held exactly, rounds the quotient once by the mode and checks that the result fits I64. Writing bill * 18 / 100 instead would round down and would fault if the product overflows even when the final result fits.
elsewhere
The same division and the same ties were evaluated in other languages on 2026-10-10:
| Language | -7 / 2 |
-7 % 2 |
rounding -3.5 | rounding 2.5 |
|---|---|---|---|---|
| cint | -4 | 1 | named: half_even gives -4, half_up gives -3 |
named |
| C, GCC 13.3 | -3 | -1 | round(-3.5) is -4, rint(-3.5) is -4 |
round(2.5) is 3, rint(2.5) is 2 |
| Python 3.13 | -7 // 2 is -4 |
1 | round(-3.5) is -4 |
round(2.5) is 2 |
| JavaScript, Node 22.22.0 | Math.trunc(-7 / 2) is -3 |
-1 | Math.round(-3.5) is -3 |
Math.round(2.5) is 3 |
Python's round rounds ties to even, and JavaScript's Math.round rounds them up. C's round rounds them away from zero, while rint follows a rounding mode set elsewhere in the program, by default to even. None of them names its rule at the call. In cint, a div_round or muldiv call carries the rule.
walk-through
Money in cents. The bill is 10000 cents, an I64. Every amount stays an exact whole number of cents, and the only rounding, the tip's, is named in the call.
{bill:/100} prints a value divided by 100 with two decimal places: 10000 prints as 100.00. Only the printing divides; the value is unchanged.
The leftover cent. total % people is 1, so one person pays one more cent. Any rule for who pays it is fine, as long as the program states it and the shares add up.
try this
- Split 100.00 seven ways. How many people pay an extra cent?
- Make the tip 15 percent of 99.99. Round it with
half_even, then withfloor, then withceil. Which ones differ?
reference
division, rounding modes, muldiv, print formats
Next: 201-05, tests and goldens.