$grades */ public function calculateSubjectAverage(array $grades): ?float { if ($grades === []) { return null; } $sumWeighted = 0.0; $sumCoef = 0.0; foreach ($grades as $entry) { $normalizedValue = $entry->gradeScale->convertTo20($entry->value); $sumWeighted += $normalizedValue * $entry->coefficient->value; $sumCoef += $entry->coefficient->value; } return round($sumWeighted / $sumCoef, 2); } /** * Moyenne générale : moyenne arithmétique des moyennes matières. * Les matières sans note sont exclues en amont. * * @param list $subjectAverages */ public function calculateGeneralAverage(array $subjectAverages): ?float { if ($subjectAverages === []) { return null; } return round(array_sum($subjectAverages) / count($subjectAverages), 2); } /** * Statistiques de classe pour une évaluation : min, max, moyenne, médiane. * Les absents et dispensés doivent être exclus en amont. * * @param list $values */ public function calculateClassStatistics(array $values): ClassStatistics { if ($values === []) { return new ClassStatistics( average: null, min: null, max: null, median: null, gradedCount: 0, ); } sort($values); $count = count($values); return new ClassStatistics( average: round(array_sum($values) / $count, 2), min: $values[0], max: $values[$count - 1], median: $this->calculateMedian($values), gradedCount: $count, ); } /** * @param list $sortedValues Valeurs déjà triées par ordre croissant */ private function calculateMedian(array $sortedValues): float { $count = count($sortedValues); $middle = intdiv($count, 2); if ($count % 2 === 0) { return round(($sortedValues[$middle - 1] + $sortedValues[$middle]) / 2, 2); } return $sortedValues[$middle]; } }