Błędy zaokrągleń podczas przejścia

W Bawarii średnia ocen \(2{,}33\) potwierdza kwalifikacje do \(2{,}34\) nie. Przy tak ostrym progu punktowym, kolejność dwóch operacji zaokrąglania może decydować o tym, po której stronie upadnie dziecko. Günther Felbinger omawia potencjalne konsekwencje tego efektu zaokrąglania w poście na blogu . Z czystej ciekawości sam obliczyłem efekty dla wszystkich kombinacji klas dozwolonych w modelu.


Moje główne pytanie brzmi: Jak często wczesne zaokrąglanie ocen do pełnych przedmiotów prowadzi do innego rodzaju obliczeń szkolnych niż obliczenia z wykorzystaniem niezaokrąglonych średnich ocen z przedmiotów? Co więcej, ciekawie byłoby zobaczyć, co się zmieni, jeśli średnie z poszczególnych przedmiotów (jak tam zasugerowano) zostaną początkowo zaokrąglone tylko do jednego miejsca po przecinku.

Zgodnie z § 6 Bawarskiego Regulaminu Szkoły Podstawowej, średnia ocen jest obliczana na podstawie ocen z języka niemieckiego, matematyki oraz przedmiotów ogólnokształcących i lokalnych. Przepisy wykonawcze określają limity do \(2{,}33\) i do \(2{,}66\) . W poniższym modelu obliczeniowym każda średnia ocen jest skracana do dwóch miejsc po przecinku i nie jest ponownie zaokrąglana. Tak więc, na przykład...

\[
\frac{2{,}33+2{,}34+2{,}34}{3}=2{,}3366\ldots \longrightarrow 2{,}33.
\]

Jest to kluczowe dla klasyfikacji: \(2{,}3366\ldots\) nie zmienia się w \(2{,}34\) , lecz w \(2{,}33\) i w związku z tym nadal wystarcza dla szkoły podstawowej.

Początkowy wpis ilustruje wczesne zaokrąglanie z założonymi średnimi wartościami przedmiotowymi \(1{,}6\) , \(2{,}6\) i \(2{,}6\) . Na ich podstawie najpierw wyprowadzane są oceny całkowite \(2\) , \(3\) i \(3\) . Ich średnia wynosi

\[
\frac{2+3+3}{3}=2{,}6666\ldots \longrightarrow 2{,}66,
\]

Co oznacza, że uczeń nie kwalifikuje się do bezpośredniego przyjęcia do szkoły podstawowej. Jednak bez zaokrąglania do pełnych ocen, wynik w hipotetycznym przykładzie wyglądałby następująco...

\[
\frac{1{,}6+2{,}6+2{,}6}{3}=2{,}2666\ldots \longrightarrow 2{,}26.
\]

W drugim przykładzie zaokrąglanie działa w odwrotnym kierunku: \(2{,}4\) , \(3{,}4\) i \(2{,}4\) stają się wartościami całkowitymi nut \(2\) , \(3\) i \(2\) , oficjalnie \(2{,}33\) . Wartości niezaokrąglone dają jednak \(2{,}73\) . Przykłady wyraźnie ilustrują ten efekt. Nie ujawniają jednak jeszcze, jak często występuje on ani jakie byłyby konsekwencje zastosowania innej metody zaokrąglania.

Dlatego do moich obliczeń używam czystej przestrzeni wynikowej. Każda średnia badana może być jedną z wartości \(501\) w niej zawartych.

\[
1{,}00,\, 1{,}01,\, 1{,}02,\, \ldots, \, 5{,}99, \, 6{,}00
\]

Załóżmy. Przypisuję jednakową wagę wszystkim uporządkowanym kombinacjom języka niemieckiego, matematyki oraz studiów lokalnych i ogólnych. Zatem istnieją

\[
501^3=125\,751\,501
\]

Przypadki. Model jest zatem jednoznaczny, ale sztuczny: zakłada równomierny rozkład średnich ocen z przedmiotów, niezależność trzech przedmiotów i stopnie wynoszące dokładnie jedną setną. Nie odzwierciedla on rzeczywistego rozkładu uczniów szkół podstawowych w Bawarii.

Dla trzech podmiotów oznaczających \(d,m,h\) piszemy

\[
A(d,m,h)=\frac{\left\lfloor 100\cdot\frac{d+m+h}{3}\right\rfloor}{100}
\]

dla średniej ogólnej obciętej do dwóch miejsc po przecinku. Teraz porównamy trzy metody obliczania.:

