2017-07-20 3 views
-1

化学記号のリストを読んでいます。 118個の要素があるので、select case構成は119のケースを有する。これを行うより良い方法はありますか?いくつかの要素は、C,Ca,Cd,Coなどの同じ文字で始まるので、A3変数の代わりに3つのA1変数を読み取ると、処理がやや楽になる場合があります。一般的にFortranで化学記号を読む

program case_test 
implicit none 

character(len=3) :: input 
integer   :: i 
real    :: mass 

write(*,*) "Give me a symbol" 

read(*,"(A3)") input 

select case (input) 
    case("H") 
    mass = 1.008 
    case("He") 
    mass = 4.003 
! 116 other checks 
    case default 
    write(*,*) "Unknown element ", input 
    stop 
end select 

write(*,*) "atom mass = ", mass 
end program case_test 
+4

私は複雑さのためのあなたのメートル法がここに何であるか分かりません。コードの行?読みやすさ?最終的に118種類の2文字の文字列に対して118種類の異なるパラメータを指定する必要があります。 – Ross

+0

読みやすさは一つの懸念事項です。ちょうど 'case'構造は考えるのは簡単ですが、もっと速く、より読み易い方法があります。私は自分自身で思いつくことができません。 – Kurzd

答えて

1

私が選択CASEを好きですが、これはまっすぐもっとだ...

MODULE Element_Definintions 
IMPLICIT NONE 

PUBLIC 

INTEGER, PARAMETER, PUBLIC :: Max_Elements = 118 

TYPE Elements_Type 
    character(len=3) :: Name 
    integer   :: i 
    real    :: mass 
END TYPE Elements_Type 

TYPE(Elements_Type), DIMENSION(Max_Elements), PUBLIC :: Elements 

CONTAINS 

SUBROUTINE Init_Elements 
IMPLICIT NONE 

Element(1).Name = "H" 
Element(1).Num = 1 
Element(1).Mass = 1.008 

Element(2).Name = "He" 
Element(2).Num = 2 
Element(2).Mass = 4.008 

!... 
Element(118).Name = "" 

RETURN 
END SUBROUTINE Init_Elements 

エンドモジュールElement_Definintionsその後

プログラム...

program case_test 
USE Element_Definintions 
implicit none 
character(len=3) :: input 
LOGICAL   :: Found = .FALSE. 

CALL Init_Elements() 

write(*,*) "Give me a symbol" 

read(*,"(A3)") input 

