Erreurs d'arrondi pendant la transition

En Bavière, une moyenne générale de \(2{,}33\) permet d'accéder au Gymnasium \(2{,}34\) ne le permet pas. À ce seuil précis, l'ordre de deux arrondis peut déterminer l'admission d'un élève. Günther Felbinger analyse les conséquences potentielles de cet effet d'arrondi dans un article de blog . Par simple curiosité, j'ai moi-même calculé ces effets pour toutes les combinaisons de notes possibles dans le modèle.


Ma question principale est la suivante : dans quelle mesure l’arrondi précoce des notes par matière conduit-il à un type de calcul scolaire différent de celui obtenu avec les moyennes non arrondies ? De plus, il serait intéressant d’observer les changements si les moyennes des matières individuelles (comme suggéré) étaient initialement arrondies à une seule décimale.

Conformément à l'article 6 du règlement bavarois relatif à l'enseignement primaire, la moyenne générale est calculée à partir des notes obtenues en allemand, en mathématiques et en études locales et générales. Le règlement d'application fixe les limites à \(2{,}33\) et à \(2{,}66\) . Dans le modèle de calcul ci-dessous, chaque moyenne générale est arrondie à deux décimales. Ainsi, par exemple…

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

Ceci est crucial pour la classification : \(2{,}3366\ldots\) ne devient pas \(2{,}34\) , mais \(2{,}33\) et est donc toujours suffisant pour l'école de grammaire.

La première entrée illustre un arrondi initial avec les valeurs moyennes supposées spécifiques à la matière \(1{,}6\) , \(2{,}6\) et \(2{,}6\) . À partir de celles-ci, les notes entières \(2\) , \(3\) et \(3\) sont d'abord calculées. Leur moyenne est

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

ce qui signifie que l'élève ne remplit pas les conditions requises pour une admission directe en école sélective. Sans arrondir à l'entier le plus proche, le résultat dans cet exemple hypothétique serait…

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

Dans le second exemple, l'arrondi fonctionne dans le sens inverse : \(2{,}4\) , \(3{,}4\) et \(2{,}4\) deviennent les valeurs entières \(2\) , \(3\) et \(2\) , soit officiellement \(2{,}33\) . Les valeurs non arrondies, quant à elles, donnent \(2{,}73\) . Ces exemples illustrent clairement l'effet. Cependant, ils ne permettent pas encore de déterminer sa fréquence d'apparition ni les conséquences d'une autre méthode d'arrondi.

Par conséquent, pour mon calcul, j'utilise un espace de résultats clair. La moyenne de chaque sujet peut prendre l'une des \(501\) valeurs qu'il contient.

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

Supposons que j'accorde la même importance à toutes les combinaisons ordonnées d'allemand, de mathématiques et d'études locales et générales. Il y a donc

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

Le modèle est donc sans ambiguïté, mais artificiel : il suppose des moyennes égales entre les sujets, l’indépendance des trois sujets et des intervalles d’un centième précis. Il ne reflète pas la répartition réelle des élèves du primaire en Bavière.

Pour trois moyens de sujet \(d,m,h\) nous écrivons

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

pour la moyenne générale arrondie à deux décimales. Nous comparons maintenant trois méthodes de calcul.:

\[
\begin{aligned}
A_0 &= A(\operatorname{round}(d),\operatorname{round}(m),\operatorname{round}(h)),\\
A_1 &= A(\operatorname{round}_1(d),\operatorname{round}_1(m),\operatorname{round}_1(h)),\\
A_\mathrm{ref} &= A(d,m,h).
\end{aligned}
\]

\(A_0\) correspond au calcul utilisant des notes entières, \(A_1\) à la proposition avec une décimale, et \(A_\mathrm{ref}\) à la référence non arrondie du modèle. Ce calcul peut être implémenté directement en Rust , par exemple.:

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
        );
    }
}

La faible tolérance dans calculate_average empêche une valeur telle que \(2{,}67\) En raison de sa représentation binaire flottante, elle a été considérée à tort comme telle. \(2{,}669999\ldots\) est coupé. normalize_grade De plus, elle ramène chaque valeur de boucle à une grille d'ordre cent. Il existe au moins deux valeurs moyennes possibles différentes. \(1/300\) à part; la tolérance de \(10^{-9}\) est donc suffisamment petite pour ne pas modifier un cas limite réel.

Le programme est compilé et lancé avec

rustc -O calc.rs && ./calc

Le programme parcourt toutes \(125\,751\,501\) combinaisons et renvoie:

ComparaisonPartie
Notes entières versus moyennes non arrondies par matière\(10{,}4411\,\%\)
Notes entières comparées à la proposition avec une décimale\(10{,}1521\,\%\)
Proposition avec une décimale comparée aux moyennes d'experts non arrondies\(0{,}6615\,\%\)

La valeur centrale pour moi est \(10{,}4411\,\%\): Dans plus d'une combinaison sur dix, l'arrondi précoce à l'entier le plus proche conduit à un type d'établissement scolaire calculé différent de celui de référence sans arrondi. Cette proportion décrit exclusivement l'effet de l'arrondi au sein du modèle choisi.

Le passage à des moyennes d'experts arrondies à une décimale conduirait à une classification différente dans \(10{,}1521\,\%\) des cas modélisés par rapport à la méthode précédente. Cependant, la troisième comparaison est cruciale : par rapport à la référence non arrondie, la méthode arrondie à une décimale ne présente que \(0{,}6615\,\%\) cas divergents. L'écart par rapport à la référence diminue donc de

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

C’est précisément là, à mon sens, la conséquence problématique de la méthode de calcul actuelle : les résultats disciplinaires supposés restent inchangés ; seul le moment de l’arrondi peut modifier le type d’établissement scolaire calculé. Si le calcul avec une décimale ne supprime pas complètement cet effet, il le réduit considérablement au sein du modèle.

Ces chiffres ne nous indiquent cependant pas le nombre d'enfants réellement concernés. Les notes des bulletins scolaires ne sont pas nécessairement des moyennes arrondies mécaniquement, les performances scolaires ne sont ni uniformément réparties ni indépendantes, et le choix du type d'établissement ne dépend pas uniquement de ces trois chiffres. Mon calcul répond à une question plus précise : à quelle fréquence l'arrondi modifie-t-il la note calculée lorsque toutes les combinaisons de centièmes sont équiprobables ?

Enfin, une comparaison avec le message initial : le taux global mentionné, environ \(10\,\%\) est proche de mon \(10{,}4411\,\%\) . Cependant, mes calculs ne confirment pas les quatre cas individuels, chacun rapporté à \(1/6 \approx 17\,\%\) Pour « échec au collège avec \(3{,}00\) », « échec au lycée avec \(2{,}33\) », « obtention du lycée avec \(2{,}66\) » et « obtention du collège avec \(2{,}66\) \(1{,}4615\,\%\) \(59{,}6096\,\%\) \(1{,}2023\,\%\) \(62{,}9395\,\%\) .

Les quatre valeurs sont des probabilités conditionnelles avec des groupes de référence de tailles différentes. Sans un espace d'échantillonnage défini différemment \(1/6\) . Mon calcul confirme donc l'effet d'arrondi, mais pas ces probabilités individuelles. En tout état de cause, toute affirmation concernant le nombre réel d'enfants touchés nécessiterait les distributions scolaires réelles et leurs dépendances.

Retour