Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Arrondis

16 réponses
Avatar
Gamotte
Bonjour,

je voudrais remplacer un fichier par le m=EAme fichier
dans lequel tous les nombres ont =E9t=E9 arrondis =E0 3
chiffres apr=E8s la virgule, l'arrondi =E9tant vers le haut
ou le bas selon celui qui est le plus proche.
Le fichier contient du texte et des nombres diss=E9min=E9s
dans le texte. Je ne peux donc pas utiliser un tableur
et recherche donc une solution du type rechercher/remplacer.

Merci

--
Yves

10 réponses

1 2
Avatar
Stephane Chazelas
2007-03-20, 09:19(-07), Gamotte:
[...]
je voudrais remplacer un fichier par le même fichier
dans lequel tous les nombres ont été arrondis à 3
chiffres après la virgule, l'arrondi étant vers le haut
ou le bas selon celui qui est le plus proche.
Le fichier contient du texte et des nombres disséminés
dans le texte. Je ne peux donc pas utiliser un tableur
et recherche donc une solution du type rechercher/remplacer.
[...]


perl -pi -e 's/d*.d{4,}/sprintf("%.3f",$&)/eg' fichier

--
Stéphane

Avatar
Alain Ketterlin
"Gamotte" writes:

je voudrais remplacer un fichier par le même fichier dans lequel
tous les nombres ont été arrondis à 3 chiffres après la virgule,
l'arrondi étant vers le haut ou le bas selon celui qui est le plus
proche. Le fichier contient du texte et des nombres disséminés dans
le texte. Je ne peux donc pas utiliser un tableur et recherche donc
une solution du type rechercher/remplacer.


Je suis sur que tu auras plein de réponse Perl etc. Je te propose un
petit analyseur lexical à la place (c'est printf() qui fait l'arrondi,
mais tu pourrais passer à round()) :

-- rond.lex ------------------------------------------------
%{
#include <stdlib.h>
"include <stdio.h>
%}
%option nounput
%option main
%%
[0-9]+.[0-9]+ {printf("%.3lf",atof(yytext));}
%%
------------------------------------------------------------

Puis :

lex -orond.c rond.lex && cc rond.c -o rond

(ou flex ... et gcc). Et roulez jeunesse.

-- Alain.

Avatar
Gamotte
Merci à tous les deux.
Je n'avais pas pensé à lex, c'est une bonne idée.
Concernant la réponse de Stéphane, c'est le 'e'
de 'eg' qui indique qu'il faut interpréter la chaine de
remplacement comme une expression, c'est bien
ça ?
Avatar
Stephane Chazelas
2007-03-21, 03:26(-07), Gamotte:
Merci à tous les deux.
Je n'avais pas pensé à lex, c'est une bonne idée.
Concernant la réponse de Stéphane, c'est le 'e'
de 'eg' qui indique qu'il faut interpréter la chaine de
remplacement comme une expression, c'est bien
ça ?


Oui, voir perldoc perlop

--
Stéphane

Avatar
Gamotte
Avatar
Vincent Lefevre
Dans l'article ,
Stephane Chazelas écrit:

2007-03-20, 09:19(-07), Gamotte:
[...]
je voudrais remplacer un fichier par le même fichier
dans lequel tous les nombres ont été arrondis à 3
chiffres après la virgule, l'arrondi étant vers le haut
ou le bas selon celui qui est le plus proche.
Le fichier contient du texte et des nombres disséminés
dans le texte. Je ne peux donc pas utiliser un tableur
et recherche donc une solution du type rechercher/remplacer.
[...]


perl -pi -e 's/d*.d{4,}/sprintf("%.3f",$&)/eg' fichier


Mauvaise solution (ou excellente solution, suivant le cas).

En faisant ça, tu vas dire à Perl de d'abord convertir une chaîne en
nombre double précision IEEE 754 et provoquer une erreur d'arrondi,
qui pourra donner un résultat différent. Par exemple:

