Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0ebeee6

Browse files
depialcolinleach
andauthoredJun 22, 2025··
add concept exercise problematic-probabilities (#966)
* add concept exercise problematic-probabilities * Update instructions.md It's hard to even guess which time zone you are in currently, so I went ahead and fixed the typo. I'll merge. --------- Co-authored-by: Colin Leach <colinleach@pm.me>
1 parent b6e3ad2 commit 0ebeee6

File tree

9 files changed

+291
-0
lines changed

9 files changed

+291
-0
lines changed
 

‎config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,18 @@
343343
],
344344
"status": "beta"
345345
},
346+
{
347+
"slug": "problematic-probabilities",
348+
"name": "Problematic Probabilities",
349+
"uuid": "f3fe4029-03fd-4dde-aeeb-a05f4873f377",
350+
"concepts": [
351+
"rational-numbers"
352+
],
353+
"prerequisites": [
354+
"loops"
355+
],
356+
"status": "beta"
357+
},
346358
{
347359
"slug": "old-elyses-enchantments",
348360
"name": "Old Elyse's Enchantments",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Hints
2+
3+
## 1. Give the ratio of successes to trials
4+
5+
- Create `Rational` numbers using the successes as the numerator and the trials as the denominator.
6+
- Loops, comprehensions or vector operations can be employed to create the new array.
7+
8+
## 2. Find the real probabilities associated with successes to trials
9+
10+
- Create `Float` numbers using the successes as the numerator and the trials as the denominator.
11+
- Loops, comprehensions or vector operations can be employed to create the new array.
12+
13+
## 3. Check the mean of the probabilities
14+
15+
- The mean is found by summing the data and dividing by the number of events.
16+
- Use your `rationalize` and `probabilities` functions.
17+
- If a discrepancy is found between using floats and rationals, return the rational number.
18+
- Loops or vector operations can be employed.
19+
20+
## 4. Check the independent probability
21+
22+
- Probabilities of independent events can be multiplied together to find the total probability of those events happening together.
23+
- Use your `rationalize` and `probabilities` functions.
24+
- If a discrepancy is found between using floats and rationals, return the rational number.
25+
- Loops or vector operations can be employed.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Instructions
2+
3+
A research organization has noticed that some of its junior researchers have been using less-than-optimal methods in their analysis.
4+
One of these methods is to immediately convert discrete probabilites into floats (i.e. real numbers) before doing further calculations.
5+
6+
Senior researchers prefer to use rational numbers in the calculations, which may provide higher precision, and would like to know if the poor practices of the junior researchers have affected the studies' outcomes.
7+
8+
There were two types of studies done:
9+
- Many tests were run, each returning a discrete probability for success, and then the mean of these probabilities was calculated.
10+
- Many independent events were tested, and the total probability for all events to occur was calculated by multiplying them together.
11+
12+
The senior researchers are asking you to write functions which can help them determine if there are rounding errors in the analyses from using floats, and asking you provide a precise rational number for the outcome if there are errors.
13+
14+
## 1. Give the ratio of successes to trials
15+
16+
The `rationalize(successes, trials)` function takes two arrays, `successes` and `trials`.
17+
For an index `i`, `successes[i]` corresponds to the number of successes which occurred in `trials[i]` number of trials.
18+
The function returns an array of rational numbers of the successes over the number of trials, in the same order as the input arrays.
19+
20+
```julia-repl
21+
julia> rationalize([1, 2, 3], [4, 5, 6])
22+
3-element Vector{Rational{Int64}}:
23+
1//4
24+
2//5
25+
1//2
26+
```
27+
28+
## 2. Find the real probabilities associated with successes to trials
29+
30+
Similarly, the `probabilities(successes, trials)` function takes two arrays, `successes` and `trials`.
31+
It returns an array of floats of the successes over the number of trials, in the same order as the input arrays.
32+
33+
```julia-repl
34+
julia> probabilities(([1, 2, 3], [4, 5, 6]))
35+
3-element Vector{Float64}:
36+
0.25
37+
0.4
38+
0.5
39+
```
40+
41+
## 3. Check the mean of the probabilities
42+
43+
The `checkmean(successes, trials)` takes the two arrays, `successes` and `trials`.
44+
It checks the mean of the real probabilities against the mean of the rational probabilities.
45+
- If the two probabilities are equal, `checkmean` returns `true`
46+
- If the two probabilites are different, `checkmean` returns the rational probability.
47+
48+
```julia-repl
49+
julia> successes, trials = [9, 4, 7, 8, 6], [22, 22, 11, 17, 12];
50+
julia> checkmean(successes, trials)
51+
true
52+
53+
julia> successes, trials = [6, 5, 9, 8, 9], [21, 19, 13, 25, 22];
54+
julia> checkmean(sucesses, trials)
55+
1873629//4754750
56+
```
57+
58+
## 4. Check the independent probability
59+
60+
The `checkprob(successes, trials)` takes the two arrays, `successes` and `trials`.
61+
It checks the total probability of the float probabilities against the total probability of the rational probabilities.
62+
- If the two probabilities are equal, `checkprob` returns `true`
63+
- If the two probabilites are different, `checkprob` returns the rational probability.
64+
65+
```julia-repl
66+
julia> successes, trials = [2, 9, 4, 4, 5], [15, 11, 17, 19, 15];
67+
julia> checkprob(successes, trials)
68+
true
69+
70+
julia> successes, trials = [9, 8, 5, 4, 3], [22, 14, 19, 25, 18];
71+
julia> checkprob(sucesses, trials)
72+
12//7315
73+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Introduction
2+
3+
`Rational numbers` are fractions with an integer numerator divided by an integer denominator.
4+
5+
For example, we can store `2//3` as an exact fraction instead of the approximate `Float64` value `0.6666...`
6+
7+
The advantage is that (except in the extreme case of *integer overflow*) a rational number will remain exact, avoiding the rounding errors that are often inevitable with floating-point numbers.
8+
9+
Rational numbers are quite a simple numeric type and aim to work much as you would expect.
10+
Because they have been a standard type in Julia since the early versions, most functions will accept them as input in the same way as integers and floats.
11+
12+
## Creating rational numbers
13+
14+
Creation is as simple as using `//` between two integers.
15+
16+
```julia-repl
17+
julia> 3//4
18+
3//4
19+
20+
julia> a = 3; b = 4;
21+
22+
julia> a//b
23+
3//4
24+
```
25+
26+
Common factors are automatically removed, converting the fraction to its "lowest terms": the smallest integers that accurately represent the fraction, and with a non-negative denominator.
27+
28+
```julia-repl
29+
julia> 5//15
30+
1//3
31+
32+
julia> 5//-15
33+
-1//3
34+
```
35+
36+
## Arithmetic with rational numbers
37+
38+
The usual `arithmetic operators` `+ - * / ^ %` work with rationals, essentially the same as with other numeric types.
39+
40+
Integers and other `Rational`s can be included and give a `Rational` result.
41+
Including a `float` in the expression results in `float` output, with a consequent (possible) loss in precision.
42+
43+
If a `float` is desired, simply use the `float()` function to convert a rational.
44+
It is quite normal to use rational numbers to preserve precision through a long calculation, then convert to a float at the end.
45+
46+
```julia-repl
47+
julia> 3//4 + 1//3 # addition
48+
13//12
49+
50+
julia> 3//4 * 1//3 # multiplication
51+
1//4
52+
53+
julia> 3//4 / 1//3 # division
54+
9//4
55+
56+
julia> 3//4 ^ 2 # exponentiation
57+
3//16
58+
59+
julia> 3//4 + 5 # rational and int => rational
60+
23//4
61+
62+
julia> 3//4 + 5.3 # rational and float => float
63+
6.05
64+
65+
julia> float(3//4) # casting
66+
0.75
67+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"depial"
4+
],
5+
"files": {
6+
"solution": [
7+
"problematic-probabilities.jl"
8+
],
9+
"test": [
10+
"runtests.jl"
11+
],
12+
"exemplar": [
13+
".meta/exemplar.jl"
14+
]
15+
},
16+
"blurb": "Help make statistics more accurate with rational numbers"
17+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Design
2+
3+
## Goal
4+
5+
The goal of this exercise is to introduce the student to rational numbers.
6+
7+
## Learning objectives
8+
9+
- Understand the use of rational numbers
10+
- Understand basic construction and arithmetic operations
11+
- Become more familiar with the key use case of rational numbers: mitigation of rounding errors
12+
13+
## Out of scope
14+
15+
- Subtlties of conversion from rational to floating-point numbers
16+
- Infinite rationals
17+
- `NaN`s
18+
19+
## Concepts
20+
21+
The Concepts this exercise unlocks are:
22+
23+
-
24+
25+
## Prerequisites
26+
27+
- `loops`
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
rationalize = .//
2+
probabilities = ./
3+
4+
function checkmean(successes, trials)
5+
r, p = sum(rationalize(successes, trials)) // length(trials), sum(probabilities(successes, trials)) / length(trials)
6+
float(r) == p || r
7+
end
8+
9+
function checkprob(successes, trials)
10+
r, p = prod(rationalize(successes, trials)), prod(probabilities(successes, trials))
11+
float(r) == p || r
12+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function rationalize(successes, trials)
2+
3+
end
4+
5+
function probabilities(successes, trials)
6+
7+
end
8+
9+
function checkmean(successes, trials)
10+
11+
end
12+
13+
function checkprob(successes, trials)
14+
15+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Test
2+
3+
include("problematic-probabilities.jl")
4+
5+
@testset verbose = true "tests" begin
6+
@testset "rationalize" begin
7+
@test rationalize([2], [4]) == [1//2]
8+
@test rationalize([1, 2, 3, 4], [2, 3, 4, 5]) == [1//2, 2//3, 3//4, 4//5]
9+
end
10+
11+
@testset "probabilities" begin
12+
@test probabilities([2], [4]) == [2/4]
13+
@test probabilities([1, 2, 3, 4], [2, 3, 4, 5]) == [1/2, 2/3, 3/4, 4/5]
14+
end
15+
16+
@testset "average check" begin
17+
successes, trials = [8, 1, 4, 4, 4], [13, 24, 16, 23, 18]
18+
@test checkmean(successes, trials)
19+
20+
successes, trials = [9, 8, 6, 8, 3], [18, 15, 23, 19, 14]
21+
@test checkmean(successes, trials)
22+
23+
successes, trials = [1, 9, 7, 7, 8], [13, 16, 13, 12, 21]
24+
@test checkmean(successes, trials) == 3119//7280
25+
26+
successes, trials = [1, 6, 8, 6, 5], [20, 15, 18, 11, 25]
27+
@test checkmean(successes, trials) == 3247//9900
28+
end
29+
30+
@testset "probability check" begin
31+
successes, trials = [4, 2, 4, 3, 2], [18, 20, 18, 25, 22]
32+
@test checkprob(successes, trials)
33+
34+
successes, trials = [9, 1, 8, 4, 3], [14, 22, 15, 15, 20]
35+
@test checkprob(successes, trials)
36+
37+
successes, trials = [6, 2, 2, 9, 8], [18, 23, 12, 18, 16]
38+
@test checkprob(successes, trials) == 1//828
39+
40+
successes, trials = [9, 3, 7, 6, 7], [11, 17, 13, 13, 17]
41+
@test checkprob(successes, trials) == 7938//537251
42+
end
43+
end

0 commit comments

Comments
 (0)
Please sign in to comment.