Le « Plus / Moins » le plus horrible du siècle !

a marqué ce sujet comme résolu.

Reprise du dernier message de la page précédente

L'utilisation de setjmp et longjmp n'est pas recommandée pour la même raison que les goto, ils rendent les programmes difficiles à comprendre, de plus il est très facile de se retrouver avec des bugs vraiment pénibles à corriger.

Souksouk

Et encore, les goto sont utiles pour la gestion d'erreurs (en C bien sûr) et dans quelques très rares cas, alors que longjmp - setjmp n'ont pas vraiment d'intérêt en C, à la limite des coroutines / système d'exceptions mais bon…

Édité par superlama

+0 -0

Salut,

Un petit code en C (oui, encore un). Ce dernier utilise un appel récursif à la fonction main() et n'utilise que argc et argv comme variables. Les abus :

  • récursion avec la fonction main() (ce qui n'est pas interdit, mais pas franchement conseillé) ;
  • conversions entre pointeurs et entiers ;
  • utilisation des déclarations implicites de fonctions ;
  • utilisation d'une partie de l'adresse d'une variable comme argument de srand() ;
  • absence d'une valeur de retour pour la fonction main() ;
  • non vérifications en tout genre (et le programme foire si on lui fourni au moins un argument :p ).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int
main(int argc, char **argv)
{
    if (argv[1] == 0) {
        srand(*((unsigned char *)argv + 3));
        argv[1] = (char *)(rand() % 100);
    } else if (argc < (int)argv[1])
        printf("Plus grand !\n");
    else if (argc > (int)argv[1])
        printf("Plus petit !\n");
    else {
        printf("Bravo ! Vous avez trouvé le nombre mystère\n");
        exit(0);
    }

    printf("Entrez un nombre [0-99] : ");
    main((scanf("%d", &argc), argc), argv);
}

#JeSuisArius

+2 -0

Je l'ai fait en fortran. Comme le faire en fortran 77 (les goto, c'est normal) aurait été tricher, je l'ai fait en fortran 2003, avec des objets. :P

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
module m_PM
    type comparateur
        integer :: nombre
        logical :: plus
        logical :: moins
    contains
            procedure :: est_ce_plus => est_ce_plus_ou_non
            procedure :: est_ce_moins
    end type

contains
    subroutine est_ce_plus_ou_non(a, b)
        class(comparateur), intent(inout) :: a
        integer, intent(inout) :: b
        
        a%plus = (a%nombre > b)
    end subroutine
    subroutine est_ce_moins(a, b)
        class(comparateur), intent(inout) :: a
        integer, intent(inout) :: b
        
        a%moins = (a%nombre<b)
    end subroutine


    subroutine init_random_seed()
        use iso_fortran_env, only: int64
        implicit none
        integer, allocatable :: seed(:)
        integer :: i, n, un, istat, dt(8), pid
        integer(int64) :: t
        
        call random_seed(size = n)
        allocate(seed(n))
        call system_clock(t)
        call date_and_time(values=dt)
        t = (dt(1) - 1970) * 365_int64 * 24 * 60 * 60 * 1000 &
            + dt(2) * 31_int64 * 24 * 60 * 60 * 1000 &
            + dt(3) * 24_int64 * 60 * 60 * 1000 &
            + dt(5) * 60 * 60 * 1000 &
            + dt(6) * 60 * 1000 + dt(7) * 1000 &
            + dt(8)
        pid = getpid()
        t = ieor(t, int(pid, kind(t)))
        do i = 1, n
            seed(i) = lcg(t)
        end do
        call random_seed(put=seed)
        contains
        ! This simple PRNG might not be good enough for real work, but is
        ! sufficient for seeding a better PRNG.
        function lcg(s)
            integer :: lcg
            integer(int64) :: s
            if (s == 0) then
                s = 104729
            else
                s = mod(s, 4294967296_int64)
            end if
            s = mod(s * 279470273_int64, 4294967291_int64)
            lcg = int(mod(s, int(huge(0), int64)), kind(0))
        end function lcg
    end subroutine init_random_seed

end module

