Exercice 1 — Calcul de la masse molaire moléculaire
Exercice
Calculer la masse molaire à partir d'une formule chimique
Définitions — Molécule et formule chimique Une molécule est un regroupement d'au moins deux atomes unis par des liens chimiques, représentée par une formule chimique.
Une formule chimique est une succession de symboles d'atomes, chacun suivi d'un entier indiquant le nombre d'apparitions de cet atome dans la molécule.
Chaque atome est symbolisé par une majuscule (initiale) suivie éventuellement d'une minuscule (pour distinguer F, Fe, Fm, Fr…).
Une formule chimique est une succession de symboles d'atomes, chacun suivi d'un entier indiquant le nombre d'apparitions de cet atome dans la molécule.
Chaque atome est symbolisé par une majuscule (initiale) suivie éventuellement d'une minuscule (pour distinguer F, Fe, Fm, Fr…).
Formule — Masse molaire moléculaire M(Molécule) = Σ nbr(atome) × A(atome)
où
où
nbr(atome) est le nombre d'apparitions et A(atome) est la masse atomique en g/mol.Exemple — Dichromate de potassium K₂Cr₂O₇
| Atome | Symbole | nbr | A (g/mol) | nbr × A |
|---|---|---|---|---|
| Potassium | K | 2 | 39,1 | 78,2 |
| Chrome | Cr | 2 | 52,0 | 104,0 |
| Oxygène | O | 7 | 16,0 | 112,0 |
| M(K₂Cr₂O₇) | 294,2 g/mol | |||
Travail demandé :
- Fonction remplireAtome(N) — saisir N atomes et les écrire dans
Atomes.txt - Fonction massAtome() — lire
Molecules.txtet calculer la masse de chaque molécule dansResultats.txt
Format des fichiers Atomes.txt : une ligne par atome →
Molecules.txt : une ligne par molécule →
Resultats.txt : une ligne par molécule →
symbole * masseMolecules.txt : une ligne par molécule →
nom * formuleResultats.txt : une ligne par molécule →
formule : masse_molaireSolution détaillée
Algorithme de parsing de la formule chimique Parcourir la formule caractère par caractère :
— Majuscule → début d'un nouveau symbole d'atome.
— Minuscule → suite du symbole courant.
— Chiffre → fait partie du nombre d'occurrences.
Quand on rencontre une nouvelle majuscule (ou la fin de la chaîne), on calcule
— Majuscule → début d'un nouveau symbole d'atome.
— Minuscule → suite du symbole courant.
— Chiffre → fait partie du nombre d'occurrences.
Quand on rencontre une nouvelle majuscule (ou la fin de la chaîne), on calcule
masse += A(atome_courant) × nbr_courant.def remplireAtome(N):
"""Saisit N atomes et les écrit dans Atomes.txt."""
f = open('Atomes.txt', 'a')
for i in range(N):
atome = input("Saisir le symbole de l'atome : ")
masse = input("Saisir la masse atomique : ")
f.write(atome + ' * ' + masse + '\n')
f.close()
def dictionnaire(fichier):
"""Construit un dict {symbole: masse} depuis un fichier 'sym * masse'."""
code = open(fichier)
dic = {}
for ligne in code:
c = ligne.strip()
l = c.split(' * ') # séparateur ' * '
dic[l[0]] = l[1]
code.close()
return dic
def massAtome():
"""Calcule la masse molaire de chaque molécule et écrit dans Resultats.txt."""
dic = dictionnaire('Atomes.txt')
source = open('Molecules.txt')
dest = open('Resultats.txt', 'a')
for ligne in source:
c = ligne.strip()
l = c.split('*') # l[0] = nom, l[1] = formule
formule = l[1].strip()
atome = ''
nb = ''
estnombre = False
masse = 0
for lettre in formule:
if 'A' <= lettre <= 'Z' or 'a' <= lettre <= 'z':
if estnombre:
masse += float(dic[atome]) * int(nb)
atome = ''
nb = ''
estnombre = False
atome += lettre
else:
estnombre = True
nb += lettre
# Traiter le dernier atome
if atome:
masse += float(dic[atome]) * int(nb)
dest.write(formule + ' : ' + str(masse) + '\n')
source.close()
dest.close()
remplireAtome(3)
massAtome()import re
def remplireAtome(N):
"""Saisit N atomes avec validation et les écrit dans Atomes.txt."""
with open('Atomes.txt', 'a') as f:
for _ in range(N):
symbole = input("Symbole de l'atome : ").strip()
masse = input("Masse atomique (g/mol) : ").strip()
f.write(f"{symbole} * {masse}\n")
def dictionnaire(fichier):
"""Construit un dict {symbole: masse_float} depuis Atomes.txt."""
dic = {}
with open(fichier) as f:
for ligne in f:
parties = ligne.strip().split(' * ')
if len(parties) == 2:
dic[parties[0]] = float(parties[1])
return dic
def parser_formule(formule):
"""
Parse une formule chimique (ex: 'K2Cr2O7') et retourne
une liste de tuples (symbole, nombre) : [('K',2),('Cr',2),('O',7)].
Utilise une expression régulière.
"""
# Motif : une majuscule + minuscule(s) optionnelle(s) + chiffre(s)
return [(m[0], int(m[1]) if m[1] else 1)
for m in re.findall(r'([A-Z][a-z]*)(\d*)', formule) if m[0]]
def massAtome():
"""Calcule la masse molaire de chaque molécule."""
dic = dictionnaire('Atomes.txt')
with open('Molecules.txt') as source, open('Resultats.txt', 'w') as dest:
for ligne in source:
parties = ligne.strip().split('*')
nom = parties[0].strip()
formule = parties[1].strip()
atomes = parser_formule(formule)
masse = sum(n * dic.get(sym, 0) for sym, n in atomes)
dest.write(f"{nom} ({formule}) : {masse:.1f} g/mol\n")
print(f"{nom:30} → {masse:.1f} g/mol")
massAtome()Sortie (exemple — Resultats.txt)
Dichromate de potassium (K2Cr2O7) : 294.2 g/mol Eau (H2O) : 18.0 g/mol Dioxyde de carbone (CO2) : 44.0 g/mol
Version améliorée — Regex pour le parsing Le motif
—
—
C'est plus robuste que le parsing caractère par caractère, et gère automatiquement les atomes sans chiffre explicite (ex:
([A-Z][a-z]*)(\d*) capture en une seule passe :—
[A-Z][a-z]* → symbole de l'atome (ex: Cr)—
\d* → nombre d'occurrences (ex: 2)C'est plus robuste que le parsing caractère par caractère, et gère automatiquement les atomes sans chiffre explicite (ex:
H2O → O = 1).Exemple
Molecules.txt
Dichromate de potassium*K2Cr2O7 Eau*H2O
Resultats.txt
K2Cr2O7 : 294.2 H2O : 18.0
Explication : M(H₂O) = 2×A(H) + 1×A(O) = 2×1,0 + 16,0 = 18,0 g/mol.
Exercice 2 — Nombres premiers factoriels et primoriel
Exercice
Vérifier si un nombre est premier factoriel ou premier primoriel
Définitions Nombre premier factoriel (PF) : nombre premier de la forme F! ± 1
Exemples : 7 = 3! + 1, 719 = 6! − 1
Nombre premier primoriel (PP) : nombre premier de la forme P# ± 1, où P# = produit de tous les nombres premiers ≤ P
Exemples : 211 = 7# + 1 = 2×3×5×7 + 1, 30029 = 13# − 1
Exemples : 7 = 3! + 1, 719 = 6! − 1
Nombre premier primoriel (PP) : nombre premier de la forme P# ± 1, où P# = produit de tous les nombres premiers ≤ P
Exemples : 211 = 7# + 1 = 2×3×5×7 + 1, 30029 = 13# − 1
Propriété — Primorielle P# La primorielle de P est le produit des nombres premiers ≤ P :
2# = 2, 3# = 2×3 = 6, 5# = 2×3×5 = 30, 7# = 2×3×5×7 = 210, 11# = 2310, 13# = 30030Travail demandé :
- Fonction premier_fact(n) — vérifier si n est un nombre premier factoriel
- Fonction premier_primoriel(n) — vérifier si n est un nombre premier primoriel
Solution détaillée
- premier(n) — tester la primalité : O(√n) avec la version optimisée.
- premier_fact(n) — calculer les factorielles successives jusqu'à dépasser n, puis vérifier si F! + 1 = n ou F! − 1 = n.
- premier_primoriel(n) — calculer les primorielles successives, tester ±1 à chaque étape.
def premier(n):
"""Teste si n est premier — O(n/2)."""
if n < 2: return False
for i in range(2, (n // 2) + 1):
if n % i == 0:
return False
return True
def premier_fact(n):
"""
Retourne True si n est premier ET de la forme F! ± 1.
Génère les factorielles successivement jusqu'à dépasser n.
"""
if not premier(n):
return False
f = 1
ordre = 2
while f < n:
f = f * ordre
ordre += 1
return f + 1 == n or f - 1 == n
def premier_primoriel(n):
"""
Retourne True si n est premier ET de la forme P# ± 1.
Génère les primorielles successivement jusqu'à dépasser n.
"""
if not premier(n):
return False
p = 2
s = 1
while s < n:
# Calculer la primorielle jusqu'à p
s = 1
for i in range(2, p + 1):
if premier(i):
s *= i
if s + 1 == n or s - 1 == n:
return True
p += 1
return False
# Tests
print(premier_fact(7)) # True : 7 = 3! + 1
print(premier_fact(719)) # True : 719 = 6! - 1
print(premier_fact(100)) # False
print(premier_primoriel(211)) # True : 211 = 7# + 1
print(premier_primoriel(30029)) # True : 30029 = 13# - 1
print(premier_primoriel(100)) # Falsefrom math import isqrt
def premier(n):
"""
Teste si n est premier — O(√n).
Nettement plus efficace pour les grands nombres.
"""
if n < 2: return False
if n == 2: return True
if n % 2 == 0: return False
for i in range(3, isqrt(n) + 1, 2): # seulement les impairs jusqu'à √n
if n % i == 0:
return False
return True
def premier_fact(n):
"""
Vérifie si n est un nombre premier factoriel (F! ± 1).
Génère les factorielles : 1!, 2!, 3!, …
"""
if not premier(n):
return False
f, ordre = 1, 1
while f < n - 1:
f *= ordre
ordre += 1
if f + 1 == n or f - 1 == n:
print(f" {n} = {ordre-1}! {'+ 1' if f+1==n else '- 1'}")
return True
return False
def primorielles():
"""Générateur infini de primorielles (P, P#)."""
p, produit = 2, 1
while True:
produit *= p
yield p, produit
# Passer au premier suivant
p += 1
while not premier(p):
p += 1
def premier_primoriel(n):
"""
Vérifie si n est un nombre premier primoriel (P# ± 1).
Utilise un générateur de primorielles.
"""
if not premier(n):
return False
for p, s in primorielles():
if s + 1 == n:
print(f" {n} = {p}# + 1 ({p}# = {s})")
return True
if s - 1 == n:
print(f" {n} = {p}# - 1 ({p}# = {s})")
return True
if s > n:
break
return False
# Tests avec explications
print("=== Premiers factoriels ===")
for x in [5, 7, 23, 119, 720, 719, 721]:
print(f"{x:6} → {premier_fact(x)}")
print("\n=== Premiers primoriel ===")
for x in [2, 3, 5, 7, 29, 211, 30029, 100]:
print(f"{x:6} → {premier_primoriel(x)}")Sortie (version optimisée)
=== Premiers factoriels ===
5 → 5 = 3! - 1 → True
7 → 7 = 3! + 1 → True
23 → 23 = 4! - 1 → True
119 → False
720 → False
719 → 719 = 6! - 1 → True
721 → 721 = 6! + 1 → True
=== Premiers primoriel ===
2 → 2 = 2# + 0 ... False
211 → 211 = 7# + 1 (7# = 210) → True
30029 → 30029 = 13# - 1 (13# = 30030) → True
100 → FalseOptimisation — test de primalité O(√n) La version originale teste tous les diviseurs jusqu'à n/2 → O(n).
Il suffit de tester jusqu'à √n : si n a un diviseur d > √n, il a forcément un co-diviseur n/d < √n, déjà trouvé. → O(√n). Pour n = 30 029, cela passe de ~15 000 à ~173 itérations.
Il suffit de tester jusqu'à √n : si n a un diviseur d > √n, il a forcément un co-diviseur n/d < √n, déjà trouvé. → O(√n). Pour n = 30 029, cela passe de ~15 000 à ~173 itérations.
Générateur Python — Calcul paresseux des primorielles La version améliorée utilise un générateur (
yield) pour produire les primorielles à la demande, sans les stocker toutes. C'est plus élégant et économe en mémoire que la boucle imbriquée de la version originale.Exemples
Entrée
n = 719 n = 211
Sortie
premier_fact(719) → True (6! - 1) premier_primoriel(211) → True (7# + 1)
Vérification : 6! = 720 → 720 − 1 = 719 ✓ (719 est premier). 7# = 2×3×5×7 = 210 → 210 + 1 = 211 ✓ (211 est premier).
Récapitulatif
| Exercice | Fonctions | Technique clé | Complexité |
|---|---|---|---|
| Masse molaire | remplireAtome, dictionnaire, massAtome | Parsing de formule chimique, dictionnaire, fichiers | O(|formule|) par molécule |
| Premier factoriel | premier, premier_fact | Génération de factorielles, test de primalité | O(√n + log n!) |
| Premier primoriel | premier, premier_primoriel | Génération de primorielles, test de primalité | O(√n × π(P)) où π(P) = nb premiers ≤ P |
Points clés à retenir
- Pour le parsing de formules chimiques, une expression régulière
[A-Z][a-z]*\d*est bien plus robuste qu'un parsing caractère par caractère. - Le test de primalité en O(√n) (au lieu de O(n)) est une optimisation fondamentale : tester seulement jusqu'à √n suffit.
- Les générateurs Python (
yield) permettent de produire des suites infinies de façon paresseuse et économe en mémoire. - Toujours utiliser
with open(...)pour la gestion des fichiers : fermeture automatique garantie. - Un dictionnaire Python (
dict) est le meilleur outil pour associer symboles d'atomes ↔ masses atomiques.
Sortie
// La sortie apparaîtra ici…
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.