アプリ版:「スタンプのみでお礼する」機能のリリースについて

フォートランで作られたデータを、perlで作り直そうと始めました。
なんとか、perlの中で値の計算までは出来たのですが、
下記データの2フィールド目に対して積算の仕方が解りません。
awkでは、awk '{SUM += $2;printf("%s %10.4e\n", $1, SUM)}'でできましたが、
perlで中ではどのようにするのか?

1998-04-20T16:16:00   6.533078e+05
1998-05-01T01:59:00   1.501809e+06
1998-05-05T07:20:00   7.202719e+05
1998-05-05T07:24:00   9.799618e+05

ついでに、御存じでしたら、御教授ください。
awkとperlの計算結果は全く同じにでましたが、フォートランの結果は
下記のように微妙に違ってしまう処がございます。
それは、どうしてでしょうか?
  
 awk,perl の結果    フォートランの結果   フォートランの7ケタの結果
 7.202719e+05      7.202718e+05      7.2027181e+05        
 9.799618e+05     9.799616e+05 9.7996169e+05

以上 よろしくお願い致します。

A 回答 (4件)

#2補足について。



この内容だと、Fortranでは単精度で処理されています。
参照: http://www.nag-j.co.jp/fortran/FI_17.html#AUTOTO …

実装にもよりますが、Cで言えば、float相当です。
http://ja.wikipedia.org/wiki/%E5%8D%98%E7%B2%BE% …
にあるように、有効桁は、10進で7桁程度です。

Perlの内部ではCで言えば、double相当の精度で計算しています。
http://ja.wikipedia.org/wiki/%E5%80%8D%E7%B2%BE% …
にあるように、有効桁は、10進で15桁程度です。

違いが出ているのは、7桁目です。
これは、単精度にとっては精度ぎりぎりの桁なので、誤差が出る箇所です。
対し、倍精度にとっては、まだ余裕のある桁です。

この差が、集計結果の違いに出ているのだと思われます。

この回答への補足

詳細な説明有難うございました。
より良い知識を得る事が出来き、フォートランとperlの違いが少し解りました。
安心してperlへ切り替えたいと思います。
では、御存じでしたら、示しましたデータについて、2フィールド目の指数表示のデータについて、perlで積算データを出力させるスクリプトを、ご教授して頂けると大変助かります。
宜しくお願い致します。

補足日時:2013/07/01 20:27
    • good
    • 0
この回答へのお礼

FortranとPerlの計算結果の精度についての、詳しい説明
ありがとうございました。なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。
有難うございました。

お礼日時:2013/07/02 21:44

既に答えは書かれています. 全ての回答を見てください.

この回答への補足

osamuyさんにご教授頂いていたのですが、コマンドプロンプトの画面の図が、私のPC上では、昨日チラッと見えただけて、見えなくなってしまいました。
確か、1ライナーで書かれていたとおもいます。
出来れば、perlのスクリプトの中で while文を使い入力データを1行ずつ呼び出しては、積算させて、出力ファイルへ書かせたいのです。 
説明不足も申し訳有りません。

補足日時:2013/07/02 13:37
    • good
    • 0
この回答へのお礼

なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。
有難うございました。

お礼日時:2013/07/02 21:45

Fortranでは、どの型を使っていますか?


Perlでは、内部で倍精度実数相当の計算をしています。
Fortranで単精度を使っているなら、精度の違いが出ます。

この回答への補足

フォートランスクリプトの中身を下記に記述しました。
お恥ずかしい事に、私にはさっぱりわかりません。
ene=でエネルギーの計算をして
enecum=でエネルギーの積算を作っているようです。