program p_PM
    use ISO_FORTRAN_ENV
    use m_PM

    integer :: entier
    type(comparateur) :: objet
    real :: flottant_aleatoire
    integer, dimension(1) :: temps

    call init_random_seed()
    call random_number(flottant_aleatoire)
    objet%nombre = int(flottant_aleatoire * 100)
    
    do while (.true.)
        write(OUTPUT_UNIT,'("Entrez un nombre entre 0 et 100")')
        read(INPUT_UNIT,*) entier
        call objet%est_ce_plus(entier)
        call objet%est_ce_moins(entier)
        if (objet%plus) then
            write(OUTPUT_UNIT, '("C est trop petit")')
        end if
        if (objet%moins) then
            write(OUTPUT_UNIT, '("C est trop grand")')
        end if
        if (.not. (objet%moins) .and. .not. (objet%plus)) then
            stop "C'est ça !"
        end if
    end do
end program

C'est laid pour pas mal de raison :

  • le module et le programme dans le même fichier (c'est comme faire du C sans .h, avec toute les fonctions dans le même fichier) ;
  • procedure :: est_ce_plus => est_ce_plus_ou_non signifie que la classe a une procédure (c'est presque comme une fonction) qui s'appelle est_ce_plus MAIS qui sera définie ensuite sous le nom est_ce_plus_ou_non. Ça peut être utile dans le cas des surcharge (avec des interfaces et compagnie), mais dans ce contexte, c'est totalement hors de propos (la classe entière d'ailleurs) ;
  • end type, ce serai mieux de faire end type comparateur. Mais ce n'est pas très grave ;
  • les noms de variable (a, b) des subroutine, classique mais efficace ^^ ;
  • integer, intent(inout) :: b signifie que b devra être lu, et pourra être modifié. Sauf qu'il ne sera pas modifié. Donc j'aurai dû mettre in ;
  • Le % est normal. C'est équivalent à a.plus de presque tout les autres langages ;
  • toute la subroutine init_random_seed est normal ! J'en suis le premier sidéré, mais c'est la procédure recommandée par le manuel de gfortran pour faire une initialisation qui change à chaque exécution. Je n'ai pas trouvé de solution plus courte. J'en reste o_O ;
  • dans le programme, pas de déclaration implicit none ;
  • l'aléatoire est fait n'importe comment (tirage d'un flottant transformé en entier plutôt que d'un entier directement) ;
  • do while (.true.) et une boucle infinie, une !
  • write(OUTPUT_UNIT,'("TEXTE")') est équivalent à write(*,*) "TEXTE". Sauf formatage manuelle, et donc cas très spéciaux, on ne fait pas ça. Et ça empêche les apostrophes de passer correctement. Joie ;
  • on vérifie si c'est trop grand et si c'est trop petit, en utilisant un objet pour ça, alors qu'un simple test aurai suffit ;
  • stop "C'est ça !" fait quitter le programme de manière brutale. C'est normalement utilisé en cas de plantage, pas comme fermeture normal.

Je voulais faire une ou deux allocations inutiles, mais ça fait trop longtemps que je n'ai pas fait de fortran.

Fortran reste mon grand copain pour gérer des tableaux efficacement et rapidement, mais j'avais oublié à quel point il est lourd pour le reste (même sans le faire exprès).

Édité par Gabbro

Il y a bien des façons de passer à l’acte. Se taire en est une. Attribué à Jean-Bertrand Pontalis

+0 -0

hello :)

c'est le code le plus dégueu que j'ai pu faire :P

en python bien sûr :D

le voici :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
global c
try:
    c=input ( "Max value ? > " )
    c=int ( c )
except Exception as blablu:
    print (blablu + " raise an error, man !")
r=[]
for _ in range ( c+1 ):
    r += [ _ ]
def rand ( r ):
    m=0
    l=len ( r )
    from time import *
    m=int ( strftime ( "%S" ) )*( l/59 )
    m=int ( m )
    return m
def dequoi ( n ):
    if 0<=n<=c:
        if n==c:
            return "Win !"
        if n<=c:
            return "Less, loser"
        if n>=c:
            return "More, loser"
    return
def mahaha ( ):
    t=rand ( r )
    while 1 :
        try:
            a=input ( "Nombre ? > " )
            a=int ( a )
            s=dequoi ( a )
            print ( s )
            if s=="Win !":
                break
        except Exception as jiku:
            print ("err... a wild error appear !")
    from os import *
    system ( "pause" )

