Skip to content
Snippets Groups Projects
Commit bac1a093 authored by Guyslain's avatar Guyslain
Browse files

Ajout TD2 (utilisation du debugger)

parent 12c7911f
No related branches found
No related tags found
No related merge requests found
Showing
with 276 additions and 0 deletions
package fr.univamu.progav.td2;
public class ASimpleLoop {
public static double nonTerminatingSum(int n) {
double sum = 0;
for (double i = 0; i != n; i = i + 0.1) {
sum = sum + i ;
}
return sum;
}
}
package fr.univamu.progav.td2;
public class GuessingGame {
public static int solve(int mystery) {
return new GuessingGame(mystery).nbAttempts();
}
public static final int LOWER_BOUND = 1;
public static final int UPPER_BOUND = 1000;
private final int mystery;
private int attempts = 0;
public GuessingGame(int mystery) {
this.mystery = mystery;
guess(LOWER_BOUND, UPPER_BOUND);
}
private int nbAttempts() {
return attempts;
}
private void guess(int lowerBound, int upperBound) {
this.attempts++;
if (lowerBound == upperBound) {
return;
}
int middle = (upperBound + lowerBound) / 2;
if (middle == mystery) {
return;
}
if (middle < mystery) {
guess(middle,upperBound);
} else {
guess(lowerBound,middle-1);
}
}
}
package fr.univamu.progav.td2;
import java.util.List;
public class People {
private final String name;
private final int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
/** Decides whether the list contains a 25-year-old "Charlie"
* @param peopleList
* @return true if a 25-year-old charlie is in the list
*/
public static int whereIsCharlie(List<People> peopleList) {
People charlie = new People("Charlie", 25);
int count = 0;
for (People p : peopleList) {
if (p == charlie) {
return count;
}
count++;
}
return -1; // Charlie is not here.
}
@Override
public String toString() {
return this.name;
}
}
package fr.univamu.progav.td2;
public class Ratio {
private final int num;
private final int denom;
private Ratio(int num, int denom) {
this.num = num;
this.denom = denom;
}
/** Builds a ratio, given its numerator and denominator
* @param num the numerator of the ratio
* @param denom the denominator of the ratio
* @return a reduced ratio equals to num/denom, represented in reduced form.
*/
public static Ratio of(int num, int denom) {
int d = gcd(denom, num);
return new Ratio(num / d, denom /d );
}
// UnsafeOf is used in test, to build a ratio without reducing it,
// and must be used with already reduced numerator and denominator.
protected static Ratio unsafeOf(int num, int denom) {
return new Ratio(num, denom);
}
// Euclid's algorithm
public static int gcd(int a, int b) {
return a == 0 || b == 0? a + b:
gcd(b, a % b);
}
public Ratio plus(Ratio r) {
return of(this.num * r.denom + this.denom * r.num, this.denom * r.denom);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Ratio r)) {
return false;
}
return r.num == this.num && r.denom == this.denom;
}
@Override
public String toString() {
double value = this.num / (double) this.denom;
return String.valueOf(value);
}
}
Introduction
============
Dans les exercices suivants, chaque petit programme comporte une
erreur, qui
apparait lors du test. L'objectif est d'apprendre à utiliser le débugger
pour Java d'IntelliJ pour trouver la cause de l'erreur, et la corriger.
La tâche Gradle permet de lancer les tests, mais on préfèrera cette fois
lancer uniquement le test de l'exercice en cours. Pour cela, ouvrir le
fichier contenant le test, trouver la méthode de test, et dans la marge
`clic gauche` sur l'icône de lancement ![run](../../../../../resources/run.png),
et choisir l'option *debug* ![debug](../../../../../resources/debug.png).
Pour arrêter le débugger à une instruction du programme, il faut placer des
*breakpoints* ![breakpoint](../../../../../resources/breakpoint.png). Il suffit
pour cela d'un `clic gauche` dans la marge du programme, sur le numéro de
ligne. Un `clic droit` permet de le paramétrer si nécessaire, et un deuxième
`clic gauche` le fait disparaître.
Lorsque le programme s'exécute, il s'interrompt automatiquement aux
breakpoints, et affiche l'état de la pile.
![Panneau de débuggage](../../../../../resources/debug-panel.png)
Dans la partie gauche se trouve la liste des *frames*, c'est-à-dire des
niveaux ou couches de la pile, la plus récente en haut. Attention, lancer un
test demande un grand nombre d'appels de méthode avant d'arriver à la
méthode de test, donc la plupart des *frames* ne sont pas pertinents, seuls
les frames les plus hauts, pour lesquels on reconnaît les méthodes du projet,
nous intéressent.
La partie droite affiche le contenu du frame courant, en commençant par la
valeur de `this` (si la méthode n'est pas statique), puis toutes les
variables et leurs valeurs. Les tableaux et les objets peuvent être
inspectés en dépliant les arborescences.
La barre du haut contient les actions réalisables, dont voici les plus
importantes.
![Relancer](../../../../../resources/rerun.png) relance le test depuis le
début, toujours en mode *debug*.
![Arrêter](../../../../../resources/stop.png) arrête l'évaluation du
programme immédiatement, et ferme le débuggeur.
![Reprendre](../../../../../resources/resume.png) reprend l'évaluation,
jusqu'au prochain *breakpoint* ou la fin normale de l'exécution du programme.
![Passer](../../../../../resources/step-over.png) passe à l'instruction
suivante, en ignorant tout appel de méthodes dans l'instruction en cours.
![Entrer](../../../../../resources/step-into.png) passe à la première
instruction d'une méthode appelée dans l'instruction en cours. En cas de
choix entre plusieurs méthodes (ou constructeurs), il faut cliquer sur celle
qui nous intéresse. Il est conseillé de ne pas entrer dans les méthodes ne
faisant pas partie du projet.
![Sortir](../../../../../resources/step-out.png) reprend l'exécution jusqu'à
terminer la méthode actuellement en cours, et s'interrompt à l'instruction
ayant appelé la méthode.
Ces actions permettent d'exécuter le programme pas-à-pas, plus ou moins
finement, en inspectant les valeurs des variables.
Exercice 1
==========
Dans la classe `People`, la méthode `whereIsCharlie` devrait retourner la
position de Charlie, 25 ans, dans la liste. Utiliser le test et le débuggeur
pour trouver l'erreur.
Exercice 2
==========
Dans la classe `ASimpleLoop`, la méthode `nonTerminatingSum` fait un calcul,
qui ne termine pas. Utiliser le test et le débuggeur, pour comprendre
pourquoi elle ne termine pas. Corriger ensuite la méthode pour que le calcul
s'arrête,
Exercice 3
==========
Dans la classe `Ratio`, représentant les nombres rationnels, l'addition ne
semble pas produire le bon résultat. Pourtant, nous avons pris soin de bien
réduire les fractions en calculant le plus grand commun diviseur avec
l'algorithme d'Euclide, et de forcer cette réduction dans la méthode
statique `of` que nous utilisons pour construire les fractions. Pour être
sûr de bien tester, nous avons aussi ajouter une méthode `unsafeOf`, qui
ignore l'étape de réduction : ainsi les valeurs attendues dans les tests
sont certainement bien définies (nous les avons réduites nous-mêmes). Enfin,
la méthode de test d'égalité profite de la forme réduite : il suffit de
tester l'égalité des numérateurs et des dénominateurs. Utiliser la méthode
de test et le débuggeur pour trouver l'erreur et la corriger.
Exercice 4
==========
La classe `GuessingGame` reprend la stratégie optimale pour le jeu
consistant à trouver un entier d'un intervalle (par exemple entre 1 et 1000),
en tentant des valeurs, et en obtenant pour chaque mauvaise réponse une
indication "plus petit" ou "plus grand". Bien sûr, il s'agit de faire une
recherche dichotomique. Ici, une erreur a été faite, et la dichotomie ne
termine pas toujours. Il va d'abord falloir trouver une valeur mystère pour
laquelle l'algorithme boucle infiniment (provoquant un dépassement de pile).
Ensuite, en utilisant le débuggeur et en partant avec cette valeur, il sera
possible de repérer la raison pour laquelle l'algorithme boucle ainsi.
Utiliser donc une fois de plus le débugger pour trouver et corriger l'erreur.
\ No newline at end of file
src/main/resources/breakpoint.png

556 B

src/main/resources/debug-panel.png

90.8 KiB

src/main/resources/debug.png

925 B

src/main/resources/mute-breakpoint.png

643 B

src/main/resources/rerun-auto.png

879 B

src/main/resources/rerun-failed.png

890 B

src/main/resources/rerun.png

958 B

src/main/resources/resume.png

649 B

src/main/resources/run.png

699 B

src/main/resources/step-into.png

469 B

src/main/resources/step-out.png

439 B

src/main/resources/step-over.png

546 B

src/main/resources/stop.png

421 B

src/main/resources/view-breakpoint.png

905 B

package fr.univamu.progav.td2;
import org.junit.jupiter.api.Test;
import static fr.univamu.progav.td2.ASimpleLoop.nonTerminatingSum;
import static org.junit.jupiter.api.Assertions.*;
class ASimpleLoopTest {
@Test
void nonTerminatingSumTest() {
double result = nonTerminatingSum(10);
assertEquals(505,result);
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment