Comment arrondir un nombre à des chiffres significatifs en Python


148

J'ai besoin d'arrondir un flotteur pour être affiché dans une interface utilisateur. Par exemple, à un chiffre significatif:

1234 -> 1000

0,12 -> 0,1

0,012 -> 0,01

0,062 -> 0,06

6253 -> 6000

1999 -> 2000

Existe-t-il une bonne façon de faire cela en utilisant la bibliothèque Python, ou dois-je l'écrire moi-même?


2
Formatez-vous simplement la sortie? Demandez-vous à ce sujet? docs.python.org/library/stdtypes.html#string-formatting ou ceci? docs.python.org/library/string.html#string-formatting
S.Lott

quelle sortie attendez-vous pour 0,062 et 6253?
lamirap

Le package to-precision le fait maintenant. Ma réponse publiée détaille comment cela s'applique.
William Rusnack

Réponses:


146

Vous pouvez utiliser des nombres négatifs pour arrondir les entiers:

>>> round(1234, -3)
1000.0

Ainsi, si vous n'avez besoin que du chiffre le plus significatif:

>>> from math import log10, floor
>>> def round_to_1(x):
...   return round(x, -int(floor(log10(abs(x)))))
... 
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0

Vous devrez probablement prendre soin de transformer float en entier s'il est supérieur à 1.


3
C'est la bonne solution. L'utilisation log10est le seul moyen approprié de déterminer comment l'arrondir.
Wolph

73
round_to_n = lambda x, n: round (x, -int (floor (log10 (x))) + (n - 1))
Roy Hyunjin Han

28
Vous devriez utiliser log10(abs(x)), sinon les nombres négatifs échoueront (et traiter x == 0séparément bien sûr)
Tobias Kienzler

2
J'ai créé un package qui fait cela maintenant et qui est probablement plus facile et plus robuste que celui-ci. Poster lien , Repo lien . J'espère que cela t'aides!
William Rusnack

2
round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))protège contre x==0et x<0Merci @RoyHyunjinHan et @TobiasKienzler. Ne protège pas contre les non définis comme math.inf, ou les déchets comme None, etc.
AJP

98

% g dans le formatage de chaîne formatera un flottant arrondi à un certain nombre de chiffres significatifs. Il utilisera parfois la notation scientifique «e», donc reconvertissez la chaîne arrondie en virgule flottante puis via le formatage de chaîne% s.

>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'

7
L'exigence du PO était que 1999 soit formaté en «2000» et non en «2000.0». Je ne vois pas de moyen simple de changer votre méthode pour y parvenir.
Tim Martin le

1
C'est exactement ce que j'ai toujours voulu! où as-tu trouvé ça?
djhaskin987

12
Notez que le comportement de% g n'est pas toujours correct. En particulier, il supprime toujours les zéros de fin même s'ils sont significatifs. Le nombre 1.23400 a 6 chiffres significatifs, mais "% .6g"% (1.23400) entraînera "1.234" qui est incorrect. Plus de détails dans ce billet de blog: randlet.com/blog/python-significant-figures-format
randlet

3
Tout comme la méthode de la réponse d'Evgeny, cela ne parvient pas à arrondir correctement 0.075à 0.08. Il revient à la 0.07place.
Gabriel

1
round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)vous permet d'ajuster le nombre de chiffres significatifs!
denizb

49

Si vous voulez avoir autre chose qu'une décimale significative (sinon la même chose que Evgeny):

>>> from math import log10, floor
>>> def round_sig(x, sig=2):
...   return round(x, sig-int(floor(log10(abs(x))))-1)
... 
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0

8
round_sig (-0.0232) -> erreur de domaine mathématique, vous voudrez peut-être ajouter un abs () là-dedans;)
dgorissen

2
Tout comme les méthodes dans les réponses de Evgeny et de Peter Graham, cela ne fonctionne pas correctement autour 0.075de 0.08. Il revient à la 0.07place.
Gabriel

3
Il échoue également pour round_sig (0).
Yuval Atzmon

2
@Gabriel C'est une "fonctionnalité" intégrée de python s'exécutant sur votre ordinateur et se manifestant par son comportement de la fonction round. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues
Novice C

1
@Gabriel J'ai ajouté une réponse qui explique pourquoi vous devriez vous attendre à récupérer 0,7 en arrondissant "0,075"! voir stackoverflow.com/a/56974893/1358308
Sam Mason

30
f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))

Cette solution est différente de toutes les autres car:

  1. il résout exactement la question OP
  2. il ne pas besoin d' aucun paquet supplémentaire
  3. il ne pas besoin d' aucune définie par l' utilisateur fonction auxiliaire ou opération mathématique

Pour un nombre arbitraire nde chiffres significatifs, vous pouvez utiliser:

print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))

Tester:

a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']

Remarque : avec cette solution, il n'est pas possible d'adapter dynamiquement le nombre de chiffres significatifs à partir de l'entrée car il n'y a pas de méthode standard pour distinguer les nombres avec différents nombres de zéros de fin ( 3.14 == 3.1400). Si vous devez le faire, des fonctions non standard comme celles fournies dans le package to-precision sont nécessaires.


Pour info: j'ai trouvé cette solution indépendamment d'eddygeek pendant que j'essayais de résoudre le même problème dans l'un de mes codes. Maintenant, je me rends compte que ma solution est, évidemment, presque identique à la sienne (je viens de remarquer la sortie erronée et je n'ai pas pris la peine de lire le code, mon erreur). Un petit commentaire sous sa réponse aurait probablement suffi à la place d'une nouvelle réponse ... La seule différence (clé) est la double utilisation du :gformateur qui préserve les entiers.
Falken

Wow, votre réponse doit être vraiment lue de haut en bas;) Cette astuce en double cast est sale, mais soignée. (Notez que 1999 formaté comme 2000.0 suggère 5 chiffres significatifs, il faut donc {:g}recommencer.) En général, les entiers avec des zéros à la fin sont ambigus en ce qui concerne les chiffres significatifs, à moins qu'une technique (comme le surlignage au-dessus du dernier significatif) ne soit utilisée.
Tomasz Gandor le

8

J'ai créé le package avec précision qui fait ce que vous voulez. Il vous permet de donner vos chiffres des chiffres plus ou moins significatifs.

Il produit également des notations standard, scientifiques et techniques avec un nombre spécifié de chiffres significatifs.

Dans la réponse acceptée, il y a la ligne

>>> round_to_1(1234243)
1000000.0

Cela spécifie en fait 8 sig figs. Pour le numéro 1234243, ma bibliothèque n'affiche qu'un seul chiffre significatif:

>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'

Il arrondira également le dernier chiffre significatif et pourra automatiquement choisir la notation à utiliser si aucune notation n'est spécifiée:

>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'

Maintenant, je cherche la même chose mais appliqué à un pandas df
mhoff

@mhoff vous pouvez probablement utiliser la carte des pandas avec un lambda. lambda x: to_precision(x, 2)
William Rusnack

Ajoutez ceci à (PyPI) [ pypi.org/] . Il n'y a rien de tel qui existe là-dedans, pour autant que je sache.
Morgoth le

c'est un excellent package mais je pense que la plupart des fonctionnalités sont maintenant dans le module
sigfig

1
il a un bogue: std_notation (9.999999999999999e-05, 3) donne: '0.00010' qui n'est que 2 chiffres significatifs
Boris Mulder

5

Pour arrondir un entier à 1 chiffre significatif, l'idée de base est de le convertir en virgule flottante avec 1 chiffre avant le point et de l'arrondir, puis de le reconvertir à sa taille entière d'origine.

Pour ce faire, nous devons connaître la plus grande puissance de 10 inférieure à l'entier. Nous pouvons utiliser le plancher de la fonction log 10 pour cela.

from math import log10, floor
def round_int(i,places):
    if i == 0:
        return 0
    isign = i/abs(i)
    i = abs(i)
    if i < 1:
        return 0
    max10exp = floor(log10(i))
    if max10exp+1 < places:
        return i
    sig10pow = 10**(max10exp-places+1)
    floated = i*1.0/sig10pow
    defloated = round(floated)*sig10pow
    return int(defloated*isign)

1
Plus un pour la solution qui fonctionne sans le tour de python (.., chiffres) et sans aucune condition!
Steve Rogers du

5

Pour répondre directement à la question, voici ma version utilisant la dénomination de la fonction R :

import math

def signif(x, digits=6):
    if x == 0 or not math.isfinite(x):
        return x
    digits -= math.ceil(math.log10(abs(x)))
    return round(x, digits)

Ma principale raison pour publier cette réponse sont les commentaires se plaignant que "0,075" arrondit à 0,07 plutôt que 0,08. Ceci est dû, comme l'a souligné "Novice C", à une combinaison d'arithmétique en virgule flottante ayant à la fois une précision finie et une représentation en base 2 . Le nombre le plus proche de 0,075 qui peut réellement être représenté est légèrement plus petit, donc l'arrondi est différent de ce à quoi vous pourriez vous attendre naïvement.

Notez également que cela s'applique à toute utilisation d'arithmétique à virgule flottante non décimale, par exemple C et Java ont tous deux le même problème.

Pour montrer plus en détail, nous demandons à Python de formater le nombre au format «hexadécimal»:

0.075.hex()

ce qui nous donne: 0x1.3333333333333p-4. La raison en est que la représentation décimale normale implique souvent des arrondis et que ce n'est donc pas ainsi que l'ordinateur "voit" le nombre. Si vous n'êtes pas habitué à ce format, quelques références utiles sont les documents Python et le standard C .

Pour montrer comment ces chiffres fonctionnent un peu, nous pouvons revenir à notre point de départ en faisant:

0x13333333333333 / 16**13 * 2**-4

qui devrait s'imprimer 0.075. 16**13est parce qu'il y a 13 chiffres hexadécimaux après la virgule décimale, et2**-4 est parce que les exposants hexadécimaux sont en base-2.

Maintenant, nous avons une idée de la façon dont les flottants sont représentés, nous pouvons utiliser le decimalmodule pour nous donner plus de précision, nous montrant ce qui se passe:

from decimal import Decimal

Decimal(0x13333333333333) / 16**13 / 2**4

donner: 0.07499999999999999722444243844et, espérons-le, expliquer pourquoi round(0.075, 2)évalue0.07


1
C'est une excellente explication de la raison pour laquelle 0,075 est arrondi à 0,07 au niveau du code , mais nous (dans les sciences physiques) avons appris à toujours arrondir vers le haut et non vers le bas. Ainsi, le comportement attendu est en fait d'avoir 0,08 en conséquence, malgré les problèmes de précision en virgule flottante.
Gabriel

1
Je ne sais pas où est votre confusion: lorsque vous entrez 0,075, vous entrez en fait ~ 0,07499 (comme ci-dessus), qui arrondit selon les règles mathématiques normales. si vous utilisiez un type de données (comme la virgule flottante décimale ) qui pourrait représenter 0,075, il devrait en effet arrondir à 0,08
Sam Mason

Je ne suis pas confus. Lorsque j'entre 0,075, j'entre en fait 0,075. Quoi qu'il arrive dans le calcul en virgule flottante dans le code, je m'en fiche.
Gabriel

@Gabriel: Et si vous aviez délibérément entré 0.074999999999999999, que voulez - vous attendre à obtenir dans ce cas?
Mark Dickinson

@MarkDickinson cela dépend. Un chiffre significatif: 0,07, deux: 0,075.
Gabriel

4
def round_to_n(x, n):
    if not x: return 0
    power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
    factor = (10 ** power)
    return round(x * factor) / factor

round_to_n(0.075, 1)      # 0.08
round_to_n(0, 1)          # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0

J'espère prendre le meilleur de toutes les réponses ci-dessus (moins pouvoir le mettre comme un lambda d'une ligne;)). Vous n'avez pas encore exploré, n'hésitez pas à modifier cette réponse:

round_to_n(1e15 + 1, 11)  # 999999999999999.9

4

J'ai modifié la solution d'indgar pour gérer les nombres négatifs et les petits nombres (y compris zéro).

from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
    return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)

Pourquoi ne pas simplement tester si x == 0? Si vous aimez un one-liner, juste return 0 if x==0 else round(...).
pjvandehaar

