Adloun

Diviser par deux ne rend pas logarithmique

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 5 — Récursivité

Énoncé

Un étudiant écrit : « ma fonction divise la taille par deux à chaque appel, donc elle est en ». Réfuter, sur cette somme dichotomique :


(* somme des cases t.(g .. d-1), par dichotomie *)
let rec somme t g d =
  if d - g <= 1 then (if d - g = 1 then t.(g) else 0)
  else let m = (g + d) / 2 in somme t g m + somme t m d

Corrigé

La fonction est correcte, mais elle n'est pas logarithmique : elle est linéaire. Mesuré, en comptant les appels :


n :                  7    15    1000    100000    1000000
appels :            13    29    1999    199999    1999999
2n - 1 :            13    29    1999    199999    1999999

Pourquoi. La taille est bien divisée par deux, mais il y a deux appels par niveau : la récurrence est , c'est-à-dire la deuxième forme du cours avec . Le nombre d'appels double à chaque niveau et il y a niveaux, donc

L'arbre des appels a de hauteur et de nœuds : ce sont bien les deux grandeurs que le cours distingue, et c'est la seconde qui donne le temps.

Ce qui est logarithmique, c'est : un seul appel par niveau. La dichotomie de recherche l'est, parce qu'elle jette une moitié ; la somme dichotomique ne l'est pas, parce qu'elle doit lire toutes les cases — et aucun algorithme ne peut sommer nombres sans les lire.


un seul appel par niveau (compte des bits de n) :
n = 1000 : 11 appels    n = 1000000 : 21 appels

La formulation juste du critère : ce n'est pas « je divise par deux » qui donne le logarithme, c'est « je divise par deux et j'abandonne une moitié ». La somme dichotomique reste néanmoins utile — elle a une profondeur de pile au lieu de , et ses deux moitiés sont indépendantes, donc parallélisables (chapitre chap:concurrence).

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.