DO I = 1, Max_Elements 
    IF(Input(1:LEN_TRIM(Input)) == Element(I).Name(1:LEN_TRIM(Element(I).Name)) THEN 
    FOUND= .TRUE. 
    EXIT 
    ELSE 
    CYCLE 
    ENDIF 
ENDDO 

IF(Found) THEN 
    write(*,*) 'atom mass of "',Element(I).Name,'" = ', mass 
ELSE 
    write(*,*) 'Unknown element "', input,'"' 
ENDIF 

END program case_test 
+0

検索の実行頻度に応じて、名前をアルファベット順にソートし、バイナリ検索を使用して一致するレコードを検索することを検討します。それ以外の場合は、名前とインデックスを関連付けるハッシュテーブルを使用すると、検索パフォーマンスが大幅に向上する可能性があります。パフォーマンスが問題であるかどうかを確認するためにアプリケーションをプロファイリングするまでは、どちらにも言及しないでください。それでも、必要に応じて最適化の余地があります。 – arclight

2

小さくない、長すぎないテキストに収まる、要素記号の小さな有限集合(私は最後の計数で118と考える)があります文字列。 Fortranはテキスト処理のための最良の言語ではありません(私はPerlとSNOBOLがそれに対抗するようにします...)しかし、現代のFortranは少し改善しています。

次のコードに基づいていくつかの前提があります。まず、大文字と小文字を混在させて要素シンボルを入力することを期待します。大文字小文字を修正することはできますが、この例では、ユーザー入力の最初の文字が大文字ではなく、2番目の文字が空白または小文字でない場合、エラーをスローすることにしました。これは、Fortran 95の言語に追加されたverify組み込み関数を使用して行われます(これは文字通り初めて使用したときのものです)。

intrinsicは、1より大きい文字列の中で部分文字列の最初の一致の開始位置を指定します。一致しない場合は0を返します。

elblob文字列には、すべての要素シンボルがアンダースコアで区切られています。単一文字要素は、character(len=2)変数に一致する末尾のスペースを保持します。 elblobの前に2つのアスタリスクが付いているので、すべての要素が3で割り切れる文字から開始します。これは、原子番号について知っているものを利用する魔法の愚かなビットです.1から118までの範囲を完全に埋めるユニークで逐次的な整数です。

elseekの最初の文字がスペースでないことを保証するために、恐らく問題ではないもう一つのビットは、adjustl()の使用です。 Fortranのread()の仕組みのせいではないかもしれませんが、私は妄想的ですので、そこに入れてください。最悪の場合は何もしないで数サイクルを燃やすことです。それを取り出して何が起こるかを見てください。

stray '_'と '*'を忘れないようにユーザー入力を確認することで、要素シンボルが正しく一致し、index()によって返された一致位置を実際の原子番号に分割することができます3つ。カーボンの検索文字列はFortranの固定長文字列の効果である「C」ではなく「C」であるため、誤って一致することはありません。 elseekcharacter(len=:), allocatableと定義されている場合、問題が発生する可能性がありますが、ダミーの古い固定長のスペースが埋め込まれた文字列を使用することによって、ダムの古い動作を使用することができます。

!> Return an element's atomic number based on its symbol. 
program elements 
    use iso_fortran_env, only: input_unit, output_unit 
    implicit none 

    character(len=*), parameter :: alpha_u = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 
    character(len=*), parameter :: alpha_l = 'abcdefghijklmnopqrstuvwxyz' 

    character(len=*), parameter :: elblob =        & 
    '**H _He_Li_Be_B _C _N _O _F _Ne_Na_Mg_Al_Si_P _S _Cl_Ar_K _Ca_Sc_' & 
// 'Ti_V _Cr_Mn_Fe_Co_Ni_Cu_Zn_Ga_Ge_As_Se_Br_Kr_Rb_Sr_Y _Zr_Nb_Mo_' & 
// 'Tc_Ru_Rh_Pd_Ag_Cd_In_Sn_Sb_Te_I _Xe_Cs_Ba_La_Ce_Pr_Nd_Pm_Sm_Eu_' & 
// 'Gd_Tb_Dy_Ho_Er_Tm_Yb_Lu_Hf_Ta_W _Re_Os_Ir_Pt_Au_Hg_Tl_Pb_Bi_Po_' & 
// 'At_Rn_Fr_Ra_Ac_Th_Pa_U _Np_Pu_Am_Cm_Bk_Cf_Es_Fm_Md_No_Lr_Rf_Db_' & 
// 'Sg_Bh_Hs_Mt_Ds_Rg_Cn_Nh_Fl_Mc_Lv_Ts_Og' 

    character(len=2) :: elseek 
    character(len=1) :: c 
    integer :: atomic_number 

404 format("Sorry, I couldn't find ", '"', A, '"') 
200 format("The element ", A, " has an atomic number of ", I0) 
500 format('"', A, '" must be ', A, ' case letter') 

    continue 

    write(output_unit, '(A)') "Give me an element's symbol "   & 
     // "(like H or Na)" 

    read(input_unit, '(A2)') elseek 

    ! Left-justify; eliminates any leading space 
    ! (Q: is leading space even possible?) 
    elseek = adjustl(elseek) 

    c = elseek(1:1) 
    if (verify(c, alpha_u) > 0) then 
     write(output_unit, 500) c, 'an upper' 
     stop(1) 
    end if 

    c = elseek(2:2) 
    if (verify(c, alpha_l // ' ') > 0) then 
     write(output_unit, 500) c, 'a lower' 
     stop(2) 
    end if 

    atomic_number = index(elblob, elseek) 
    if (atomic_number < 1) then 
     write(output_unit, 404) elseek 
    else 
     atomic_number = atomic_number/3 
     write(output_unit, 200) elseek, atomic_number 
    end if 

end program elements 

とにかく、私はこのすべてを30秒間テストしました。安全上重要なものには使用しないでください。これが宿題のためのものであれば、コードを読んで理解し、それをあなた自身のものとして書き直して、Turnitinにフラグを立てないようにしてください。

これは最も堅牢なソリューションではありませんが、短くてシンプルで、書かれた要件を満たしています。ハッシュテーブル、検索ツリー、または文字列より複雑なデータ構造は必要ありません。それはFORTRAN77の下で動作するためにそれを愚かにすることはあまりありませんが、その方法は狂気です...

関連する問題