Adloun

Le cours raconte qu'en 2006, un débordement d'entier a été découvert…

Exercice supplémentaire · niveau 3 (difficile) · NSI (première), chapitre 8 — Dichotomie, voisins et gloutons · Le défaut de 2006, et la dichotomie ailleurs

Énoncé

Le cours raconte qu'en 2006, un débordement d'entier a été découvert dans la dichotomie de la bibliothèque Java. Simuler un entier signé sur bits et reproduire le défaut. Pourquoi Python y échappe-t-il, et quelle écriture corrige le problème dans les deux cas ?

Corrigé


def milieu_java(gauche, droite, bits=32):
    """Simule (gauche + droite) // 2 sur un entier SIGNE de 32 bits."""
    s = gauche + droite
    limite = 2 ** (bits - 1)
    if s >= limite:              # debordement : le bit de signe bascule
        s = s - 2 ** bits
    return s // 2

g, d = 2 ** 30, 2 ** 30 + 10
assert milieu_java(g, d) < 0     # indice NEGATIF
assert (g + d) // 2 > 0          # en Python, aucun probleme

Le mécanisme, en une phrase. Sur un tableau de plus d'un milliard de cases, dépasse , la plus grande valeur représentable : le bit de poids fort bascule, et le nombre devient négatif. Le programme lit alors t[-quelque chose] — en Java, une erreur d'accès ; le tableau ne contient évidemment rien à cet indice.

Pourquoi Python n'est pas concerné. Ses entiers n'ont pas de taille fixe : ils grandissent tant que la mémoire suit. C'est le chapitre 1, et c'est aussi ce qui rend le défaut invisible à un élève qui ne programmerait qu'en Python — d'où l'intérêt de le simuler.

La correction, valable partout.


assert g + (d - g) // 2 == (g + d) // 2

for _ in range(2000):
    a = random.randint(0, 10**9)
    b = random.randint(a, 10**9)
    assert a + (b - a) // 2 == (a + b) // 2

donne exactement le même résultat, mais ne calcule jamais de somme plus grande que droite : aucun débordement possible. La boucle de test vérifie l'égalité sur deux mille couples — car une correction qui changerait la valeur calculée ne serait pas une correction.

Ce que l'anecdote enseigne. Le code fautif était prouvé correct, au sens mathématique, et il l'était : la preuve raisonnait sur des entiers, la machine travaillait sur des entiers de bits. Une preuve ne vaut que pour le modèle dans lequel elle est écrite. Neuf ans se sont écoulés avant que quelqu'un remarque l'écart.

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.