j'écris un script de lecture de données binaires produites par un code de
calcul en F77; une valeur de charge particulière est affectée aux mailles
inactives, typiqument 999.99. Les valeurs sont des REALs écrits en binaire
non formatté.
Malheureusement dans la lecture du fichier je ne récupère pas exactement
cette valeur, je suis confronté à un problème de ce genre:
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
j'écris un script de lecture de données binaires produites par un code de
calcul en F77; une valeur de charge particulière est affectée aux mailles
inactives, typiqument 999.99. Les valeurs sont des REALs écrits en binaire
non formatté.
Malheureusement dans la lecture du fichier je ne récupère pas exactement
cette valeur, je suis confronté à un problème de ce genre:
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
j'écris un script de lecture de données binaires produites par un code de
calcul en F77; une valeur de charge particulière est affectée aux mailles
inactives, typiqument 999.99. Les valeurs sont des REALs écrits en binaire
non formatté.
Malheureusement dans la lecture du fichier je ne récupère pas exactement
cette valeur, je suis confronté à un problème de ce genre:
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
À mon avis, vous feriez mieux de travailler en DOUBLE plutôt qu'en
FLOAT. La quasi totalité des processeurs modernes ne savent plus
utiliser les floats (ils font leurs calculs en double et filtrent au
dernier moment pour simuler les floats). Il n'y a que lorsqu'on est
très très contraint en place mémoire qu'on utilise les floats mais
c'est quand même très rare.
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." <bozo_le_clown@wherever.you.want.com> écrivait (wrote):
[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
À mon avis, vous feriez mieux de travailler en DOUBLE plutôt qu'en
FLOAT. La quasi totalité des processeurs modernes ne savent plus
utiliser les floats (ils font leurs calculs en double et filtrent au
dernier moment pour simuler les floats). Il n'y a que lorsqu'on est
très très contraint en place mémoire qu'on utilise les floats mais
c'est quand même très rare.
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
À mon avis, vous feriez mieux de travailler en DOUBLE plutôt qu'en
FLOAT. La quasi totalité des processeurs modernes ne savent plus
utiliser les floats (ils font leurs calculs en double et filtrent au
dernier moment pour simuler les floats). Il n'y a que lorsqu'on est
très très contraint en place mémoire qu'on utilise les floats mais
c'est quand même très rare.
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." <bozo_le_clown@wherever.you.want.com> écrivait (wrote):
[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
Là encore je ne comprends pas... Si les données proviennent d'un
fichier binaire Fortran (dont tu connais le format), il suffit de lire
les octets regroupés correctement (par 4 pour des floats, par 8 pour
doubles...) puis de leur appliquer 'unpack' pour en faire des nombres
Perl :
my $float = unpack("F", $quatre_octets_d_un_float);
my $double = unpack("D", $double_octets_d_un_float);
Là encore je ne comprends pas... Si les données proviennent d'un
fichier binaire Fortran (dont tu connais le format), il suffit de lire
les octets regroupés correctement (par 4 pour des floats, par 8 pour
doubles...) puis de leur appliquer 'unpack' pour en faire des nombres
Perl :
my $float = unpack("F", $quatre_octets_d_un_float);
my $double = unpack("D", $double_octets_d_un_float);
Là encore je ne comprends pas... Si les données proviennent d'un
fichier binaire Fortran (dont tu connais le format), il suffit de lire
les octets regroupés correctement (par 4 pour des floats, par 8 pour
doubles...) puis de leur appliquer 'unpack' pour en faire des nombres
Perl :
my $float = unpack("F", $quatre_octets_d_un_float);
my $double = unpack("D", $double_octets_d_un_float);
À (at) Tue, 29 Jan 2008 19:45:20 +0100,
"Julien K." écrivait (wrote):On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
J'en conclus donc que tu lis un fichier binaire (plutôt que la sortie
ASCII). Bon... C'est très facile à faire à partir du moment où on sait
comment est constitué le fichier Fortran.
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
Heu... je ne comprends pas ce que tu veux dire. Les floats sont
généralement stockés sur 4 octets et les doubles sur 8 octets.
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
Là encore je ne comprends pas...
Si les données proviennent d'un fichier binaire Fortran (dont tu connais
le format), il suffit de lire les octets regroupés correctement (par 4
pour des floats, par 8 pour doubles...) puis de leur appliquer 'unpack'
pour en faire des nombres Perl :
Nul besoin de passer par la représentation textuelle des valeurs.
À (at) Tue, 29 Jan 2008 19:45:20 +0100,
"Julien K." <bozo_le_clown@wherever.you.want.com> écrivait (wrote):
On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." <bozo_le_clown@wherever.you.want.com> écrivait (wrote):
[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]
Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
J'en conclus donc que tu lis un fichier binaire (plutôt que la sortie
ASCII). Bon... C'est très facile à faire à partir du moment où on sait
comment est constitué le fichier Fortran.
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
Heu... je ne comprends pas ce que tu veux dire. Les floats sont
généralement stockés sur 4 octets et les doubles sur 8 octets.
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
Là encore je ne comprends pas...
Si les données proviennent d'un fichier binaire Fortran (dont tu connais
le format), il suffit de lire les octets regroupés correctement (par 4
pour des floats, par 8 pour doubles...) puis de leur appliquer 'unpack'
pour en faire des nombres Perl :
Nul besoin de passer par la représentation textuelle des valeurs.
À (at) Tue, 29 Jan 2008 19:45:20 +0100,
"Julien K." écrivait (wrote):On 29-01-2008, Paul Gaborit wrote:
À (at) Tue, 29 Jan 2008 15:18:15 +0100,
"Julien K." écrivait (wrote):[...]
$ perl -e 'print unpack("f",(pack("f",999.99))) ;'
999.989990234375
$ perl -e 'print sprintf("%.4f",unpack("f",(pack("f",999.99)))) ;'
999.9900
Comment puis-je faire pour récupérer 999.99, valeur utilisée dans des
tests? Utiliser sprintf résoud le problème mais ça ne me semble pas /propre/.
[...]Bon, ceci étant dit, vous n'avez peut-être pas le choix...
L'autre alternative est de lire une sortie ASCII du code; je fixe
arbitrairement le format de sortie donc ça revient à peu-près au même que de
fixer l'arrondi du binaire (sauf que c'est plus lent à lire).
J'en conclus donc que tu lis un fichier binaire (plutôt que la sortie
ASCII). Bon... C'est très facile à faire à partir du moment où on sait
comment est constitué le fichier Fortran.
Le problème constaté est tout fait normal et n'a rien à voir avec Perl
C'est juste que la valeur stockée par un float ne peut pas être tout pile
999.99 donc si on l'affiche avec trop de précision on voit les derniers
bits erronés.
Oui, ça je sais, je cherchais un moyen de limiter l'affectation des
variables à la partie codée (8 octets) du float (et pas me trimbaler le
bourrage de la mantisse).
Heu... je ne comprends pas ce que tu veux dire. Les floats sont
généralement stockés sur 4 octets et les doubles sur 8 octets.
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
La solution du sprintf est pas mal pour arrondir mais le .4f est
arbitraire (pourquoi 4 décimales après la virgule,
C'est la première qui marche ;-)
et si la valeur vaut 1e-5 ou 1e20...). Je propose donc d'utiliser une
même limite arbitraire mais ne dépendant pas de l'ordre de la valeur :
perl -e 'print sprintf("%g", unpack("f",(pack("f",999.99)))), "n" ;'
Oui c'est effectivement mieux mais ça implique toujours de passer par une
chaîne de caractères pour arriver à un float... Enfin vu le temps
d'exécution c'est négligeable.
Là encore je ne comprends pas...
Si les données proviennent d'un fichier binaire Fortran (dont tu connais
le format), il suffit de lire les octets regroupés correctement (par 4
pour des floats, par 8 pour doubles...) puis de leur appliquer 'unpack'
pour en faire des nombres Perl :
Nul besoin de passer par la représentation textuelle des valeurs.
On 29-01-2008, Paul Gaborit wrote:
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
On 29-01-2008, Paul Gaborit wrote:
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
On 29-01-2008, Paul Gaborit wrote:
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est dans
le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est dans
le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est dans
le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?
Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
À (at) Wed, 30 Jan 2008 11:54:47 +0100,
"Julien K." écrivait (wrote):C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
(Je mets de côté le $t utilisé dans @{ $t } et donc on ne sait rien
mais j'imagine que c'est là où tu veux stocker tes valeurs...)
Donc tu crois qu'il faut que tu remplaces la ligne :
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
par :
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
C'est absolument inutile !
Avec la première version de cette ligne, les valeurs *flottantes* envoyées
dans @{ $t } sont exactement les mêmes que celles écrites par Fortran dans
le fichier binaire... mais comme Perl n'utilise que des doubles (en
interne), tu récupères nécessairement plus de précision qu'en Fortan.
C'est d'ailleurs signalé dans la doc de 'pack'. Petit extrait (en
français) :
Sachez que Perl utilise des doubles en interne pour tous les
calculs numériques et qu'une conversion de double vers float puis
retour vers double amène à une perte de précision (i.e.,
unpack("f", pack("f", $foo)) est généralement différent de $foo).
Sauf que là, l'opération se fait dans l'autre sens. Mais ça ne change
rien à la situation : lorsqu'on enlève des bits, on perd en précision
et lorsqu'on en ajoute, ils sont évidemment faux.
À (at) Wed, 30 Jan 2008 11:54:47 +0100,
"Julien K." <bozo_le_clown@wherever.you.want.com> écrivait (wrote):
C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?
Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
(Je mets de côté le $t utilisé dans @{ $t } et donc on ne sait rien
mais j'imagine que c'est là où tu veux stocker tes valeurs...)
Donc tu crois qu'il faut que tu remplaces la ligne :
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
par :
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
C'est absolument inutile !
Avec la première version de cette ligne, les valeurs *flottantes* envoyées
dans @{ $t } sont exactement les mêmes que celles écrites par Fortran dans
le fichier binaire... mais comme Perl n'utilise que des doubles (en
interne), tu récupères nécessairement plus de précision qu'en Fortan.
C'est d'ailleurs signalé dans la doc de 'pack'. Petit extrait (en
français) :
Sachez que Perl utilise des doubles en interne pour tous les
calculs numériques et qu'une conversion de double vers float puis
retour vers double amène à une perte de précision (i.e.,
unpack("f", pack("f", $foo)) est généralement différent de $foo).
Sauf que là, l'opération se fait dans l'autre sens. Mais ça ne change
rien à la situation : lorsqu'on enlève des bits, on perd en précision
et lorsqu'on en ajoute, ils sont évidemment faux.
À (at) Wed, 30 Jan 2008 11:54:47 +0100,
"Julien K." écrivait (wrote):C'est ce que je fais et c'est ce qui me donne les erreurs d'arrondi. J'ai
mis un exemple en ligne de commande pour faire simple mais ceci devrait
t'en dire plus (code adapté ie sans contrôle, use strict...):
<<<<
# header
$head_fmt = q!i2f2a16i3! ;
read($FH,$f,length(pack($head_fmt)),0) ;
# ($step $period $per_$time $tot_time $var $ncol $nrow $nlay)
@t = unpack($head_fmt,$f) ;
($nrow,$ncol) = @t[5,6] ;
# matrice ($nrow x $ncol)
$line_fmt = sprintf('f%i',$ncol) ;
for $i (0..$nrow-1)
{ read($FH,$f,length(pack($line_fmt)),0) ;
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
}
Le 'sprintf()' qui motive ma question est appliqué à la dernière ligne:
<<<<
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
Est-ce plus clair?Nul besoin de passer par la représentation textuelle des valeurs.
Pour donner un exemple concis, si :-).
(Je mets de côté le $t utilisé dans @{ $t } et donc on ne sait rien
mais j'imagine que c'est là où tu veux stocker tes valeurs...)
Donc tu crois qu'il faut que tu remplaces la ligne :
push( @{ $t }, [ unpack($line_fmt,$f) ] ;
par :
push(@{ $t },[ map (sprintf('%.4f',$_),unpack($line_fmt,$f)) ]) ;
C'est absolument inutile !
Avec la première version de cette ligne, les valeurs *flottantes* envoyées
dans @{ $t } sont exactement les mêmes que celles écrites par Fortran dans
le fichier binaire... mais comme Perl n'utilise que des doubles (en
interne), tu récupères nécessairement plus de précision qu'en Fortan.
C'est d'ailleurs signalé dans la doc de 'pack'. Petit extrait (en
français) :
Sachez que Perl utilise des doubles en interne pour tous les
calculs numériques et qu'une conversion de double vers float puis
retour vers double amène à une perte de précision (i.e.,
unpack("f", pack("f", $foo)) est généralement différent de $foo).
Sauf que là, l'opération se fait dans l'autre sens. Mais ça ne change
rien à la situation : lorsqu'on enlève des bits, on perd en précision
et lorsqu'on en ajoute, ils sont évidemment faux.
--{ Julien K. a plopé ceci: }--Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est
dans le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
Les nombres flottants exprimé en binaire ne sont jamais exacts,
la plupart du temps. Je t'invite à regarder les messages récents
dans le ng comp.lang.fortran, où ce genre de question revient
régulièrement.
--{ Julien K. a plopé ceci: }--
Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est
dans le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
Les nombres flottants exprimé en binaire ne sont jamais exacts,
la plupart du temps. Je t'invite à regarder les messages récents
dans le ng comp.lang.fortran, où ce genre de question revient
régulièrement.
--{ Julien K. a plopé ceci: }--Et dans ces octets, on trouve la mantisse et l'exposant. De quel 'bourrage'
parles-tu ?
Eh bien celui qui fait que perl ne lise pas /exactement/ ce qui est
dans le fichier (ou ce que je pense y trouver). Maintenant je m'y prends
peut-être mal pour la lecture de données binaires...
Les nombres flottants exprimé en binaire ne sont jamais exacts,
la plupart du temps. Je t'invite à regarder les messages récents
dans le ng comp.lang.fortran, où ce genre de question revient
régulièrement.