2
@pjvandehaar, vous avez raison pour le cas général et j'aurais dû le mettre. De plus, pour les calculs numériques que je dois effectuer, nous obtenons parfois des nombres comme 1e-15. Dans notre application, nous voulons qu'une comparaison de deux petits nombres (dont l'un pourrait être zéro) soit considérée comme égale. Certaines personnes veulent aussi arrondir les petits nombres (cela pourrait être 1e-9, 1e-15 ou même 1e-300) à zéro.
ryan281

1
Intéressant. Merci d'avoir expliqué cela. Dans ce cas, j'aime vraiment cette solution.
pjvandehaar

@Morgoth C'est un problème intéressant et difficile. Comme vous l'avez souligné, la valeur imprimée n'affiche pas les 3 chiffres significatifs, mais la valeur est correcte (par exemple 0.970 == 0.97). Je pense que vous pouvez utiliser certaines des autres solutions d'impression comme f'{round_sig(0.9701, sig=3):0.3f}'si vous voulez que le zéro soit imprimé.
ryan281 du

3

Si vous voulez arrondir sans impliquer de chaînes, le lien que j'ai trouvé enfoui dans les commentaires ci-dessus:

http://code.activestate.com/lists/python-tutor/70739/

me semble le meilleur. Ensuite, lorsque vous imprimez avec des descripteurs de mise en forme de chaîne, vous obtenez une sortie raisonnable et vous pouvez utiliser la représentation numérique à d'autres fins de calcul.

Le code du lien est composé de trois lignes: def, doc et return. Il a un bug: vous devez vérifier les logarithmes explosifs. C'est facile. Comparez l'entrée à sys.float_info.min. La solution complète est:

import sys,math

def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )

Cela fonctionne pour n'importe quelle valeur numérique scalaire, et n peut être un floatsi vous avez besoin de décaler la réponse pour une raison quelconque. Vous pouvez en fait repousser la limite à:

sys.float_info.min*sys.float_info.epsilon

sans provoquer d'erreur, si pour une raison quelconque vous travaillez avec des valeurs minuscules.


2

Je n'arrive pas à penser à quoi que ce soit qui puisse gérer cela hors de la boîte. Mais c'est assez bien géré pour les nombres à virgule flottante.

>>> round(1.2322, 2)
1.23

Les nombres entiers sont plus compliqués. Ils ne sont pas stockés en base 10 en mémoire, donc les endroits importants ne sont pas une chose naturelle à faire. C'est assez simple à implémenter une fois qu'il s'agit d'une chaîne.

Ou pour les entiers:

>>> def intround(n, sigfigs):
...   n = str(n)
...   return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))

>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)

Si vous souhaitez créer une fonction qui gère n'importe quel nombre, ma préférence serait de les convertir en chaînes et de rechercher une décimale pour décider quoi faire:

>>> def roundall1(n, sigfigs):
...   n = str(n)
...   try:
...     sigfigs = n.index('.')
...   except ValueError:
...     pass
...   return intround(n, sigfigs)

Une autre option consiste à vérifier le type. Ce sera beaucoup moins flexible et ne jouera probablement pas bien avec d'autres nombres tels que des Decimalobjets:

>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)

Le simple fait de jouer avec des chaînes n'arrondira pas les chiffres. 1999 arrondi à 1 chiffre significatif est 2000, et non 1000.
Peter Graham

Il y a une bonne discussion sur ce problème archivé sur ActiveState code.activestate.com/lists/python-tutor/70739
Tim McNamara

2

La réponse affichée était la meilleure disponible lorsqu'elle a été donnée, mais elle présente un certain nombre de limites et ne produit pas de chiffres significatifs techniquement corrects.

numpy.format_float_positional prend directement en charge le comportement souhaité. Le fragment suivant renvoie le flottant xformaté à 4 chiffres significatifs, la notation scientifique étant supprimée.

import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.

La documentation (déplacée vers numpy.org/doc/stable/reference/generated/… ) indique que cette fonction implémente l'algorithme Dragon4 (de Steele & White 1990, dl.acm.org/doi/pdf/10.1145/93542.93559 ). Cela produit des résultats ennuyeux, par exemple print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n'). Je n'ai pas vérifié Dragon4 lui-même.
Rainald62

0