\[
\begin{wyrównane}
A_0 &= A(\operatorname{runda}(d),\operatorname{runda}(m),\operatorname{runda}(h)),\\
A_1 &= A(\operatorname{runda}_1(d),\operatorname{runda}_1(m),\operatorname{runda}_1(h)),\\
A_\mathrm{ref} &= A(d,m,h).
\koniec{wyrównany}
\]

\(A_0\) odpowiada obliczeniu z wykorzystaniem ocen całkowitych, \(A_1\) propozycji z jednym miejscem po przecinku, a \(A_\mathrm{ref}\) niezaokrąglonemu odniesieniu w modelu. Obliczenie można zaimplementować bezpośrednio na przykład w Rust .:

const SCHOOL_GYMNASIUM: i32 = 0;
const SCHOOL_REALSCHULE: i32 = 1;
const SCHOOL_MITTELSCHULE: i32 = 2;
const FLOAT_TOLERANCE: f64 = 1e-9;

#[derive(Clone, Copy, Default)]
struct Statistic {
    conflict_count: u64,
    total_count: u64,
}

fn determine_school(average: f64) -> i32 {
    if average <= 2.33 {
        return SCHOOL_GYMNASIUM;
    }
    if average <= 2.66 {
        return SCHOOL_REALSCHULE;
    }
    SCHOOL_MITTELSCHULE
}

fn calculate_average(note_deutsch: f64, note_mathe: f64, note_hsu: f64) -> f64 {
    let average = (note_deutsch + note_mathe + note_hsu) / 3.0;
    ((average + FLOAT_TOLERANCE) * 100.0).floor() / 100.0
}

fn round_to_whole_grade(grade: f64) -> f64 {
    grade.round()
}

fn round_to_one_decimal(grade: f64) -> f64 {
    (grade * 10.0).round() / 10.0
}

fn normalize_grade(grade: f64) -> f64 {
    (grade * 100.0).round() / 100.0
}

fn percentage(count: u64, total: u64) -> f64 {
    count as f64 / total as f64 * 100.0
}

fn main() {
    let mut combination_count = 0;
    let mut official_reference_conflicts = 0;
    let mut official_proposal_conflicts = 0;
    let mut proposal_reference_conflicts = 0;
    let mut statistics = [Statistic::default(); 4];

    let mut note_deutsch = 1.0;
    while note_deutsch <= 6.0 {
        let mut note_mathe = 1.0;
        while note_mathe <= 6.0 {
            let mut note_hsu = 1.0;
            while note_hsu <= 6.0 {
                combination_count += 1;

                let official_average = calculate_average(
                    round_to_whole_grade(note_deutsch),
                    round_to_whole_grade(note_mathe),
                    round_to_whole_grade(note_hsu),
                );
                let proposed_average = calculate_average(
                    round_to_one_decimal(note_deutsch),
                    round_to_one_decimal(note_mathe),
                    round_to_one_decimal(note_hsu),
                );
                let reference_average =
                    calculate_average(note_deutsch, note_mathe, note_hsu);
                let official_school = determine_school(official_average);
                let proposed_school = determine_school(proposed_average);
                let reference_school = determine_school(reference_average);

                if official_average == 3.0 {
                    statistics[0].total_count += 1;
                    if reference_school != SCHOOL_MITTELSCHULE {
                        statistics[0].conflict_count += 1;
                    }
                }
                if official_average == 2.66 {
                    statistics[1].total_count += 1;
                    if reference_school == SCHOOL_GYMNASIUM {
                        statistics[1].conflict_count += 1;
                    }
                }
                if official_average == 2.33 {
                    statistics[2].total_count += 1;
                    if reference_school != SCHOOL_GYMNASIUM {
                        statistics[2].conflict_count += 1;
                    }
                }
                if official_average == 2.66 {
                    statistics[3].total_count += 1;
                    if reference_school == SCHOOL_MITTELSCHULE {
                        statistics[3].conflict_count += 1;
                    }
                }

                if official_school != reference_school {
                    official_reference_conflicts += 1;
                }
                if official_school != proposed_school {
                    official_proposal_conflicts += 1;
                }
                if proposed_school != reference_school {
                    proposal_reference_conflicts += 1;
                }

                note_hsu = normalize_grade(note_hsu + 0.01);
            }
            note_mathe = normalize_grade(note_mathe + 0.01);
        }
        note_deutsch = normalize_grade(note_deutsch + 0.01);
    }

    println!(
        "official/reference: {}%",
        percentage(official_reference_conflicts, combination_count)
    );
    println!(
        "official/proposal: {}%",
        percentage(official_proposal_conflicts, combination_count)
    );
    println!(
        "proposal/reference: {}%",
        percentage(proposal_reference_conflicts, combination_count)
    );
    for (index, statistic) in statistics.iter().enumerate() {
        println!(
            "#{}: {}% ({}/{})",
            index + 1,
            percentage(statistic.conflict_count, statistic.total_count),
            statistic.conflict_count,
            statistic.total_count
        );
    }
}