les problèmes :
ligne 1 : utilisations inutile de global :P
ligne 3 : aucun respect des PEP (il faudrait faire c = input("nombre") )
ligne 5 : on catch toutes les erreurs, meme les CTRL+C, donc c'est pas bien, il faudrait juste catcher les ValueError, et encore, on devrait meme faire un while avec isalpha(c) pour savoir si on doit continuer ou non a demander un nombre
ligne 6 : le texte en plus, "raise an error, man !" est inutile
lignes 8 et 9 : on pourrait générer la liste comme ceci : [i for i in range(c+1)]
lignes 10 à 16, pourquoi recoder random ? c'est inutile voyons !
lignes 11 et 12 : les noms de variables sont pas clairs
ligne 13 : les import * sont à bannir, ca encombre la memoire pour rien
lignes 14 et 15 : pas de gestion des erreurs si on rate le cast en int ?
ligne 14, code *( 1/59 ) : ca veut dire quoi ? ca vient d'où ?
ligne 17 : hein ? mais qu'est ce que c'est que ce nom de fonction ?
ligne 18 (et tous les autres if d'ailleurs) : ca ne respect toujours pas les conventions !
lignes 18, 19, 21 et 23 : c'est quoi c ? j'ai pas envie de me retaper tout le code, faut mettre un nom explicite
ligne 26 : encore un nom bizarre …
ligne 28 : c'est personnel, mais j'aime pas les while True / while 1, je préfère les while continuer :)
ligne 29 : ca se gate ! tout le code est dans un try ! horreur !
lignes 30, 31 et 32 : des noms bizarres …
ligne 36 : tu catch une exception en as jiku (drole de nom) mais tu t'en sert pas ? Nan mais allo quoi, tu codes en python et tu sais pas coder ? #troll
ligne 37 : le message d'erreur est inutile …
ligne 38 : encore un import * inutile
ligne 39 : ne jamais faire de system("pause"), mais input() !

voilà, c'était ma participation :D

Python is good | CV | Unamed (C++14/SFML2.5)

+0 -0

ligne 13 : les import * sont à bannir, ca encombre la memoire pour rien

Folaefolc

Ça encombre la mémoire ?

ligne 39 : ne jamais faire de system("pause"), mais input() !

Folaefolc

On ne fait pas input non plus. On laisse le programme se terminer :)

entwanne

je veux dire que ca charge inutilement des modules qui ne seront pas utilisés :) autant faire un from os import system

mais ca peut aussi faire des collisions ! image que dans une lib x tu as une fonction system, et dans os, et ben tu as aussi cette fonction. et si tu fais from os import * puis from lib_x import *, la fonction system du module os serait écrasée !

encore mieux pour input :D

Python is good | CV | Unamed (C++14/SFML2.5)

+0 -0

Je suis fan du :

1
2
for _ in range ( c+1 ):
    r += [ _ ]

Je me suis arrêter devant ça pendant 30 secondes, en me demandant ce que ça faisait, si c'était une syntaxe que je ne connaissait pas ou autre chose.

Bah non, c'est juste l'un des pires noms de variables possibles. Mais _, sérieusement ?

Il y a bien des façons de passer à l’acte. Se taire en est une. Attribué à Jean-Bertrand Pontalis

+1 -0

ben oui xD le _ est généralement utilisé pour les variables anonymes

exemple : [0 for _ in range(562556652656549865656)]

sauf que là j'ai voulu faire un truc tres crade comme j'en vois un peu (beaucoup) sur OC :)

Python is good | CV | Unamed (C++14/SFML2.5)

+0 -0

Oui on utilise les _ en Python pour une variable (retour de fonction généralement) qu'on ne va pas utiliser.

Par contre pour les from bidule import *, su c'est déconseillé ça n'a rien à voir avec la mémoire. Dans tous les cas le module est importé et chargé totalement.

Si c'est déconseillé c'est que ça importe plein de chose dans l'espace de nom global que tu peux écraser par inadvertance ou écraser des trucs built-in sans que tu le sache.

C'est uniquement pour ces questions de pollution de l'espace de nom qu'on le déconseille, ça n'a rien à voir avec la mémoire.