J'ai rencontré cela aussi, mais j'avais besoin de contrôler le type d'arrondi. Ainsi, j'ai écrit une fonction rapide (voir code ci-dessous) qui peut prendre en compte la valeur, le type d'arrondi et les chiffres significatifs souhaités.

import decimal
from math import log10, floor

def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
    roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']

    power =  -1 * floor(log10(abs(value)))
    value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
    divided = Decimal(value) * (Decimal('10.0')**power) 
    roundto = Decimal('10.0')**(-sig+1)
    if roundstyle not in roundstyles:
        print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
    return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
    nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
    return decimal.Decimal(nozero)


for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
    print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
    print (x, 'rounded normal: ',myrounding(x,sig=3))

0

Utilisation du formatage nouveau style python 2.6+ (car% -style est obsolète):

>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'

Dans python 2.7+, vous pouvez omettre les premiers 0s.


Avec quelle version de python? Python 3.6.3 | Anaconda, Inc. | (par défaut, 13 octobre 2017, 12:02:49) présente le même problème d'arrondi. "{0}". Format (float ("{0: .1g}". Format (0.075))) donne '0,07', pas '0,08'
Don Mclachlan

@DonMclachlan J'ai ajouté une explication de la raison pour laquelle cela est attendu dans stackoverflow.com/a/56974893/1358308
Sam Mason

0

Cette fonction effectue un arrondi normal si le nombre est supérieur à 10 ** (- decimal_positions), sinon ajoute plus de décimales jusqu'à ce que le nombre de positions décimales significatives soit atteint:

def smart_round(x, decimal_positions):
    dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
    return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)

J'espère que ça aide.


0

https://stackoverflow.com/users/1391441/gabriel , est-ce que ce qui suit répond à votre préoccupation concernant rnd (.075, 1)? Avertissement: renvoie la valeur sous forme de flottant

def round_to_n(x, n):
    fmt = '{:1.' + str(n) + 'e}'    # gives 1.n figures
    p = fmt.format(x).split('e')    # get mantissa and exponent
                                    # round "extra" figure off mantissa
    p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
    return float(p[0] + 'e' + p[1]) # convert str to float

>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593

0

Cela renvoie une chaîne, de sorte que les résultats sans parties fractionnaires et les petites valeurs qui apparaîtront autrement en notation E s'affichent correctement:

def sigfig(x, num_sigfig):
    num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
    return '%.*f' % (num_decplace, round(x, num_decplace))

0

Étant donné une question si bien répondue, pourquoi ne pas en ajouter une autre

Cela convient un peu mieux à mon esthétique, bien que beaucoup de ceux ci-dessus soient comparables

import numpy as np

number=-456.789
significantFigures=4

roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)

string=rounded.astype(str)

print(string)

Cela fonctionne pour les nombres individuels et les tableaux numpy, et devrait fonctionner correctement pour les nombres négatifs.

Il y a une étape supplémentaire que nous pourrions ajouter - np.round () renvoie un nombre décimal même si arrondi est un entier (c'est-à-dire que pour significantFigures = 2, nous pourrions nous attendre à récupérer -460 mais à la place nous obtenons -460.0). Nous pouvons ajouter cette étape pour corriger cela:

if roundingFactor<=0:
    rounded=rounded.astype(int)

Malheureusement, cette dernière étape ne fonctionnera pas pour un tableau de nombres - je vous laisse cela à vous, cher lecteur, de déterminer si vous en avez besoin.


0

Le package / bibliothèque sigfig couvre cela. Après l' installation, vous pouvez effectuer les opérations suivantes:

>>> from sigfig import round
>>> round(1234, 1)
1000
>>> round(0.12, 1)
0.1
>>> round(0.012, 1)
0.01
>>> round(0.062, 1)
0.06
>>> round(6253, 1)
6000
>>> round(1999, 1)
2000

0
import math

  def sig_dig(x, n_sig_dig):
      num_of_digits = len(str(x).replace(".", ""))
      if n_sig_dig >= num_of_digits:
          return x
      n = math.floor(math.log10(x) + 1 - n_sig_dig)
      result = round(10 ** -n * x) * 10 ** n
      return float(str(result)[: n_sig_dig + 1])


    >>> sig_dig(1234243, 3)
    >>> sig_dig(243.3576, 5)

        1230.0
        243.36
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.