# education.weighted-grade
The overall percentage for a module or course made of weighted components:
coursework worth 40% marked out of 60, an exam worth 60% marked out of 120,
and so on. Each component contributes `mark / outOf x weight`, the sum is
kept as an exact fraction (`percent`), and it is rounded once, at the end, to
the places and rounding mode the caller names (`scaled`).
## Why exact, then one rounding
Component percentages are usually repeating decimals (45 out of 60 is fine;
88 out of 120 is 73.333...). Adding them as floats can land a hair under a
.5 and round the wrong way: 10/30 at 50% plus 29/300 at 50% is exactly 21.5,
which floats compute as 21.4999999..., so a half-up round to whole marks
gives 21 instead of 22. A vector pins that case. Rounding each component
before adding is a second, commoner source of drift and is not done here.
## Decisions
- **Weights are basis points and must total 10000.** A table that adds up to
99.99% is almost always a typo, so it is refused rather than normalised.
Equal thirds are 3333, 3333, 3334: say which component carries the extra
basis point.
- A weight of 0 is allowed (a formative piece recorded alongside), and adds
nothing.
- `scaled` is an integer so no float ever carries the answer: 74.3% at one
decimal place is `743`. Grade the student with `education.grade-boundaries`
on the scaled value if your boundaries are in percent.
- Components not yet sat, capped resits and compensation rules are the
institution's regulations and are out of scope: pass only marks that count.
## Errors
An empty list, a mark outside 0 to `outOf`, `outOf` below 1, a negative
weight, weights not totalling 10000, `decimals` outside 0 to 6, or an unknown
rounding mode all raise.