open(11,file='lfall.dat')
open(12,file='enecum.dat')
open(13,file='eneind.dat')
read (11,'(2(1x,i4,4i2),2x,a3)') iyrf1,monf1,idyf1,ihrf1,
& minf1,iyrf2,monf2,idyf2,ihrf2,minf2,stnm ! period,station
read (11,'(2(1x,i4,4i2))') iyrd1,mond1,idyd1,ihrd1,
& mind1,iyrd2,mond2,idyd2,ihrd2,mind2 ! data
read (11,'(1x,3i6)') iymax,itickdy ! Ymax,Ytick-int
read (11,'(1x,3i6)') iamaxmm,iamaxnmps,idur ! legend Amax, dt
write(*,'(2(1x,i4,4i2))') iyrf1,monf1,idyf1,ihrf1,minf1,
& iyrf2,monf2,idyf2,ihrf2,minf2
write(*,'(2(1x,i4,4i2))') iyrd1,mond1,idyd1,ihrd1,mind1,
& iyrd2,mond2,idyd2,ihrd2,mind2
write(*,'(1x,2i6)') iymax,itickdy
write(*,'(1x,3i6)') iamaxmm,iamaxnmps,idur ! iamaxmm is fix
read(11,'(1x)')
c
enecum=0.0
pi=3.1415
rho=2600.0
c=3500.0
r0=20000.0
r02=r0**2
fact=0.00000001
fk=0.5
c
1 continue
read(11,1102) IY00,IM00,ID00,IH100,IMI100,IH200,IMI200,
1 LDMIN, ampx
1102 format(1x,i4,2i2,1x,2i2,1x,2i2,i5,f7.1)
if(IY00 .gt. 2020 .or. IY00 .lt. 1) go to 9000
ampxm=0.5*ampx*fact
ene=2.0*fk*pi*60.0*float(LDMIN)*rho*c*r02*ampxm**2
write(13,1210) oy,ene
enecum=enecum+ene
call time1(IY00,IM00,ID00,IH100,IMI100,oy)
write(12,1200) oy,enecum
write(*,1202) oy,enecum,ampx,ampxm,ene
1200 format(f10.4,3x,e12.5)
1210 format(f10.4,3X,e15.8)
1202 format(f10.4,3x,4e12.5)
go to 1
9000 continue
stop
end
subroutine time1(iy,im,id,ih,imin,oy)
dimension imday(12)
imday(1)=0
imday(2)=31
imday(3)=59
imday(4)=90
imday(5)=120
imday(6)=151
imday(7)=181
imday(8)=212
imday(9)=243
imday(10)=273
imday(11)=304
imday(12)=334
c
f4=0.0
m4y=mod(iy,4)
if(m4y .eq. 0) then
f4=1.0
if(iy .eq. 2000) f4=0.0
if(im .gt.2) f40=f4
endif
if40=f40
fd=(float(ih)+float(imin)/60.0)/24.0
fd=fd+float(id)
fm=float(imday(im)+if40)+fd
fm=fm/(365.0+f4)
oy=float(iy)+fm
return
end

補足日時:2013/07/01 13:37
    • good
    • 0
この回答へのお礼

FortranとPerlの計算結果の精度についての、詳しい説明
ありがとうございました。なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。
有難うございました。

お礼日時:2013/07/02 21:40

一例。



>awkとperlの計算結果は全く同じにでましたが、フォートランの結果は下記のように微妙に違ってしまう処がございます。

いわば環境依存です。
awkやperlは、OS標準ライブラリを使ってデータを読み込んだり、値を処理しているので。
計算誤差とかは別途検討する必要があります。
「perl 積算の仕方が解らない」の回答画像1

この回答への補足

#! /usr/bin/perl

open ( InFile, "< /home/tanaka/lfall.dat");
open ( OutFile, "> /home/tanaka/ene-perl.dat" );
open ( OutFileseki, "> /home/tanaka/lfall.dat.out" );
while ( <InFile> )
{
chop;
s/ +/ /g;
s/^ //;
s/\t/ /g;
@Data = split ( / /, $_ );
$Nf = @Data;


if ( $Nf == 5 )
{
( $DateA , $DateB , $DateC , $min , $kando ) = split ( / /, $_ );

if ( $DateA != '00000000' )
{
$countWC+= '1';
#print " 444 $DateA , $DateB , $DateC , $min , $kando 555\n";
$en = (2 * 0.5 * 3.1415 * 60 * $min * 2600 * 3500 * 20000 * 20000 * (0.5 * $kando * 0.00000001) * (0.5*$kando * 0.00000001));
#print "444 $en\n";
$YYYY = substr($DateA,0,4);
$MM1 = substr($DateA,4,2);
$DD = substr($DateA,6,2);
$HH = substr($DateB,0,2);
$MM = substr($DateB,2,2);
$Time = "${YYYY}-${MM1}-${DD}T${HH}:$MM";
$EN = sprintf ( "%10.5E", $en);
###printf OutFile ( "%s %s\n", $Time, $EN );

( $EN1, $EN2) = split ( /\+/, $EN);
($En1, $En2) = split ( /\./, $EN1 );

$EN3 = $EN2 + 1;
$AA = '0.';
$BB = '+';


printf OutFile ( "%s %s%s%s%s%02d\n", $Time, $AA, $En1, $En2, $BB, $EN3 );

if ( $countWC == '1' )
{
printf OutFileseki ( "%s %s%s%s%s%02d %s\n", $Time, $AA, $En1, $En2, $BB, $EN3, $countWC );
$enecum += $en;
}else{

$enecum += $en;
$enecum1 = sprintf ("%10.5E", $enecum);
($ENcum1, $ENcum2) = split ( /\+/, $enecum1);
($Encum1, $Encum2) = split ( /\./, $ENcum1 );
$ENcum3 = $ENcum2 + 1;
printf OutFileseki ( "%s %s%s%s%s%02d %s\n", $Time, $AA, $Encum1, $Encum2, $BB, $ENcum3, $countWC );
}

}
}
}
close ( InFile );
close ( OutFile );
close ( OutFileseki );

補足日時:2013/07/02 21:29
    • good
    • 0
この回答へのお礼

1ライナーperlでの積算方法有難うございました。
記憶に留めさせて頂きます。
補足に、自力で作ったperlのスクリプトを記述させて頂きました、まったくのperlの初心者でお恥ずかしいかぎりです。

お礼日時:2013/07/02 21:40

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!