+6 -0

ah ok

j'ai dis ca parce que dans urworld, je ne charge que 50 mo de ressources, maxi 70 quand j'ai chargé toutes les musiques au fur et a mesure, je consomme 130 Mo de ram

et ben je viens de faire un test, et je suis navré de dire qu'on a tous tord et raison :D

car sa charge pas mal de trucs en mémoire, mais ca pese rien (ou presque)

regardez donc ceci :

Image utilisateur

un shell python sans module, un autre avec

Édité par SuperFola

Python is good | CV | Unamed (C++14/SFML2.5)

+0 -0

Non mais ça c'est parfaitement normal. Ce que je voulais dire et que Kje a ensuite expliqué, c'est que un from toto import x ne consomme pas moins de mémoire qu'un from toto import *. Les objets sont chargés dans tous les cas.

Le cas du import toto est encore différent, je crois, car l'évaluation du contenu du module a lieu plus tard. Edit: je me suis un peu emmêlé les pinceaux avec le import simple, le module est évalué tout de suite, la différence se ressent juste lors d'imports circulaires (si on essaie d'importer des fonctions depuis un module en cours d'import).

Édité par entwanne

lignes 8 et 9 : on pourrait générer la liste comme ceci : [i for i in range(c+1)]

Si tu veux vraiment faire une liste, list(range(c+1)) est encore plus simple. Mais ici, c'est même inutile, prendre directement le range est encore plus simple et bouffe moins de mémoire (même si dans le cas présent avec un c relativement petit c'est risible ^^ ). Au lieu d'avoir une bête liste, tu as un objet range mathématiquement complètement définit (et en plus stocké en mémoire et manipulé) par trois nombres : les deux bornes et le pas. Si c est de l'ordre de 10000, ça fait déjà un facteur 3000 en terme de mémoire par rapport à une liste. :p

La mémoire est même pas le seul ni le meilleur argument en faveur de range. Si tu as besoin de faire des manip' du genre number in range(a,b,c), un seul test est effectué et coutera la même chose quelque soient les valeurs des bornes. Si tu t'amuse à faire une liste et que $\dfrac{b-a}{c}$ est très grand, le moindre in va prendre une plombe.

De manière générale, utiliser une liste en python devrait être relativement rare et réservé aux cas où on en a vraiment besoin. Dans la plupart des cas, ce qu'on veut, c'est juste un itérable, peu importe la structure de données derrière.

Édité par adri1

I don’t mind that you think slowly, but I do mind that you are publishing faster. — W. Pauli

+6 -0

En me repanchant un peu sur ma participation, voici la même, mais sans un appel à srand() et rand() (j'utilise l'adresse de la variable argc à la place) et avec une utilisation abusive de l'opérateur ternaire (edit: et de l'opérateur ,) et de la récursion de sorte que le corps de la fonction main() ne comporte en fait q'une seule grosse expression-instruction de type void.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int
main(int argc, char **argv)
{
    (argv[1] == 0)
        ? argv[1] = (char *)((unsigned)&argc % 100), (void)main(-1, argv)
        : (argc == -1)
            ? printf("Entrez un nombre [0-99] : "), scanf("%u", &argc), (void)main(argc, argv)
            : (argc == (int)argv[1])
                ? printf("Bravo ! Vous avez trouvé le nombre mystère\n"), exit(0)
                : (argc < (int)argv[1])
                    ? printf("Plus grand !\n"), (void)main(-1, argv)
                    : printf("Plus petit !\n"), (void)main(-1, argv);
}

Édité par Taurre

#JeSuisArius

+2 -0

C'ets vrai que c'est moche, mais je pense que c'est que c'est illégal d'appeler main depuis le programme.

Davidbrcz

À ma connaissance, c'est parfaitement « légal » dans le sens où la norme ne l'interdit pas et où il ne s'agit pas d'un comportement indéfini. D'ailleurs, il n'y a pas de raison spécifique pour que cela soit interdit, puisqu'il s'agit finalement d'une fonction comme les autres, mise à part qu'elle est le point d'entrée du programme. Après, ce n'est clairement pas considéré comme une bonne pratique. :-°

#JeSuisArius

+2 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte