Ceci est une ancienne révision du document !
[Tyrtamos déc 2007 version 1.30]
cette version 1.30 doit être préférée à l'ancienne version 1.22!
NB: Passage de la version 1.22 à 1.30 (complément dans le fichier lisezmoi.txt de l'archive v 1.30 à télécharger):
Création d'une Calculext en ligne, accessible sans installation par un simple navigateur web (http://calculext.jpvweb.com). Son code n'est pas diffusé pour des raisons de sécurité, mais elle fait pratiquement tout ce que fait la calculext installée sur PC, et elle utilise tous ses modules sans modification. Ses limites sont mentionnées dans son fichier d'aide.
S'il y a bien quelque chose d'énervant, c'est d'avoir un ordinateur puissant devant soi, et d'être obligé de sortir une calculatrice de poche pour faire des petits calculs.
Oui, je sais que tous les systèmes d'exploitation ont des calculatrices de poche simulées, mais pourquoi cliquer plein de boutons alors qu'on a devant soit un clavier de 104 touches?
Et puis devant une calculatrice de poche, réelle ou simulée, il y a toujours une limite de précision et des fonctions qui manquent qu'on ne peut pas ajouter.
Et j'aimerais bien avoir la même calculatrice sous Windows et sous Linux!
Voilà, mon objectif correspond bien à ces problèmes:
Mais si, c'est possible!
La calculette, a cet aspect:
Sous Windows XP:
Et sous Linux:
L'utilisation est très simple:
Quand on a fait plusieurs calculs, on peut afficher sur la 1ère ligne de saisie (ce qui permet de ne pas les retaper):
Le calcul s'exécute en tâche de fond, ce qui a les avantages suivants:
Pour les nombres réels (dits “à virgule flottante”), les calculs sont faits avec la “double précision” de la bibliothèque “C”, c'est à dire 16 ou 17 chiffres significatifs. L'affichage est cependant réduit à 15 chiffres significatifs, pour éviter des résultats irritants comme 0.1 ⇒ 0.10000000000000001. Vous noterez qu'une erreur portant sur le 17ème chiffre après la virgule n'a aucune importance pratique. Et en fait, ce n'est pas une erreur de calcul, c'est un écart qui dépend de la façon dont les nombres réels sont stockés en mémoire dans l'ordinateur, et cet écart n'est pas spécifique à python qui utilise la bibliothèque C.
A noter que cette présentation limitées à 15 chiffres ne concerne que l'affichage: les calculs sont toujours faits avec la pleine précision.
On peut changer le mode d'affichage des nombres réels avec la fonction precision(n=-15) en modifiant la valeur de n (-15<=n<=+15):
Cet affichage fonctionne aussi:
On peut obtenir le même effet ponctuellement, c'est à dire sans changer le mode courant d'affichage, avec la fonction arrond(x,n). Par exemple, arrond(0.1,4) ⇒ “0.1000” ne change pas “nbchiffres” qui peut rester à -15.
La séquence de touches Ctle-R (“R” pour Résultat) sauvegarde le dernier résultat calculé sur disque, à la fin du fichier resultat.txt. Pour que l'action soit exécutée, il faut que le focus (=le curseur) soit sur l'une des 2 lignes (saisie ou résultat).
La séquence de touches Ctle-E (“E” pour Expressions) sauvegarde la liste de toutes les expressions calculées depuis le lancement de l'exécution de la calculatrice, complétée par le dernier résultat calculé. Cette liste est ajoutée au fichier resultat.txt. Pour que l'action soit exécutée, il faut que le focus (=le curseur) soit sur l'une des 2 lignes (saisie ou résultat).
Attention 1: pour l'introduction et l'affichage des nombres décimaux, la virgule est toujours remplacée par un point décimal: c'est 2.5 et pas 2,5!
Attention 2: la calculette a été configurée pour qu'une division entre 2 nombres entiers donne un résultat décimal et pas un entier tronqué. Par exemple, “10/3” donnent bien “3.33333333333” et pas “3”. C'est une configuration inhabituelle pour python, mais habituelle pour une calculatrice!. La division entière est toujours possible avec "//": l'expression "10//3" donne bien “3”.
Le fait que les calculs en entier et en décimal soit différents a un gros avantage: en calcul “entier”, le nombre de chiffres n'a pas d'autre limite que la mémoire!.
Prenons un exemple:
2.0**200 => 1.60693804425899e+060
2**200 => 1606938044258990275541962092341162602522202993782792835301376
Intéressant, non?
Le bouton “effacer” de même que la touche “esc” efface les 3 lignes (saisie, résultat et durée) et met le focus sur la zone de saisie.
Le bouton “aide” ou la touche F1 fait apparaitre la notice sous forme d'une page html dans le navigateur web par défaut. Si vous ajoutez des fonctions à votre calculette, je vous suggère de mettre à jour ce manuel.
Nouveauté de la version 1.2, vous pouvez demander l'aide sur une fonction donnée en tapant directement dans la zone de saisie, par exemple:
aide(bissextile)
ce qui affichera après exécution dans la zone des résultats:
"bissextile(a): dit si l'année donnée est bissextile ou non (True=oui, False=non)"
Pour arrêter la calculatrice, il suffit de “tuer la fenêtre”: cliquez sur la croix dans la case rouge en haut et à droite de la fenêtre, ou avec le menu en haut à gauche (Fermer) ou la touche “Alt-F4”.
Les fonctions intégrées dans la calculette de base sont déjà très nombreuses, car ce sont toutes celles de python et des modules python importés.
fonctions et opérateurs de base
12+65-987+(78/6)**2 => -741.0 10 % 3 => 1 (fonction modulo = reste de la division entière de 10 par 3)
(2==2) and (5>4) => True (2<>2) and (5>4) => False
2 << 1 => 4
hex(12345) => "0x3039" 0x3039 => 12345 oct(12345) => "030071" 030071 => 12345
sin(0.25698)*1/sqrt(2*pi)*log(1.25698)**(1.6987) => 0.00827261825741359
Vous voulez calculer cette fonction avec d'autres valeurs que 0.25698 (qui intervient à 2 endroits) et 1.6987. Vous faites:
sto("toto",lambda x,y: sin(x)*1/sqrt(2*pi)*log(1.25698)**(y))
A la place de “toto”, vous pouvez utiliser un nom de variable plus explicite
Désormais, quand vous faites:
toto(0.25698,1.6987) => 0.00827261825741359
Vous obtenez bien la même valeur que précédemment. Mais bien sûr, vous pouvez recalculer avec toutes les valeurs que vous voulez, pour autant que le calcul soit possible:
toto(0.65423,1.7298) => 0.0189192228012913 toto(1.9875,1.0749) => 0.0747066661174212 toto(2.86278,0.0749) => 0.0983086841243615 etc...
Dans le contexte de la calculette, vous pouvez utiliser un ou plusieurs paramètres avec “lambda”, mais vous n'avez droit qu'à une seule expression après le “:”.
Exemple avec la fonction sinus, qui va donc calculer sin(0.1), puis sin(0.2), etc…:
map(sin,[0.1, 0.2, 0.3, 0.4, 0.5]) => [0.0998334166468282,0.198669330795061,0.29552020666134,0.389418342308651,0.479425538604203]
Autre exemple: on créé une fonction lambda quelconque avec un paramètre:
sto("double",lambda x: 2*x)
Et on applique cette fonction à toutes les valeurs suivantes: [1,2,3,4,5,6], ce qui donne:
map(double,[1,2,3,4,5,6]) => [2, 4, 6, 8, 10, 12]
Et vous pouvez même faire ça en une seule fois:
map(lambda x:2*x,[1,2,3,4,5,6]) => [2, 4, 6, 8, 10, 12]
Dernier point, la fonction lambda permet de passer plusieurs paramètres, mais cette fois-ci sous forme de liste:
sto("y", lambda L: L[0]*L[1])
Pour calculer avec une telle fonction:
y([3,5]) => 15
Et avec la fonction map:
map(y,[[3,5],[4,6],[7,9]]) => [15, 24, 63]
On se servivira de cela plus loin avec les jeux d'essais.
range(20,30,2) => [20,22,24,26,28] donc; 1er paramètre=valeur initiale (défaut=0), 2ème paramètre=dernière valeur exclue, 3ème paramètre=incrément (défaut=1)
Autre exemple: la date de Pâques des 10 prochaines années.
map(paques,range(2008,2018)) => ["23/03/2008","12/04/2009","04/04/2010","24/04/2011","08/04/2012","31/03/2013","20/04/2014","05/04/2015","27/03/2016","16/04/2017"]
Par exemple, on fabrique la fonction lambda qui donne vrai quand son paramètre y est >=100:
sto("f",lambda y: y>=100)
Et on cherche la liste des nombres premiers compris entre 100 et 200:
filter(f,premiers(200)) => [101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199]
On peut aussi chercher, par exemple, des variables aléatoires distribuées au hasard selon la loi normale réduite (module probabilite), mais en ne retenant que les valeurs positives. Dans cet exemple, nous avons enchaîné les expressions dans une liste:
[sto(“f”,lambda y: y>=0),filter(f,hgaussred(10))] → [0.70683994795139,0.139106211249837,0.517782930504369,0.222072398717544,0.578393938896522]
C'est une appellation étrange, parce que ce n'est pas forcément facile à comprendre. Il s'agit d'une boucle conditionnelle dans une liste qui est considérée par Python comme une expression, et donc qui est calculable par la calculext. Par exemple:
Dans cette expression:
La condition avec “if” est optionnelle. Par exemple: les 5 prochaines dates de Pâques:
[paques(x) for x in range(2008,2013)] => ["23/03/2008","12/04/2009","04/04/2010","24/04/2011","08/04/2012"]
On peut, bien sûr, combiner toutes ces fonctions: sto, lambda, map, filter, compréhension de liste, etc… pour obtenir ce qu'on veut.
module math:
sin(0.365)/log(2)*pi => 1.61782275494049 acos(0.5) => 1.0471975511966 (radians) degrees(acos(0.5)) => 60 (degrés décimaux) sqrt(2) => 1.4142135623731 2**0.5 => 1.4142135623731 pow(2,0.5) => 1.4142135623731 2*pi => 6.28318530717959 e => 2.71828182845905 log(e) => 1 (évidemment!) log10(10) => 1 (idem!)
radians(180) => 3.14159265358979 (conversion de degrés en radians) degrees(3.14159265358979) => 180 (heureusement!)
module decimal:
Decimal("10")/Decimal("3") => Decimal("3.333333333333333333333333333") Decimal("10.54796823145698563256")+Decimal("0.00000000000000000001") => Decimal("10.54796823145698563257")
module random
random() => 0.399824531593547 random() => 0.753101408653799
module cmath
complex(1,2)+complex(2,3) => (3+5j) complex(-2,5)*complex(1,-3) => (13+11j) complex(3,1)/complex(-2,-5) => (-0.379310344827586+0.448275862068966j) (en fait, avec le calcul à la main, on trouve (-11/29 + 13/29j)) cmath.sin(complex(3,1)) => (0.217759551622152-1.16344036370325j) (pour éviter les confusions avec les fonctions de "math", toutes les fonctions de "cmath" doivent être préfixées par "cmath.")
fonctions traitant des chaînes de caractères
'27/10' + '/' + '2007' => '27/10/2007' (la concaténation de plusieurs chaînes donne une nouvelle chaîne) len('27/10/2007') => 10 (=nombre de caractères de la chaîne) '27/10/2007'[3:5] => '10' (extraction des caractères numéro 3 à 5 (5 exclu), le 1er caractère de la chaîne étant numéroté zéro) avec int('27/10/2007'[3:5]), on obtient 10 sous forme numérique (ici, numéro du mois dans l'année) qu'on pourrait réutiliser dans d'autres calculs.
fonctions traitant des listes
[12, 43, 9.765, 2][1] => 43 (extraction de la 2ème valeur car l'indice commence à zéro) [12, 43, 9.765, 2][0:2] => [12, 43] (extraction de la liste des valeurs allant de 0 à 2, 2 étant exclu) [12, 43, 9.765, 2][-2] => 765 (extraction de l'avant dernière valeur)
sto("x",premiers(1000))
len(x) -> 168
x[-6:-1] => [967, 971, 977, 983, 991]
Appel de l'aide de chaque fonction. Exemple:
aide(fact) => 'fact(n): calcule la factorielle de n (entier >= 0)'
Création de variables, affectation et réaffectation de valeurs de type quelconque
sto("x",2*sin(0.145)) => 0.288984859421053 (si la variable x n'existait pas, elle est crée. N'oubliez pas les guillemets ou les apostrophes autour du nom de variable)
Comme cette fonction “sto” renvoie le résultat de l'expression (2ème paramètre), on peut l'utiliser en plein milieu d'une expression.
55/sto("x",2*sin(0.145))+45.3687 => 235.690089536414 (l'expression "2*sin(0.145" a été utilisée dans le calcul et a été affectée à x en plus)
Après cette instruction, la variable x peut être utilisée dans n'importe quelle expression. Sa valeur sera utilisée dans l'expression.
(5/x-6.521873) => 10.7800715033104
On peut affecter ou réaffecter à cette variable x n'importe quel type de valeur.
sto("x",premiers(10000)) => affecte à x la liste de tous les nombres premiers <= 10000 len(x) => donne alors le nombre de nombres premiers ainsi calculés, c'est à dire 1229. sto("x",dec2bin(48325)) => affecte à x la conversion binaire de 48325, soit '1011110011000101' sto("x",paques(2008)) => affecte à la variable x la date de pâques de 2008 = '23/03/2008' (voir plus loin)
La fonction arrond(x,n) renvoie le résultat de l'expression x sous forme de chaine, avec les nombres à virgule flottante correctement affichés, conformément au mode d'affichage défini par “n”. Cela correspond à l'affichage normal du résultat, à part qu'on ne modifie par le mode d'affichage courant. Par exemple:
sin(0.123) => 0.122690090024315
arrond(sin(0.123),4) => "0.1227"
On aurait pu obtenir la même chose avec la séquence suivante:
precision(4) sin(0.123) => 0.1227 precision() pour revenir au mode d'affichage par défaut (affichage "intelligent" avec 15 chiffres significatifs)
Bibliothèque générale - fonctions diverses
dec2bin(759135841) => "101101001111110111111001100001"
dec2bins(-91,12) => "111110100101"
bin2dec("1011000101011010110101010") => 23246250
bin2decs("111110100101",12) => -91
Si L1 et L2 sont des valeurs numériques, la fonction renvoie une liste de n valeurs dont la 1ère est L1 et la dernière L2, les valeurs intermédiaires étant calculées:
jeuxdessais(10,0,9) => [0,1,2,3,4,5,6,7,8,9]
Autre exemple plus inhabituel: la date de Pâques des 10 prochaines années:
map(paques,jeuxdessais(10,2008,2017)) => ["23/03/2008","12/04/2009","04/04/2010","24/04/2011","08/04/2012","31/03/2013","20/04/2014","05/04/2015","27/03/2016","16/04/2017"]
Si L1 et L2 sont des listes de paramètres, renvoie une liste de n listes de paramètres, le 1er jeu de paramètre étant L1 et le dernier L2, les jeux intermédiaires étant calculés:
jeuxdessais(3,[1,2,3],[3,4,5]) => [[1,2,3],[2,3,4],[3,4,5]]
Ça marche aussi si les paramètres vont dans un sens différent (l'un grandit, l'autre diminue et même devient négatif):
jeuxdessais(3,[1,2,3],[3,-2,5]) => [[1,2,3],[2,0,4],[3,-2,5]]
Si, à un moment donné on ne veut plus faire progresser le 2ème paramètre (par exemple), il suffit qu'il ait la même valeur dans L1 et L2:
jeuxdessais(3,[1,2,3],[3,2,5]) => [[1,2,3],[2,2,4],[3,2,5]]
Avec lambda et map(), on peut obtenir une liste de valeurs d'une fonction testée avec n valeurs de plusieurs paramètres passés à la fonction.
Exemple:
Créer une fonction avec lambda. On prend l'exemple ici d'une fonction simple avec 3 paramètres passés dans une liste L. Cette fonction se contente de renvoyer la somme des 3 paramètres:
sto("X",lambda L: L[0]+L[1]+L[2])
On va ensuite solliciter cette fonction avec n=5 jeux de paramètres, dont le 1er jeu est: L1=[1,2,3], le dernier: L2=[3,4,5]. La fonction jeuxdessais va calculer les paramètres intermédiaires:
jeuxdessais(5,[1,2,3],[3,4,5]) => [[1,2,3],[1.5,2.5,3.5],[2,3,4],[2.5,3.5,4.5],[3,4,5]]
Et on va utiliser la fonction python “map()” pour appliquer ces jeux de paramètres à la fonction X:
map(X, jeuxdessais(5,[1,2,3],[3,4,5])) => [6,7.5,9,10.5,12]
Vérification: vous voyez que le 2ème résultat (7.5) est bien le résultat de la fonction X sollicité par le 2ème jeu de paramètres calculé [1.5, 2.5, 3.5] puisque (1.5+2.5+3.5) ⇒ 7.5
Comme la fonction créée par lambda peut être aussi complexe qu'on veut, vous voyez avec quelle facilité vous pouvez, par exemple, tracer une courbe f(x):
sto("Y",lambda L: (2*cos(L[0])/(1+tan(L[0]))*1/sqrt(2*pi))**2)
Et calculer 10 valeurs de la fonction Y pour x=L[0] allant de 0 à 18:
Le jeu d'essais sera:
jeuxdessais(10,[0],[18]) => [[0],[2],[4],[6],[8],[10],[12],[14],[16],[18]]
Et la fonction Y=f() deviendra pour toutes ces valeurs:
map(Y,jeuxdessais(10,[0],[18])) => [0.636619772367581,0.0785068222629216,0.0584159216106966,1.16759375121064,0.000400676191347714,0.164958053317647,3.41883200806231,0.000175111120347522,0.345138427520504,14.7216632319214]
Si vous êtes gêné par le nombre de chiffres significatifs, il suffit d'utiliser la fonction arrond(x,n) comme suit (ici avec 4 chiffres après la virgule):
arrond(map(Y,jeuxdessais(10,[0],[18])),4) => "[0.6366,0.0785,0.0584,1.1676,0.0004,0.1650,3.4188,0.0002,0.3451,14.7217]"
fact(20) => 2432902008176640000
Votre calculatrice python est rapide: fact(5000) est calculée immédiatement sur un PC moderne… mais sur certains PC, il y a trop de chiffres pour que le résultat soit affiché (ça dépend de l'OS et des limites du module graphique Tkinter)! En fait, il en a exactement 16325, et vous pouvez le calculer facilement avec len(repr(fact(5000))) (qui vous comptera en plus le “L” final puisque c'est un entier “long”). Pour récupérer ce résultat, utilisez la séquence de touche Ctle-R qui sauvegarde la donnée calculée sur disque en l'ajoutant au fichier “resultat.txt”, situé dans le même répertoire que la calculette (donc, il faut avoir le droit d'écrire dans ce fichier).
pgcd(20,64) => 4
On aurait pu le faire d'une autre façon moins automatique en considérant la décomposition en facteurs premiers:
facteurs(20) => [2,2,5] facteurs(64) => [2,2,2,2,2,2]
On voit alors le pgcd: 2×2=4
Lorsque le pgcd est “1”, les 2 nombres donnés sont dits “premiers entre eux” (=ils n'ont aucun facteur commun):
pgcd(6,35) => 1
ppcm(20,64) => 320
On aurait pu le faire d'une autre façon moins automatique en considérant la décomposition en facteurs premiers:
facteurs(20) => [2,2,5] facteurs(64) => [2,2,2,2,2,2]
On voit alors le ppcm: (2**6)x5=320
Tout naturellement, lorsque les 2 nombres donnés sont “premiers entre eux”, leur ppcm est égal à leur produit:
ppcm(6,35) => 210 = 6*35
facteurs(48925327594) => [2, 11, 13, 31, 1103, 5003L] résultat obtenu en un centième de seconde (le post-fixage par "L" du dernier chiffre signifie simplement que c'est un entier long)
Quand le résultat est seulement le nombre donné, c'est que ce nombre est “premier” (=il n'est divisible que par lui-même):
facteurs(99989) => [99989]
estpremier(9973) => True estpremier(9841) => False estpremier(1111111111111111111) => True résultat trouvé en 9mn et 27 sec
premiers(100) => [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
NB: au delà de 10000 environ, le résultat est calculé, mais certains ordinateurs ne peuvent pas l'afficher parce que la ligne est trop longue (ça dépend de l'OS et des limitations du module graphique Tkinter). Par exemple, sur Windows XP, “premiers(100000)” calcule bien les 9592 nombres premiers (en 5 secondes!), mais refuse de les afficher. La solution la plus facile est d'enregistrer ce résultat sur disque avec Ctle-R et de le récupérer dans le fichier resultat.txt avec un simple éditeur de texte.
Au delà il faudra être patient: pour 10000000 (10 millions), la calculette trouvera bien les 664.579 nombres premiers (je l'ai fait!), mais mettra environ 24h.
permut(3) => 6 (ex: les 6 permutations possibles des 3 objets "1", "2" et "3": 123 231 312 213 132 321) permut(10) => 3628800
Même remarque que pour la fonction “fact(n)” du module arithmetique concernant l'affichage des résultats très longs sur certains PC (En fait, c'est le même code).
arrang(10,3) => 720
combin(10,3) => 120
On retrouve bien:
combin(10,3) = arrang(10,3) / permut(3)
binom(8,100,0.12) => 0.0624559656927432
binomcum(8,100,0.12) => 0.138592064127197
hypgeo(8,100,0.12,500) => 0.0560626494472544
hypgeocum(8,100,0.12,500) => 0.111411520509563
pgaussred(2) => 0.977249865802215
pgauss(5, 3.58, 0.8547) => 0.951683594346861
Cette fonction a été calculée par “intégration numérique”, c'est à dire en décomposant la surface à trouver en très nombreux petits rectangles (2000 par écart-type). Ce qui fait que le calcul pour 3 écarts-types nécessite le calcul de 6000 petits rectangles, mais ne demande qu'un centième de seconde…
Vous pouvez, bien sûr, retrouver les valeurs habituelles des tables calculées avec la “loi normale réduite” (m=0, s=1).
Ainsi, avant +3s, il y a:
pgaussred(3) ou pgauss(3,0,1) => 0.998650104184 ou 99.865% (valeur courante des tables "papier" : 0.99865)
Et entre -2s et +2s, il y a:
2*(pgauss(2,0,1)-0.5) => 0.954499772098 ou 95.45%
xgaussred(0.977249865802215) => 1.99999999999984 (ça devrait être "2.0": on n'est pas tombé loin :-D)
xgauss(0.95,3,1.456) => 5.39490693071295
hgaussred() => -0.506305559604254 hgaussred() => 1.43100857605685 hgaussred() => 0.0557568797713102 hgaussred(5) => [0.653567562762523,0.907479359323617,1.37670670103468,-0.608230227262229,-1.70607264166885]
hgauss(3,5) => 4.18456627105497 hgauss(3,5) => 9.89972166717921 hgauss(3,5) => 3.79305505449398 hgauss(3,5,5) => [-2.92544650845046,4.74059647970691,1.87221150326321,5.18916574661666,-2.42821512357165]
Pour faire plusieurs calculs de suite avec ce module, je vous suggère de passer en précision “2” pour éviter les 10 ou 15 chiffres après la virgule:
precision(2) affichage avec 2 chiffres après la virgule
Et à la fin, n'oubliez pas de revenir au mode par défaut (15 chiffres significatifs) avec:
precision()
menscredit(500,6,12) => 43.03 Euros
Ponctuellement, vous pourriez aussi utiliser la fonction arrond(x,2) pour n'obtenir que des résultats avec 2 chiffres après la virgule:
arrond(menscredit(500,6,12),2) => "43.03"
moiscredit(1000,8,50) => 21.54 (soit 21 mois + une 22ème mensualité plus faible)
capcredit(4.5,1500,240) => 237098.16 Euros (ex de calcul de capacité d'emprunt pour une maison, en fonction des possibilités de remboursement)
intcredit(3000,93,36) => 7.27%
coutcredit(300,26,12,200) => 212 Euros
Pour l'instant, il y a surtout des fonctions “date”. Ce sera complété par des fonctions “heures” bientôt!
tempsordi() => "vendredi 30/11/2007 08:43:51"
tempsntp() => "vendredi 30/11/2007 8:44:20"
Le serveur NTP par defaut est: “ntp.univ-lyon1.fr”. Vous pouvez choisir un autre serveur de temps NTP en consultant, par exemple, http://www.cru.fr/services/ntp/serveurs_francais:
tempsntp("ntp.imag.fr") => "vendredi 30/11/2007 8:45:3"
cejour() => "30/11/2007"
bissextile(2007) => False bissextile(2008) => True bissextile(2010) => False bissextile(2000) => True bissextile(3000) => False
numjouran("27/10/2007") => 300
datenumjouran(300,2007) => "27/10/2007"
diffdate("27/10/2007","31/12/2007") => 65 diffdate("27/10/2007","1/7/2007") => -118 diffdate("14/7/1789","27/10/2007") => 79727 jours depuis la prise de la bastille :-D
adddate("27/10/2007",45) => "11/12/2007" (date dans 45 jours) adddate("27/10/2007",-90) => "29/07/2007" (date il y a 90 jours) adddate("27/10/2007",-79727) => "14/07/1789" (Eh oui, ça marche aussi comme ça)
numjoursem("27/10/2007") => 6 (c'est à dire un samedi puisque lundi=1)
joursem("27/10/2007") => "samedi" (je l'avais bien dit...) joursem("1/1/2008") => "mardi" (le jour de l'an tombe un mardi: c'est bien pour le pont :-D) joursem("14/7/1789") => "mardi" (oui, ils ont fait ça un mardi!)
lundi("27/10/2007") => "22/10/2007"
NB: j'ai utilisé la méthode Hodges. J'ai bien sûr vérifié avec les dates officielles que toutes les dates calculées étaient exactes sur toute la période de validité dans le calendrier grégorien (1583 à 4100 soit 2518 dates de Pâques).
paques(2007) => "08/04/2007" paques(2008) => "23/03/2008" paques(2009) => "12/04/2009" paques(2010) => "04/04/2010" paques(3000) => "13/04/3000" (ça, ce sera difficile à vérifier sur votre carnet de rendez-vous: il faudra attendre un peu ou me faire confiance ;-))
ascension(2008) => "01/05/2008"
pentecote(2008) => "11/05/2008"
mardigras(2008) => "05/02/2008"
rameaux(2008) => "16/03/2008"
Tant que j'y étais, j'ai fait une fonction qui renvoie sous forme de liste tous les jours fériées (France) de l'année.
- Sans le second paramètre optionnel (comme: “feries(2008)”), vous n'avez que ceux qui tombent un jour de semaine (ni samedi, ni dimanche).
- Avec un 1 comme second paramètre (comme: “feries(2008,1)”), vous les avez tous, y compris les samedis-dimanches.
- Avec un 2 comme second paramètre(comme: “feries(2008,2)”), vous les avez tous + les 2 jours fériés supplémentaires d'Alsace-Moselle: le vendredi saint et la St Etienne (lendemain de Noël).
feries(2008,1) => voir liste suivante: pour faciliter la lecture, je présente ici la liste en plusieurs lignes:
["Jour de l'an = mardi 01/01/2008", "Jour de Pâques = dimanche 23/03/2008", "lundi de Pâques= lundi 24/03/2008", "Fête du Travail = jeudi 01/05/2008", "Fête de la Victoire 1945 = jeudi 08/05/2008", "Ascension = jeudi 01/05/2008", "Pentecôte = dimanche 11/05/2008", "Lundi de Pentecôte = lundi 12/05/2008", "Fête Nationale = lundi 14/07/2008", "Assomption = vendredi 15/08/2008", "Toussaint = samedi 01/11/2008", "Armistice 1918 = mardi 11/11/2008", "Noël = jeudi 25/12/2008"]
NB: pour le lundi de la Pentecôte, vous adaptez en fonction de ce que vous avez compris (férié/pas ferié ?)
Cette fonction est à adapter à votre situation, région, pays et besoins (ainsi qu'à l'évolution de la législation!)!
Il faut peu de choses pour que cette calculatrice fonctionne:
Pour Linux, on trouve tout ça sous forme de paquets déjà prévus (rpm pour la suse et deb pour debian) et souvent déjà pré installés.
Pour Windows, on trouve le programme à installer ici: http://www.python.org/download/windows/
Pour Mac, je ne sais pas ce qu'il faut faire, ni si ça marche: quelqu'un peut-il me renseigner ? (page contact du présent site)
Pour les versions de python:
Vous pouvez consulter toutes les versions ici (y compris les anciennes versions, mais celle-ci ne bénéficient d'aucun suivi de ma part!):
NB: c'est le même programme pour Windows et pour Linux!
La calculette comporte les fichiers suivants:
La calculette de base:
Les modules additionnels optionnels:
Vous placez tous les fichiers de la calculette dans un même répertoire (je l'appelle ”/chemin“ pour l'exemple).
Si vous voulez adapter cette calculette à vos besoins (c'est à dire modifier son code), vous devriez la mettre dans votre home. Si vous la mettez ailleurs, il faudrait au minimum que le fichier “resultat.txt” ait un chmod de 666 pour recevoir des données sauvegardées.
Vous pouvez lancer la calculette en console sous votre login par:
$ python /chemin/calculette.py
Mais comme c'est un programme graphique, je vous suggère plutôt de construire un raccourcis sur votre bureau KDE ou gnome pour faire ça (clic droit → etc…).
Si vous voulez ajouter des fonctions, installez aussi “idle” de python, ou un autre programme de développement python. N'oubliez pas que l'édition du code doit respecter l'encodage unicode “UTF-8”.
Et si vous avez ajouté des nouvelles fonctions, vous pouvez mettre à jour le fichier html pour l'aide avec n'importe quel outil d'édition de page web sur Windows ou sur linux. Sur linux: quanta plus ou nvu par exemple (ou même avec vim si vous êtes très très courageux (limite maso ))
Vous placez tous les fichiers de la calculette dans un même répertoire.
Pour lancer la calculette, le meilleur moyen est de créer un raccourcis sur le bureau (clic-droit → etc…) avec une commande de lancement du genre:
C:\Python25\pythonw.exe "C:\Documents and Settings\Tyrtamos\Mes documents\calculette\calculette.py".
Vous noterez l'utilisation de “pythonw.exe” (et pas python.exe) pour éviter le lancement de la console dos.
Vous pouvez aussi double-cliquer sur le nom calculette.py dans l'explorateur Windows, auquel cas, c'est la terminaison ”.py“ qui appellera “python.exe”. Mais là, vous avez la console DOS en plus. Pour l'éviter, c'est très simple: vous renommez le fichier:
Avec cette modif, le double-clic sur le nom calculette.pyw appellera le programme pythonw.exe.
Si vous voulez ajouter des fonctions, il faudra lancer “idle” de python, en principe livré aussi avec le python de base, ou un autre programme de développement python. N'oubliez pas que l'édition du code doit respecter l'encodage unicode “UTF-8”. Sous Windows,c'est le cas pour “idle” de Python (c'est ce que j'utilise pour le développement), mais aussi du notepad/bloc-notes. J'ai aussi essayé avec succès “easyeclipse pour Python” (http://www.easyeclipse.org/site/distributions/index.html)
Si vous avez ajouté des nouvelles fonctions, vous pouvez mettre à jour le fichier html pour l'aide avec n'importe quel outil d'édition de page web (ou avec un simple éditeur de texte si vous êtes très courageux).
La partie graphique de la calculette est entièrement définie dans la classe “Calculext” qui complète et surcharge la classe Frame du module Tkinter.
Une fois lancée, la calculette s'affiche et attend les évènements à prendre en compte: saisie d'une expression, clic de souris, touche F1 pour demande d'aide, etc…
Toutes les fonctions appelées directement par ces évènements sont définies à l'intérieur de cette classe.
Quand le calcul d'une expression est lancé, il est confié à un thread (thread = processus léger qui s'exécute à l'intérieur d'un processus normal) qui fait le calcul en tâche de fond, ce qui fait que la partie graphique reprend tout de suite la main et n'est pas bloquée par un calcul long.
Ce thread de calcul est défini dans la classe “Calcul”. Il reçoit l'expression à calculer, se charge du calcul par la fonction Python “eval()”, traite les erreurs par “try: .. except:” et place le résultat dans la variable globale “resultcalcul”. C'est l'état de la variable globale “encourscalcul” qui dit si un calcul est en cours ou pas. C'est la fonction “calculer()” de la classe “Calculext()” qui teste si le calcul est terminé ou si un arrêt de calcul a été demandé. Dans ce dernier cas, il est demandé au thread de s'arrêter (avec arretcalcul=True, et il est abandonné (del calc). Dans tous les cas, cette fonction calculer() se termine par l'affichage du résultat ou de l'erreur. A noter que cette boucle d'attente doit passer la main à la fenêtre par self.update() à chaque cycle afin que cette fenêtre ne soit pas bloquée pendant tout le calcul.
Le traitement d'erreur traite:
Remarque concernant l'arrêt demandé par l'utilisateur: ça ne marche pas toujours, et cela semble tenir au fonctionnement de Python. D'après ce que j'ai compris, le thread de calcul ne rend pas la main au bout d'un temps donné, mais au bout d'un certain nombre d'instructions virtuelles (100 bytecodes par défaut), ce qui fait que le thread ne rend pas toujours la main dans les boucles très courtes. Par exemple, j'ai eu beaucoup de problèmes pour arrêter la fonction factorielle (version non récursive). Heureusement, le problème ne se pose que pour des calculs rares (factorielle 20000 !) et on a toujours la possibilité d'arrêter sauvagement la calculatrice (non! ne retirez pas la prise! )…
L'affichage passe par une fonction “affiche()” qui permet de formater correctement les nombres réels (à virgule flottante), selon la valeur de la variable globale “nbchiffres”. La fonction “precision(n) avec -15<=n<=+15 permet à l'utilisateur de modifier ce formatage des nombres réels.
On peut sauvegarder le dernier résultat calculé par Ctle-R. Celui-ci est simplement ajouté au fichier texte “resultat.txt” et son contenu peut être consulté et récupéré avec un simple éditeur de texte.
Après chaque calcul, est aussi affiché la durée de ce calcul, formatée par la fonction “afficheduree(sd)”, ce qui permet de faciliter l'optimisation des fonctions qu'on ajoute.
Après chaque calcul réussi, l'expression ainsi que le dernier résultat sont empilés dans une pile (pile[]). On peut ainsi rappeler ce dernier résultat ainsi que l'une des expressions précédentes avec la flèche en haut et flèche en bas. Ce qui est rappelé vient dans la ligne de saisie, ce qui permet de ne pas avoir à les retaper. La pile n'est cependant pas conservée lors de l'extinction de la calculatrice, mais vous pouvez cependant la sauvegarder dans le fichier resultat.txt par Ctls-E.
Avec un clic droit dans la zone de saisie, un menu flottant apparait. Les items de ce menu en cascade (2 niveaux) sont définies dans la variable globale “chmenu” sous forme d'une liste de liste. Sa structure est très simple:
chmenu=( (titre1, item1, iten2, item3), (titre2, item1, item2), (titre3, item1, item2, item3, item4) )
Chaque “titre” est un texte du menu 1er niveau, qui affiche un menu 2ème niveau composé des “items” qui suivent.
Le menu lui-même est créé par le constructeur de la classe Calculext (c'est à dire dans __init__). Son codage est tel qu'il s'adaptera automatiquement aux modifications de chmenu, pour autant qu'on en respecte sa structure. Cela veut dire qu'il sera facile de mettre à jour le menu au fur et à mesure des fonctions ajoutés ultérieurement par les utilisateurs!
Le positionnement du menu à l'emplacement de la souris est défini par la fonction menupopup(self, evt). En cas de sélection d'un item du menu 2ème niveau, il y a insertion de l'item à l'emplacement du curseur (celui de la zone de saisie) par la fonction execmenu(self,ch). L'insertion est empêchée si l'item commence par “$”, ce qui permet de mettre des textes d'information dans le menu, comme par exemple un rappel des règles de priorités des opérateurs ou l'inévitable “à propos”. Si l'item commence par ”'”, seule la partie entre deux “'” est insérée. Si l'item est vide, cela déclenche l'affichage d'une ligne de séparation non sélectionnable dans le menu.
Nouveauté de la version 1.30: si on avait sélectionné du texte avant d'appeler l'insertion d'une fonction avec parenthèses au menu, le texte sélectionné se retrouve à l'intérieur des parenthèses de la fonction insérée.
J'ai finalement renoncé à afficher ici l'ensemble du code de la calculext, parce qu'il devient trop long: presque 700 lignes pour le seul fichier calculext.py. Il est cependant auto-documenté et je vous invite à le consulter directement.
Les “modules” python sont des fichiers “texte” séparés, importés dans le programme principal (ici “calculette.py”) par une instruction “import”. Ci-dessous les importations actuelles:
# importation des modules additionnels # ajoutez les modules que vous avez créés # et mettez en commentaire ceux que vous n'utilisez pas from bibgene import * from arithmetique import * from combinatoire import * from probabilite import * from credit import * from temps import *
C'est super simple! Prenons un exemple: une fonction qui teste si un nombre entier est pair.
def estpair(n): """estpair(n): dit si un nombre entier est pair (renvoie True ou False)""" return (n % 2)==0
Ajoutez ce code au fichier bibgene.py, enregistrez-le (n'oubliez pas l'encodage UTF-8!), relancez la calculatrice, et essayez:
estpair(42) => True estpair(99) => False
Vous pouvez voir aussi à quoi sert la ligne entourée de triples guillemets. Faites:
aide(estpair) => "estpair(n): dit si un nombre entier est pair (renvoie True ou False)"
Bien entendu, si la fonction nécessite l'importation de modules supplémentaires, il faut ajouter l'importation de ces modules au début du module en question.
Enfin, il est évident que votre fonction doit renvoyer quelque chose (instruction “return”), sinon, aucun résultat ne sera affiché. Par contre, ce résultat peut être n'importe quoi qui s'écrit sur une seule ligne, y compris une chaine de caractère ou une liste!
Vous pouvez aussi vérifier que le “n” fourni est bien un nombre entier. L'exemple devient:
def estpair(n): """estpair(n): dit si un nombre entier est pair (renvoie True ou False)""" if not ((type(n)==int) or (type(n)==long)): raise ValueError ("erreur estpair(n): n doit être un nombre entier") return (n % 2)==0
Dans ce cas:
estpair(8.123) => 'erreur estpair(n): n doit être un nombre entier'
C'est aussi simple que ça!
Imaginons maintenant que vous vouliez ajouter une fonction dont le calcul pourrait être très long: il faut que l'utilisateur puisse l'arrêter avant la fin!
Exemple extrême: une fonction qui ne fait rien mais ne s'arrête jamais toute seule:
def bidon(): """bidon(): fonction qui ne fait rien mais ne s'arrete jamais toute seule""" while True: pass return None
Vous l'ajoutez au module bibgene.py (mais vous ne lancez pas la calculatrice).
Vous remarquez que dans ce module, il y a au début:
import sys prog=sys.modules['__main__']
C'est important, parce que cela permettra de tester si l'arrêt du calcul a été demandé.
Il suffit de modifier le code comme suit:
def bidon(): """bidon(): fonction qui ne fait rien mais ne s'arrete jamais toute seule""" while True: prog.calc.arretcalcul() return None
Lorsque l'utilisateur demandera l'arrêt du calcul (bouton “stopper” ou touche F2), la variable globale arretcalcul passera à True, et à la boucle “while” suivante, il y aura une exception raise qui arrêtera le calcul en-cours dans le thread de calcul. En fait, ce test permet surtout d'arrêter le thread afin qu'il ne reste pas actif en mémoire, parce qu'il est libéré de toute façon par “del calc”.
Un détail bizarre cependant. Quelquefois, la boucle est trop rapide et ne rend pas la main à la fenêtre, ce qui fait que le calcul ne s'arrête pas sur demande. Il suffit alors de ralentir un peu la boucle avec time.sleep(0.001) pour que l'arrêt sur demande fonctionne. C'est ce que j'ai été obligé de faire avec fact(n) du module arithmetique et permut(n)du module combinatoire qui ne s'arrêtait pas avant l'arrêt normal du calcul pour n=20000.
Conseils supplémentaires:
Si vous voulez que vos nouvelles fonctions apparaissent dans le menu flottant, il faut l'ajouter dans la variable globale chmenu du fichier calculext.py.
Si vous voulez ajouter simplement une fonction “machin(x,y)” à un menu existant:
Situation initiale:
chmenu=( ..... ("titre_n", "item1", "item2", ..., "itemk"), ..... )
Situation finale:
chmenu=( ..... ("titre_n", "item1", "item2", ..., "itemk", "machin(x,y)"), ..... )
Simple, non?
Si vous voulez créer un nouveau titre “hi-fi” au menu 1er niveau, et une fonction “calcul_hp(x,y,z)” au 2ème niveau:
Nouvelle situation finale:
chmenu=( ..... ("titre_n", "item1", "item2", ..., "itemk"), ("hi-fi", "calcul_hp(x,y,z)"), ..... )
Voilà, c'est tout ce qu'il faut connaitre pour ajouter les fonctions dont vous avez besoin.
Pourquoi ajouter un module supplémentaire? En général parce qu'on veut regrouper plusieurs fonctions qui appartiennent à une même famille d'application. Par exemple:
Prenons le 2ème exemple pour la suite.
Pour construire un module supplémentaire, il suffit:
1- de créer le nouveau module par recopie du fichier fourni “modele.py”. Vous l'appelez comme vous voulez. Pour l'exemple, c'est “photos.py”.
2- Editez ce nouveau fichier photos.py avec un éditeur de texte (avec encodage UTF-8), et ajustez les zones à remplir par vous: votre nom, le nom du module, …
3- Vous devez ensuite ajouter dans ce module “photos.py”, l'importation des modules dont vos nouvelles fonctions auront besoin. Par exemple:
from math import *
4- Et vous ajoutez dans calculext.py l'importation de ce module par:
from photos import *
En variante, l'importation pourrait être plus “propre” en important seulement les fonctions que vous voulez rendre disponible:
from photos import fonction1, fonction2, ..., fonctionn
Mais si vous faites ça:
import photos
vos fonctions devront alors être toutes préfixées dans les expressions à calculer, avec le nom du module, par exemple: “photos.fonction1()”
5- Il ne reste plus qu'à ajouter vos nouvelles fonctions dans votre nouveau module photos.py: pour cela, voir le chapitre précédent “Ajouter une fonction supplémentaire dans un module existant”.
Voilà, c'est fait: vous avez votre calculette miniature toujours disponible, et faisant tout ce que vous voulez (et encore plus)!
Vous aurez du mal à trouver une autre calculatrice qui vous fait tout ça!
Les fonctions supplémentaires que je propose représentent un tout petit début de ce que je souhaite faire: surveillez l'arrivée des prochaines versions!
Si vous ajoutez de nouvelles fonctions ou de nouveaux modules, donnez moi l'info (page contact du site)!
J'espère que vous vous amuserez autant que moi!