from decimal import Decimal as D from pathlib import Path import json,csv N='https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors' B='https://www.bipm.org/en/publications/si-brochure' U='https://aa.usno.navy.mil/faq/leap_years' cases=[ ('gallons','20 gallons : US liquide ou impérial','US liquide','impérial','L','20','3.785411784','4.54609',N,'Les deux nombres désignent des conventions différentes, pas une incertitude de mesure.','/mathematique/gallon-us-imperial.html'), ('tonnes','2 tonnes : métriques ou short tons','tonne métrique','short ton US','kg','2','1000','907.18474',N,'Lire le nom complet de l’unité sur le document.','/poids/tonne-short-ton.html'), ('cuilleres','4 cuillères à soupe : métriques ou US','cuillère métrique','tablespoon US','mL','4','15','14.78676478125',N,'Les ustensiles réels peuvent différer de ces conventions de volume.','/autres/cuillere-soupe-millilitre.html'), ('mois','6 mois : convention de 30 jours ou moyenne grégorienne','mois de 30 jours','mois moyen grégorien','jours','6','30','30.436875',U,'Aucune de ces moyennes ne remplace deux dates de calendrier.','/temps/mois-calendrier.html'), ('livres','10 livres : facteur exact ou raccourci à 500 g','livre avoirdupois','approximation à 500 g','g','10','453.59237','500',N,'La deuxième colonne est un raccourci volontairement approximatif, pas une autre définition de la livre.','/poids/livre-gramme.html'), ('pieds','5,11 pieds ou 5 pieds 11 pouces','5,11 pieds décimaux','5 pieds 11 pouces','m','1','1.557528','1.8034',N,'5,11 × 0,3048 ; (5 × 0,3048) + (11 × 0,0254). La virgule ne sépare pas les unités.','/distance/pied-metre.html')] rows=[] for id,title,la,lb,unit,quantity,fa,fb,source,limit,page in cases: a=D(quantity)*D(fa);b=D(quantity)*D(fb);delta=b-a;ratio=delta/a*100 rows.append(dict(id=id,title=title,conventionA=la,conventionB=lb,unit=unit,quantity=quantity,factorA=fa,factorB=fb,resultA=str(a),resultB=str(b),difference=str(delta),relativeDifferencePercent=str(ratio.quantize(D('.0001'))),source=source,limit=limit,page=page)) # Independently specified expected outputs catch changes to the constants or arithmetic. expected=[('75.708235680','90.92180'),('2000','1814.36948'),('60','59.14705912500'),('180','182.621250'),('4535.92370','5000'),('1.557528','1.8034')] assert all(D(r['resultA'])==D(a) and D(r['resultB'])==D(b) for r,(a,b) in zip(rows,expected)) out=Path('site/donnees/comparaison-conventions');out.mkdir(parents=True,exist_ok=True) (out/'resultats.json').write_text(json.dumps(dict(version='2026-10-31',method='Calcul décimal ; différence B − A et écart relatif (B − A)/A × 100. Six scénarios choisis, sans mesure de terrain ni comparaison de logiciels.',rows=rows),ensure_ascii=False,indent=2)+'\n') with (out/'resultats.csv').open('w',encoding='utf-8-sig',newline='') as f: w=csv.DictWriter(f,fieldnames=list(rows[0]),delimiter=';');w.writeheader();w.writerows(rows) print('6 comparaisons, 12 résultats attendus validés')