t
t
t
t
t t 3) Contrôle du flux du programme
tttt
3) Contrôle du flux du programme
Texte original t Traducteur : Jean-Pierre VIDAL
t
t
///
Ce chapitre contient 6 pages
1 2 3 4 5 6
    
t t t
t t t
t
t t t
Integral-selector is an expression that produces an integral value. The switch compares the result of integral-selector to each integral-value. IF it finds a match, the corresponding statement (simple or compound) executes. If no match occurs, the default statement executes. t sélecteur-entier est une expression qui produit une valeur entière. switch compare le résultat de sélecteur-entier avec chaque valeur-entière. S'il trouve une égalité, l'instruction correspondante (simple ou composée) est exécutée. Si aucune égalité n'est trouvée, l'instruction qui suit default est exécutée.
t t t
You will notice in the above definition that each case ends with a break, which causes execution to jump to the end of the switch body. This is the conventional way to build a switch statement, but the break is optional. If it is missing, the code for the following case statements execute until a break is encountered. Although you don’t usually want this kind of behavior, it can be useful to an experienced programmer. Note the last statement, following the default, doesn’t have a break because the execution just falls through to where the break would have taken it anyway. You could put a break at the end of the default statement with no harm if you considered it important for style’s sake. t Notons dans la définition précédente que chaque instruction case se termine par une instruction break, qui provoque un saut à la fin du corps de l'instruction switch. Ceci est la manière habituelle de construire une instruction switch. Cependant break est optionnel. S'il n'est pas là, le code associé à l'instruction case suivante est exécuté, et ainsi de suite jusqu'à la rencontre d'une instruction break. Bien qu'on n'ait généralement pas besoin d'utiliser cette possibilité, elle peut se montrer très utile pour un programmeur expérimenté. La dernière instruction, qui suit default, n'a pas besoin de break car en fait l'exécution continue juste à l'endroit où une instruction break l'aurait amenée de toute façon. Il n'y a cependant aucun problème à terminer l'instruction default par une instruction break si on pense que le style de programmation est une question importante.
t t t
The switch statement is a clean way to implement multi-way selection (i.e., selecting from among a number of different execution paths), but it requires a selector that evaluates to an integral value such as int or char. If you want to use, for example, a string or a floating-point number as a selector, it won’t work in a switch statement. For non-integral types, you must use a series of if statements. t L'instruction switch est une manière propre d'implémenter une sélection multiple (c'est à dire sélectionner un certain nombre de possibilités d'exécution), mais elle requiert une expression de sélection dont le résultat soit entier, comme int ou char. Par exemple on ne peut pas utiliser une chaîne de caractères ou un flottant comme sélecteur dans une instruction switch. Pour les types non entiers, il faut mettre en oeuvre une série d'instructions if.
t t t
Here’s an example that creates letters randomly and determines whether they’re vowels or consonants: t Voici un exemple qui crée des lettres aléatoirement, et détermine s'il s'agit d'une voyelle ou d'une consonne :
t t t
//: c03:VowelsAndConsonants.java
// Demonstrates the switch statement.

public class VowelsAndConsonants {
  public static void main(String[] args) {
    for(int i = 0; i < 100; i++) {
      char c = (char)(Math.random() * 26 + 'a');
      System.out.print(c + ": ");
      switch(c) {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
                System.out.println("vowel");
                break;
      case 'y':
      case 'w':
                System.out.println(
                  "Sometimes a vowel");
                break;
      default:
                System.out.println("consonant");
      }
    }
  }
} ///:~
t
//: c03:VowelsAndConsonants.java
// Démonstration de l'instruction switch.

