- ベストアンサー
Perlで積算の仕方がわからない
- フォートランで作られたデータをperlで作り直そうとしています。perlの中で値の計算まではできましたが、2番目のフィールドの積算方法がわかりません。
- awkでの積算方法は`awk '{SUM += $2;printf("%s %10.4e", $1, SUM)}'`ですが、perlではどのようにすれば良いのでしょうか?
- また、awkとperlの計算結果は同じですが、フォートランの結果は微妙に異なっています。なぜでしょうか?
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
#2補足について。 この内容だと、Fortranでは単精度で処理されています。 参照: http://www.nag-j.co.jp/fortran/FI_17.html#AUTOTOC_17_3 実装にもよりますが、Cで言えば、float相当です。 http://ja.wikipedia.org/wiki/%E5%8D%98%E7%B2%BE%E5%BA%A6 にあるように、有効桁は、10進で7桁程度です。 Perlの内部ではCで言えば、double相当の精度で計算しています。 http://ja.wikipedia.org/wiki/%E5%80%8D%E7%B2%BE%E5%BA%A6 にあるように、有効桁は、10進で15桁程度です。 違いが出ているのは、7桁目です。 これは、単精度にとっては精度ぎりぎりの桁なので、誤差が出る箇所です。 対し、倍精度にとっては、まだ余裕のある桁です。 この差が、集計結果の違いに出ているのだと思われます。
その他の回答 (3)
- Tacosan
- ベストアンサー率23% (3656/15482)
既に答えは書かれています. 全ての回答を見てください.
お礼
なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。 有難うございました。
補足
osamuyさんにご教授頂いていたのですが、コマンドプロンプトの画面の図が、私のPC上では、昨日チラッと見えただけて、見えなくなってしまいました。 確か、1ライナーで書かれていたとおもいます。 出来れば、perlのスクリプトの中で while文を使い入力データを1行ずつ呼び出しては、積算させて、出力ファイルへ書かせたいのです。 説明不足も申し訳有りません。
- kmee
- ベストアンサー率55% (1857/3366)
Fortranでは、どの型を使っていますか? Perlでは、内部で倍精度実数相当の計算をしています。 Fortranで単精度を使っているなら、精度の違いが出ます。
お礼
FortranとPerlの計算結果の精度についての、詳しい説明 ありがとうございました。なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。 有難うございました。
補足
フォートランスクリプトの中身を下記に記述しました。 お恥ずかしい事に、私にはさっぱりわかりません。 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
- osamuy
- ベストアンサー率42% (1231/2878)
一例。 >awkとperlの計算結果は全く同じにでましたが、フォートランの結果は下記のように微妙に違ってしまう処がございます。 いわば環境依存です。 awkやperlは、OS標準ライブラリを使ってデータを読み込んだり、値を処理しているので。 計算誤差とかは別途検討する必要があります。
お礼
1ライナーperlでの積算方法有難うございました。 記憶に留めさせて頂きます。 補足に、自力で作ったperlのスクリプトを記述させて頂きました、まったくのperlの初心者でお恥ずかしいかぎりです。
補足
#! /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 );
お礼
FortranとPerlの計算結果の精度についての、詳しい説明 ありがとうございました。なんとか、自力でperlで積算を求めるスクリプトを書く事ができました。 有難うございました。
補足
詳細な説明有難うございました。 より良い知識を得る事が出来き、フォートランとperlの違いが少し解りました。 安心してperlへ切り替えたいと思います。 では、御存じでしたら、示しましたデータについて、2フィールド目の指数表示のデータについて、perlで積算データを出力させるスクリプトを、ご教授して頂けると大変助かります。 宜しくお願い致します。