echo 1.01250000000000001 | perl -pe 's/d*.d{4,}/sprintf("%.3f",$&)/eg' -

donne "1.012" au lieu de "1.013". La solution de ne travailler que
sur la chaîne en base 10 est la bonne.

Maintenant, si les nombres stockés dans le fichier sont censés être
des représentations de nombres en double précision (comme ce qui
peut se faire avec le type double de XML, cf XML Schema Part 2),
alors au contraire, c'est la bonne solution.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Vincent Lefevre
Dans l'article ,
Alain Ketterlin écrit:

"Gamotte" writes:

je voudrais remplacer un fichier par le même fichier dans lequel
tous les nombres ont été arrondis à 3 chiffres après la virgule,
l'arrondi étant vers le haut ou le bas selon celui qui est le plus
proche. Le fichier contient du texte et des nombres disséminés dans
le texte. Je ne peux donc pas utiliser un tableur et recherche donc
une solution du type rechercher/remplacer.


Je suis sur que tu auras plein de réponse Perl etc. Je te propose un
petit analyseur lexical à la place (c'est printf() qui fait l'arrondi,
mais tu pourrais passer à round()) :

-- rond.lex ------------------------------------------------
%{
#include <stdlib.h>
"include <stdio.h>
%}
%option nounput
%option main
%%
[0-9]+.[0-9]+ {printf("%.3lf",atof(yytext));}
%%
------------------------------------------------------------


Cf ma réponse à Stéphane. Ta solution a le même problème. La solution
générale (y compris pour un fichier avec des nombres à plage et à
précision arbitraire) la moins complexe est probablement d'utiliser
quelques expressions régulières pour traiter tous les cas possibles
et faire les transformations. Si la plage des nombres est restreinte
(à déterminer...), alors la solution suivante peut convenir:

perl -pe
's/(d*.d{3})(d)d*/$2 < 5 ? $1 : sprintf("%.3f", $1 + 0.001)/eg'

(il s'agit d'un arrondi "away from zero", comme ce qui se fait souvent
en base 10).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)


Avatar
Stephane Chazelas
2007-03-25, 22:41(+00), Vincent Lefevre:
[...]
perl -pi -e 's/d*.d{4,}/sprintf("%.3f",$&)/eg' fichier


Mauvaise solution (ou excellente solution, suivant le cas).

En faisant ça, tu vas dire à Perl de d'abord convertir une chaîne en
nombre double précision IEEE 754 et provoquer une erreur d'arrondi,
qui pourra donner un résultat différent. Par exemple:

echo 1.01250000000000001 | perl -pe 's/d*.d{4,}/sprintf("%.3f",$&)/eg' -

donne "1.012" au lieu de "1.013". La solution de ne travailler que
sur la chaîne en base 10 est la bonne.

Maintenant, si les nombres stockés dans le fichier sont censés être
des représentations de nombres en double précision (comme ce qui
peut se faire avec le type double de XML, cf XML Schema Part 2),
alors au contraire, c'est la bonne solution.


en ce cas, on peut faire

perl -pi -e 's/(?<=.)(d{3})(d)d*/$1+($2>=5)/ge'

--
Stéphane


Avatar
Stephane Chazelas
2007-03-26, 06:33(+00), Stephane Chazelas:
[...]
en ce cas, on peut faire

perl -pi -e 's/(?<=.)(d{3})(d)d*/$1+($2>=5)/ge'


D'ailleurs, -0.2345 doit-il etre arrondi en -0.234 or -0.235?

Si -0.234:

perl -p -e 's/(-?)(d*.)(d{3})(d)d*/
$1.$2.($3+($4>=(5+($1eq"-"))))/ge'
--
Stéphane

Avatar
Nicolas George
Stephane Chazelas wrote in message
:
D'ailleurs, -0.2345 doit-il etre arrondi en -0.234 or -0.235?


-0.234, si on veut quelque chose de logique et régulier.

1 2