= Solution
For `Uniform`, require a nonempty <integer interval>. Compute its size in `Long` before converting to `Double`, avoiding <integer overflow> in `u-l+1`. For `Flip`, require $0\leq p\leq1$, and omit zero-<probability> outcomes from the reported support.
``
class Uniform(l: Int, u: Int) extends FiniteDist[Int] {
require(l <= u)
private val size = u.toLong - l.toLong + 1L
def getDom: List[Int] = {
val result = List.newBuilder[Int]
var x = l.toLong
while (x <= u.toLong) { result += x.toInt; x += 1L }
result.result()
}
def getProb(x: Int): Double =
if (l <= x && x <= u) 1.0 / size.toDouble else 0.0
}
class Flip(p: Double) extends FiniteDist[Boolean] {
require(0.0 <= p && p <= 1.0)
def getDom: List[Boolean] =
if (p == 0.0) List(false)
else if (p == 1.0) List(true)
else List(true, false)
def getProb(x: Boolean): Double = if (x) p else 1.0-p
}
``
The first is a <discrete uniform distribution>; the second is a <Bernoulli distribution> on <Boolean> values. Their exact mathematical <probability mass functions> are
$$
\boxed{p_U(x)=\begin{cases}\dfrac1{u-l+1}&l\leq x\leq u,\\0&\text{otherwise},\end{cases}\qquad p_F(\mathrm{true})=p,\quad p_F(\mathrm{false})=1-p.}
$$
Each support contains exactly the positive-<probability> outcomes once, and the <probabilities> sum to one. `Double` approximates these exact values by <floating-point arithmetic>. Materializing a huge support is limited by available memory; the `Long` calculation keeps its cardinality and endpoints arithmetically correct.
Back to article page