Adloun

Dichotomiser sur la réponse : la racine carrée entière

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 15 — Diviser pour régner

Énoncé

Écrire, avec spécification, terminaison et correction, une fonction rendant sans employer de flottants. Où se cache le débordement ?

Corrigé

La propriété « » est monotone en : vraie jusqu'à un seuil, fausse ensuite. On dichotomise sur ce seuil.


(* Renvoie le plus grand r tel que r*r <= n, c'est-à-dire floor(sqrt n).
   Précondition : n >= 0. Aucun flottant, aucun débordement.
   Complexité : Theta(log n). *)
let racine n =
  let bas = ref 0 and haut = ref (n + 1) in
  (* INVARIANT : bas*bas <= n < haut*haut, et bas < haut. *)
  while !haut - !bas > 1 do
    let m = !bas + (!haut - !bas) / 2 in
    if m <= n / m then bas := m else haut := m       (* PAS m * m <= n *)
  done;
  !bas

Terminaison. Variant : . Comme dès que l'écart dépasse , l'affectation réduit strictement l'écart. Il faut tours.

Correction. L'invariant tient à l'initialisation : et pour . Il est préservé par construction, puisqu'on remplace l'une des bornes par du bon côté du test. À la sortie, et : c'est la définition de .

Le débordement, et il est où l'on ne l'attend pas. La forme naturelle du test est m * m &lt;= n. Or vaut environ au premier tour : le produit approche , qui déborde bien avant . Mesuré en OCaml, dont les entiers font bits (max_int ) :

test `m * m <= n`test `m <= n / m`

La première divergence apparaît à , valeur trouvée en balayant les puissances de deux. Au-delà, la version naïve rend des résultats absurdes — un « » plus grand que — sans le moindre signalement.

Le remède. Écrire m &lt;= n / m : la division entière ne déborde jamais, et le test est équivalent pour . C'est le même geste qu'au chapitre chap:langage-c — x &lt;= INT8_MAX - y plutôt que x + y &lt;= INT8_MAX : on réécrit le test pour que l'expression testée ne puisse pas déborder avant d'être testée.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.