Mała tolerancja w calculate_average zapobiega wartości takiej jak \(2{,}67\) ze względu na binarną reprezentację typu float, błędnie uznano ją za \(2{,}669999\ldots\) jest odcięty. normalize_grade Co więcej, redukuje każdą wartość pętli z powrotem do siatki setnego rzędu. Istnieją co najmniej dwie różne możliwe wartości średnie. \(1/300\) oddzielnie; tolerancja \(10^{-9}\) jest zatem na tyle mała, że nie zmienia żadnego realnego przypadku granicznego.

Program jest kompilowany i uruchamiany za pomocą

rustc -O calc.rs && ./calc

Program iteruje przez wszystkie \(125\,751\,501\) kombinacji i zwraca:

PorównanieCzęść
Oceny całkowite a średnie ocen przedmiotowych niezaokrąglone\(10{,}4411\,\%\)
Oceny całkowite w porównaniu do propozycji z jednym miejscem po przecinku\(10{,}1521\,\%\)
Propozycja z jednym miejscem po przecinku w porównaniu do niezaokrąglonych średnich eksperckich\(0{,}6615\,\%\)

Dla mnie najważniejszą wartością jest \(10{,}4411\,\%\): W ponad jednej na dziesięć kombinacji wczesne zaokrąglanie do pełnych ocen prowadzi do innego obliczonego typu szkoły niż niezaokrąglony punkt odniesienia. Ten odsetek opisuje wyłącznie efekt zaokrąglania w wybranym modelu.

Przejście na średnie eksperckie z jednym miejscem po przecinku prowadziłoby do innej klasyfikacji w \(10{,}1521\,\%\) wszystkich przypadków modelowych w porównaniu z poprzednią metodą. Jednak trzecie porównanie jest kluczowe: w porównaniu z niezaokrąglonym odniesieniem, metoda z jednym miejscem po przecinku pozostawia jedynie \(0{,}6615\,\%\) przypadków odchylonych. Odchylenie od odniesienia zmniejsza się zatem o

\[
1-\frac{0{,}6615}{10{,}4411}\approx 93{,}7\,\%.
\]

To właśnie, moim zdaniem, jest wątpliwą konsekwencją obecnej metody obliczeniowej: zakładane osiągnięcia przedmiotowe pozostają niezmienione; jedynie moment zaokrąglenia może zmienić obliczony typ szkoły. Chociaż obliczenia z jednym miejscem po przecinku nie eliminują całkowicie tego efektu, to jednak znacząco go ograniczają w modelu.

Liczby te nie mówią nam jednak, ilu dzieci jest faktycznie dotkniętych tym problemem. Oceny na świadectwach szkolnych niekoniecznie są generowane jako mechanicznie zaokrąglone średnie, wyniki w nauce nie są ani równomiernie rozłożone, ani niezależne, a rzeczywisty wybór typu szkoły nie zależy wyłącznie od tych trzech liczb. Moje obliczenia odpowiadają na bardziej szczegółowe pytanie: jak często zaokrąglenie zmienia obliczoną ocenę, gdy wszystkie kombinacje setnych części są równie prawdopodobne?

Na koniec porównanie z oryginalnym postem: Podany tam ogólny wskaźnik, wynoszący około \(10\,\%\) jest bliski mojemu \(10{,}4411\,\%\) . Jednak moje obliczenia nie potwierdzają czterech indywidualnych przypadków, z których każdy jest podany jako \(1/6 \approx 17\,\%\) Dla „opuszczenia szkoły średniej z \(3{,}00\) ”, „opuszczenia szkoły podstawowej z \(2{,}33\) ”, „ukończenia szkoły podstawowej z \(2{,}66\) ” i „ukończenia szkoły średniej z \(2{,}66\) \(1{,}4615\,\%\) \(59{,}6096\,\%\) \(1{,}2023\,\%\) \(62{,}9395\,\%\) .

Te cztery wartości to prawdopodobieństwa warunkowe z grupami odniesienia o różnej liczebności. Bez inaczej zdefiniowanej przestrzeni próby nie można z nich wyprowadzić \(1/6\) . Moje obliczenia potwierdzają zatem efekt zaokrąglenia, ale nie te indywidualne prawdopodobieństwa. W każdym razie, stwierdzenia dotyczące rzeczywistej liczby dzieci dotkniętych tym problemem wymagałyby rzeczywistych rozkładów klas i ich zależności.

Plecy