public class VowelsAndConsonants {
  public static void main(String[] args) {
    for(int i = 0; i < 100; i++) {
      char c = (char)(Math.random() * 26 + 'a');
      System.out.print(c + ": ");
      switch(c) {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
                System.out.println("vowel");
                break;
      case 'y':
      case 'w':
                System.out.println(
                  "Sometimes a vowel");
                break;
      default:
                System.out.println("consonant");
      }
    }
  }
} ///:~
t t t
Since Math.random( ) generates a value between 0 and 1, you need only multiply it by the upper bound of the range of numbers you want to produce (26 for the letters in the alphabet) and add an offset to establish the lower bound. t Math.random( ) générant une valeur entre 0 et 1, il faut la multiplier par la borne supérieure de l'intervalle des nombres qu'on veut produire (26 pour les lettres de l'alphabet) puis ajouter un décalage correspondant à la borne inférieure.
t t t
Although it appears you’re switching on a character here, the switch statement is actually using the integral value of the character. The singly-quoted characters in the case statements also produce integral values that are used for comparison. t Bien qu'il semble que la sélection s'opère ici sur un type caractère, l'instruction switch utilise en réalité la valeur entière du caractère. Les caractères entre guillemets simples des instructions case sont également interprétés comme des entiers avant la comparaison.
t t t
Notice how the cases can be “stacked” on top of each other to provide multiple matches for a particular piece of code. You should also be aware that it’s essential to put the break statement at the end of a particular case, otherwise control will simply drop through and continue processing on the next case. t Remarquez la manière d'empiler les instructions case pour affecter un même code d'exécution à plusieurs cas d'égalité. Il faut également faire attention à terminer chaque instruction par une instruction break, faute de quoi le contrôle serait transféré à l'instruction correspondant au case suivant.
t t t

Calculation details

t

Détails de calcul :

t t t
The statement: t L'instruction :
t t t
char c = (char)(Math.random() * 26 + 'a');
t
char c = (char)(Math.random() * 26 + 'a');
t t t
deserves a closer look.
Math.random( ) produces a double, so the value 26 is
converted to a double to perform the multiplication, which also produces
a double. This means that ‘a’ must be converted to a
double to perform the addition. The double result is turned back
into a char with a cast.
t mérite une attention particulière. Math.random( ) a pour résultat un double, par suite la valeur 26 est convertie en double avant que la multiplication ne soit effectuée ; cette dernière a aussi pour résultat un double. Ce qui signifie que 'a' doit lui aussi être converti en double avant d'exécuter l'addition. Le résultat double est finalement transtypé en char.
t t t
What does the cast to char do?
That is, if you have the value 29.7 and you cast it to a char, is the
resulting value 30 or 29? The answer to this can be seen in this
example:

t Que fait exactement ce transtypage ? En d'autres termes, si on obtient une valeur de 29.7 et qu'on la transtype en char, le résultat est-il 30 ou 29 ? La réponse est dans l'exemple suivant :
t t t
//: c03:CastingNumbers.java
// What happens when you cast a float
// or double to an integral value?

public class CastingNumbers {
  public static void main(String[] args) {
    double
      above = 0.7,
      below = 0.4;
    System.out.println("above: " + above);
    System.out.println("below: " + below);
    System.out.println(
      "(int)above: " + (int)above);
    System.out.println(
      "(int)below: " + (int)below);
    System.out.println(
      "(char)('a' + above): " +
      (char)('a' + above));
    System.out.println(
      "(char)('a' + below): " +
      (char)('a' + below));
  }
} ///:~
t
//: c03:CastingNumbers.java
// Qu'arrive-t-il lorsqu'on transtype un flottant
// ou un double vers une valeur entière ?

public class CastingNumbers {
  public static void main(String[] args) {
    double
      above = 0.7,
      below = 0.4;
    System.out.println("above: " + above);
    System.out.println("below: " + below);
    System.out.println(
      "(int)above: " + (int)above);
    System.out.println(
      "(int)below: " + (int)below);
    System.out.println(
      "(char)('a' + above): " +
      (char)('a' + above));
    System.out.println(
      "(char)('a' + below): " +
      (char)('a' + below));
  }
} ///:~
t t t
The output is: t Le résultat :
t t t
above: 0.7
below: 0.4
(int)above: 0
(int)below: 0
(char)('a' + above): a
(char)('a' + below): a
t
above: 0.7
below: 0.4
(int)above: 0
(int)below: 0
(char)('a' + above): a
(char)('a' + below): a
t t t
So the answer is that casting from a float or double to an integral value always truncates. t La réponse est donc : le transtypage d'un type float ou double vers une valeur entière entraîne une troncature dans tous les cas.
t t t
A second question concerns Math.random( ). Does it produce a value from zero to one, inclusive or exclusive of the value ‘1’? In math lingo, is it (0,1), or [0,1], or (0,1] or [0,1)? (The square bracket means “includes” whereas the parenthesis means “doesn’t include.”) Again, a test program might provide the answer: t Une seconde question à propos de Math.random( ) : cette méthode produit des nombres entre zéro et un, mais : les valeurs 0 et 1 sont-elles inclues ou exclues ? En jargon mathématique, obtient-on ]0,1[, [0,1], ]0,1] ou [0,1[ ? (les crochets « tournés vers le nombre » signifient « ce nombre est inclus », et ceux tournés vers l'extérieur « ce nombre est exclu »). À nouveau, un programme de test devrait nous donner la réponse :
t t t
//: c03:RandomBounds.java
// Does Math.random() produce 0.0 and 1.0?

public class RandomBounds {
  static void usage() {
    System.out.println("Usage: \n\t" +
      "RandomBounds lower\n\t" +
      "RandomBounds upper");
    System.exit(1);
  }
  public static void main(String[] args) {
    if(args.length != 1) usage();
    if(args[0].equals("lower")) {
      while(Math.random() != 0.0)
        ; // Keep trying
      System.out.println("Produced 0.0!");
    }
    else if(args[0].equals("upper")) {
      while(Math.random() != 1.0)
        ; // Keep trying
      System.out.println("Produced 1.0!");
    }
    else
      usage();
  }
} ///:~
t
//: c03:RandomBounds.java
// Math.random() produit-il les valeurs 0.0 et 1.0 ?

public class RandomBounds {
  static void usage() {
    System.out.println("Usage: \n\t" +
      "RandomBounds lower\n\t" +
      "RandomBounds upper");
    System.exit(1);
  }
  public static void main(String[] args) {
    if(args.length != 1) usage();
    if(args[0].equals("lower")) {
      while(Math.random() != 0.0)
        ; // Essayer encore
      System.out.println("Produced 0.0!");
    }
    else if(args[0].equals("upper")) {
      while(Math.random() != 1.0)
        ; // Essayer encore
      System.out.println("Produced 1.0!");
    }
    else
      usage();
  }
} ///:~
t t t
To run the program, you type a command line of either: t Pour lancer le programme, frapper en ligne de commande :
t t t
java RandomBounds lower
t
java RandomBounds lower
t t t
or

t ou bien :
t t t
java RandomBounds upper
t
java RandomBounds upper
t t t
In both cases you are forced to break out
of the program manually, so it would appear that
Math.random( ) never produces either 0.0 or 1.0. But this is where
such an experiment can be deceiving. If you
consider[26] that
there are about 262 different double fractions between 0 and 1, the
likelihood of reaching any one value experimentally might exceed the lifetime of
one computer, or even one experimenter. It turns out that 0.0 is included
in the output of Math.random( ). Or, in math lingo, it is
[0,1).
t Dans les deux cas nous sommes obligés d'arrêter le programme manuellement, et il semble donc que Math.random( ) ne produise jamais les valeurs 0.0 ou 1.0. Une telle expérience est décevante. Si vous remarquez [26] qu'il existe environ 262 fractions différentes en double-précision entre 0 et 1, alors la probabilité d'atteindre expérimentalement l'une ou l'autre des valeurs pourrait dépasser la vie d'un ordinateur, voire celle de l'expérimentateur. Cela ne permet pas de montrer que 0.0 est inclus dans les résultats de Math.random( ). En réalité, en jargon mathématique, le résultat est [0,1[.
t t t


Summary


t

Résumé

t t t
This chapter concludes the study of
fundamental features that appear in most programming languages: calculation,
operator precedence, type casting, and selection and iteration. Now you’re
ready to begin taking steps that move you closer to the world of object-oriented
programming. The next chapter will cover the important issues of initialization
and cleanup of objects, followed in the subsequent chapter by the essential
concept of implementation
hiding.
t Ce chapitre termine l'étude des fonctionnalités fondamentales qu'on retrouve dans la plupart des langages de programmation : calcul, priorité des opérateurs, transtypage, sélection et itération. Vous êtes désormais prêts à aborder le monde de la programmation orientée objet. Le prochain chapitre traite de la question importante de l'initialisation et du nettoyage des objets, et le suivant du concept essentiel consistant à cacher l'implémentation.
t t t


Exercises


t

Exercices

t t t
Solutions to selected exercises
can be found in the electronic document The Thinking in Java Annotated
Solution Guide
, available for a small fee from
www.BruceEckel.com.
t Les solutions des exercices sélectionnés sont dans le document électronique The Thinking in Java Annotated Solution Guide, disponible pour un faible coût à www.BruceEckel.com.
t t t
  1. There are two expressions
    in the section labeled “precedence” early in this chapter. Put these
    expressions into a program and demonstrate that they produce different
    results.
  2. Put the
    methods ternary( ) and alternative( ) into a working
    program.
  3. From the
    sections labeled “if-else” and “return”, put the methods
    test( ) and test2( ) into a working
    program.
  4. Write a
    program that prints values from one to
    100.
  5. Modify Exercise
    4 so that the program exits by using the break keyword at value 47. Try using
    return
    instead.
  6. Write a
    function that takes two String arguments, and uses all the Boolean comparisons
    to compare the two Strings and print the results. For the == and !=, also
    perform the equals( ) test. In main( ), call your function with some
    different String
    objects.
  7. Write a
    program that generates 25 random int values. For each value, use an if-then-else
    statement to classify it as greater than, less than or equal to a second
    randomly-generated
    value.
  8. Modify
    Exercise 7 so that your code is surrounded by an “infinite” while
    loop. It will then run until you interrupt it from the keyboard (typically by
    pressing
    Control-C).
  9. Write a
    program that uses two nested for loops and the modulus operator (%) to detect
    and print prime numbers (integral numbers that are not evenly divisible by any
    other numbers except for themselves and
    1).
  10. Create a switch
    statement that prints a message for each case, and put the switch inside a for
    loop that tries each case. Put a break after each case and test it, then remove
    the breaks and see what happens.

t
  1. Dans la section « priorité » au début de ce chapitre, il y a deux expressions. Utiliser ces expressions dans un programme qui montre qu'elles produisent des résultats différents.
  2. Utiliser les méthodes ternary( ) et alternative( ) dans un programme qui fonctionne.
  3. À partir des sections « if-else » et « return », utiliser les méthodes test( ) et test2( ) dans un programme qui fonctionne.
  4. Écrire un programme qui imprime les valeurs de un à 100.
  5. Modifier l'exercice 4 de manière que le programme termine avec la valeur 47, en utilisant le mot clef break. Même exercice en utilisant return.
  6. Écrire une fonction prenant pour arguments deux String, utiliser les comparaisons booléennes pour comparer les deux chaînes et imprimer le résultat. En plus de == et !=, tester aussi equals( ). Dans la méthode main( ), appeler la fonction avec différents objets de type String.
  7. Écrire un programme qui génère aléatoirement 25 valeurs entières. Pour chaque valeur, utiliser une instruction if-then-else pour la classer (plus grande, plus petite, ou égale) par rapport à une deuxième valeur générée aléatoirement.
  8. Modifier l'exercice 7 en englobant le code dans une boucle while infinie. Il devrait alors fonctionner tant qu'on ne l'interrompt pas au moyen du clavier (classiquement avec Ctrl-C).
  9. Écrire un programme utilisant deux boucles for imbriquées ainsi que l'opérateur modulo (%) pour détecter et imprimer les nombres premiers (les nombres entiers qui ne sont divisibles que par eux-mêmes et l'unité).
  10. Écrire une instruction switch qui imprime un message pour chaque case, la mettre dans une boucle for qui teste chaque case. Mettre un break après chaque case, tester, puis enlever les break et voir ce qui se passe..
t t t
[25]
John Kirkham writes, “I started computing in 1962 using FORTRAN II on an
IBM 1620. At that time, and throughout the 1960s and into the 1970s, FORTRAN was
an all uppercase language. This probably started because many of the early input
devices were old teletype units that used 5 bit Baudot code, which had no
lowercase capability. The ‘E’ in the exponential notation was also
always upper case and was never confused with the natural logarithm base
‘e’, which is always lowercase. The ‘E’ simply stood for
exponential, which was for the base of the number system used—usually 10.
At the time octal was also widely used by programmers. Although I never saw it
used, if I had seen an octal number in exponential notation I would have
considered it to be base 8. The first time I remember seeing an exponential
using a lowercase ‘e’ was in the late 1970s and I also found it
confusing. The problem arose as lowercase crept into FORTRAN, not at its
beginning. We actually had functions to use if you really wanted to use the
natural logarithm base, but they were all uppercase.”
t [25] John Kirkham écrivait, « J'ai fait mes débuts en informatique en 1962 avec FORTRAN II sur un IBM 1620. À cette époque, pendant les années 60 et jusqu'au début des années 70, FORTRAN était un langage entièrement écrit en majuscules. Sans doute parce que beaucoup de périphériques d'entrée anciens étaient de vieux téléscripteurs utilisant le code Baudot à cinq moments (à cinq bits), sans possibilité de minuscules. La lettre 'E' dans la notation scientifique était en majuscule et ne pouvait jamais être confondue avec la base 'e' des logarithmes naturels, toujours écrite en minuscule. 'E' signifiait simplement puissance, et, naturellement, puissance de la base de numération habituellement utilisée c'est à dire puissance de 10. À cette époque également, l'octal était largement utilisé par les programmeurs. Bien que je ne l'aie jamais vu utiliser, si j'avais vu un nombre octal en notation scientifique j'aurais pensé qu'il était en base 8. Mon plus ancien souvenir d'une notation scientifique utilisant un 'e' minuscule remonte à la fin des années 70 et je trouvais immédiatement cela déroutant. Le problème apparut lorsqu'on introduisit les minuscules en FORTRAN, et non à ses débuts. En réalité il existait des fonctions qui manipulaient la base des logarithmes naturels, et elles étaient toutes en majuscules. »
t t t
[26]
Chuck Allison writes: The total number of numbers in a floating-point number
system is2(M-m+1)b^(p-1) +
1
where b is the base (usually
2), p is the precision (digits in the mantissa), M is the largest
exponent, and m is the smallest exponent. IEEE 754
uses:M = 1023, m = -1022, p = 53, b =
2
so the total number of numbers
is2(1023+1022+1)2^52
=
2((2^10-1) + (2^10-1))2^52
=
(2^10-1)2^54
= 2^64 -
2^54
Half of these numbers
(corresponding to exponents in the range [-1022, 0]) are less than 1 in
magnitude (both positive and negative), so 1/4 of that expression, or 2^62 -
2^52  + 1 (approximately 2^62)  is in the range [0,1). See my paper at
http://www.freshsources.com/1995006a.htm (last of text).

t [26] Chuck Allison écrivait : Le nombre total de nombres dans un système à virgule flottante est 2(M-m+1)b^(p-1) + 1b est la base (généralement 2), p la précision (le nombre de chiffres dans la mantisse), M le plus grand exposant, et m le plus petit. Dans la norme IEEE 754, on a : M = 1023, m = -1022, p = 53, b = 2 d'où le nombre total de nombres est 2(1023+1022+1)2^52 = 2((2^10-1) + (2^10-1))2^52 = (2^10-1)2^54 = 2^64 - 2^54 La moitié de ces nombres (correspondant à un exposant dans l'intervalle[-1022, 0]) sont inférieurs à un en valeur absolue, et donc 1/4 de cette expression, soit 2^62 - 2^52 + 1 (approximativement 2^62) est dans l'intervalle [0,1[. Voir mon article à http://www.freshsources.com/1995006a.htm (suite de l'article).
t t t
t t t
t t
\\\
    
t t t
t
     
Sommaire Le site de Bruce Eckel