fortran66のブログ

fortran について書きます。

F-22 パイロット訓練ソフトウェア開発者募集!

jobs.boeing.com

米空軍のボーイング F-22 ステルス戦闘機パイロット訓練ソフトウェア開発者が募集されているようです。

プログラミング言語

C, C++, Ada, Fortran, OpenGL programming languages. Qt user interface framework, Perl, GLStudio

なお応募には米国市民権wと軍機を守れる安全審査許可が必要なようです。

Virtual 紙テープ 

ネットを彷徨していたところ、Virtual 紙テープパンチ機「ミスター・パンチ」なるプログラムを公開されているページに行き当たりました。とても面白いので紹介いたします。

ミスター・パンチ

同サイトには、Virtual 計算尺も公開されており、アナログ計算もできます。

      PROGRAM FORMAT
      IMPLICIT NONE
      READ 100
100   FORMAT(20H                    )
      PRINT 100
      END PROGRAM FORMAT


f:id:fortran66:20170510022745p:plain

NASA が Fortran コード高速化に賞金!

www.bbc.com
www.nasa.gov



BBC によると NASA流体力学Fortran プログラム FUN3D を賞金を懸けて高速化をしようとしているそうです。参加資格は 18 歳以上のアメリカ市民権保持者。十~一万倍くらいの高速化を希望しているようです。NvidiaGPU を積んだスパコンをプレアデスでの実行とのこと。賞金総額は五万五千ドルの模様。

Spigot algorithm による e の計算

J.Borwein & K.Devlin 著 『数学を生み出す魔法のるつぼ』二章にある Spigot algorithm を使って e を1桁づつ求める計算をしてみます。

Spigot algorithm は直訳すれば、「蛇口算法」となりますが、邦訳では「こつこつアルゴリズム」になっています。しまりの悪い蛇口からポタポタと水滴が垂れるイメージでしょうか?

(邦訳はアマゾンのレビューでもクソミソに書かれているように機械翻訳のような訳文で、用語の誤りや何を言ってるのか意味不明なところが多数あります。)

ソース・プログラム

クラスを使って OO 風にしましたが、冗長になってしまいました。1桁づつ数字が求まることを強調するため、1桁毎に出力しています。advance ='no' にすると改行は避けられますが、buffering されてしまうので、flush で強制出力しています。

なお4バイト整数の配列を使っているので、一回に1桁ではなく、8桁まで求められるんじゃないかと思います。

Intel Fortran compiler のバグで parameterized derived type のサイズが正しく取れないために、associate で配列をポインタで別名化することが出来ませんでした。

    module m_e
      implicit none
      private
      public :: t_e
      type :: t_e(n)
        private  
        integer, len:: n
        integer :: m(n + 1)
      contains
        procedure, public :: next, init 
      end type t_e
    contains
      subroutine init(this)
        class(t_e(*)), intent(in out) :: this
        this%m = 1
      end subroutine init
      
      impure subroutine next(this, k)
        class(t_e(*)), intent(in out) :: this
        integer, intent(in out) :: k
        integer :: i, l
        associate (n => this%n, m=> this%m) ! m => this%m: bug
        this%m = this%m * 10
        do i = n + 1, 1, -1
          l = mod(this%m(i) + k  ,  i + 1)
          k =    (this%m(i) + k) / (i + 1)
          this%m(i) = l
        end do
        end associate
      end subroutine next
    end module m_e
    
    program Console16
      use m_e 
      implicit none
      integer :: i, n = 10000, k = 0
      type(t_e(:)), allocatable :: e
      allocate(t_e(n)::e)
      call e%init()
      write(6, '(a)', advance='no') '2.'
      flush(6)
      do i = 1, n - 1
        call e%next(k)  
        write(6, '(i1)', advance='no') k
        flush(6)
      end do
      print *
      stop
    end program Console16

実行結果

一万桁求めてみました。千桁目までは他の結果と比較して確かめました。

2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035402123407849819334321068170121005627880235193033224745015853904730419957777093503660416997329725088687696640355570716226844716256079882651787134195124665201030592123667719432527867539855894489697096409754591856956380236370162112047742722836489613422516445078182442352948636372141740238893441247963574370263755294448337998016125492278509257782562092622648326277933386566481627725164019105900491644998289315056604725802778631864155195653244258698294695930801915298721172556347546396447910145904090586298496791287406870504895858671747985466775757320568128845920541334053922000113786300945560688166740016984205580403363795376452030402432256613527836951177883863874439662532249850654995886234281899707733276171783928034946501434558897071942586398772754710962953741521115136835062752602326484728703920764310059584116612054529703023647254929666938115137322753645098889031360205724817658511806303644281231496550704751025446501172721155519486685080036853228183152196003735625279449515828418829478761085263981395599006737648292244375287184624578036192981971399147564488262603903381441823262515097482798777996437308997038886778227138360577297882412561190717663946507063304527954661855096666185664709711344474016070462621568071748187784437143698821855967095910259686200235371858874856965220005031173439207321139080329363447972735595527734907178379342163701205005451326383544000186323991490705479778056697853358048966906295119432473099587655236812859041383241160722602998330535370876138939639177957454016137223618789365260538155841587186925538606164779834025435128439612946035291332594279490433729908573158029095863138268329147711639633709240031689458636060645845925126994655724839186564209752685082307544254599376917041977780085362730941710163434907696423722294352366125572508814779223151974778060569672538017180776360346245927877846585065605078084421152969752189087401966090665180351650179250461950136658543663271254963990854914420001457476081930221206602433009641270489439039717719518069908699860663658323227870937650226014929101151717763594460202324930028040186772391028809786660565118326004368850881715723866984224220102495055188169480322100251542649463981287367765892768816359831247788652014117411091360116499507662907794364600585194199856016264790761532103872755712699251827568798930276176114616254935649590379804583818232336861201624373656984670378585330527583333793990752166069238053369887956513728559388349989470741618155012539706464817194670834819721448889879067650379590366967249499254527903372963616265897603949857674139735944102374432970935547798262961459144293645142861715858733974679189757121195618738578364475844842355558105002561149239151889309946342841393608038309166281881150371528496705974162562823609216807515017772538740256425347087908913729172282861151591568372524163077225440633787593105982676094420326192428531701878177296023541306067213604600038966109364709514141718577701418060644363681546444005331608778314317444081194942297559931401188868331483280270655383300469329011574414756313999722170380461709289457909627166226074071874997535921275608441473782330327033016823719364800217328573493594756433412994302485023573221459784328264142168487872167336701061509424345698440187331281010794512722373788612605816566805371439612788873252737389039289050686532413806279602593038772769778379286840932536588073398845721874602100531148335132385004782716937621800490479559795929059165547050577751430817511269898518840871856402603530558373783242292418562564425502267215598027401261797192804713960068916382866527700975276706977703643926022437284184088325184877047263844037953016690546593746161932384036389313136432713768884102681121989127522305625675625470172508634976536728860596675274086862740791285657699631378975303466061666980421826772456053066077389962421834085988207186468262321508028828635974683965435885668550377313129658797581050121491620765676995065971534476347032085321560367482860837865680307306265763346977429563464371670939719306087696349532884683361303882943104080029687386911706666614680001512114344225602387447432525076938707777519329994213727721125884360871583483562696166198057252661220679754062106208064988291845439530152998209250300549825704339055357016865312052649561485724925738620691740369521353373253166634546658859728665945113644137033139367211856955395210845840724432383558606310680696492485123263269951460359603729725319836842336390463213671011619282171115028280160448805880238203198149309636959673583274202498824568494127386056649135252670604623445054922758115170931492187959271800194096886698683703730220047531433818109270803001720593553052070070607223399946399057131158709963577735902719628506114651483752620956534671329002599439766311454590268589897911583709341937044115512192011716488056694593813118384376562062784631049034629395002945834116482411496975832601180073169943739350696629571241027323913874175492307186245454322203955273529524024590380574450289224688628533654221381572213116328811205214648980518009202471939171055539011394331668151582884368760696110250517100739276238555338627255353883096067164466237092264680967125406186950214317621166814009759528149390722260111268115310838731761732323526360583817315103459573653822353499293582283685100781088463434998351840445170427018938199424341009057537625776757111809008816418331920196262341628816652137471732547772778348877436651882875215668571950637193656539038944936642176400312152787022236646363575550356557694888654950027085392361710550213114741374410613444554419210133617299628569489919336918472947858072915608851039678195942983318648075608367955149663644896559294818785178403877332624705194505041984774201418394773120281588684570729054405751060128525805659470304683634459265255213700806875200959345360731622611872817392807462309468536782310609792159936001994623799343421068781349734695924646975250624695861690917857397659519939299399556754271465491045686070209901260681870498417807917392407194599632306025470790177452751318680998228473086076653686685551646770291133682756310722334672611370549079536583453863719623585631261838715677411873852772292259474337378569553845624680101390572787101651296663676445187246565373040244368414081448873295784734849000301947788802046032466084287535184836495919508288832320652212810419044804724794929134228495197002260131043006241071797150279343326340799596053144605323048852897291765987601666781193793237245385720960758227717848336161358261289622611812945592746276713779448758675365754486140761193112595851265575973457301533364263076798544338576171533346232527057200530398828949903425956623297578248873502925916682589445689465599265845476269452878051650172067478541788798227680653665064191097343452887833862172615626958265447820567298775642632532159429441803994321700009054265076309558846589517170914760743713689331946909098190450129030709956622662030318264936573369841955577696378762491885286568660760056602560544571133728684020557441603083705231224258722343885412317948138855007568938112493538631863528708379984569261998179452336408742959118074745341955142035172618420084550917084568236820089773945584267921427347756087964427920270831215015640634134161716644806981548376449157390012121704154787259199894382536495051477137939914720521952907939613762110723849429061635760459623125350606853765142311534966568371511660422079639446662116325515772907097847315627827759878813649195125748332879377157145909106484164267830994972367442017586226940215940792448054125536043131799269673915754241929660731239376354213923061787675395871143610408940996608947141834069836299367536262154524729846421375289107988438130609555262272083751862983706678722443019579379378607210725427728907173285487437435578196651171661833088112912024520404868220007234403502544820283425418788465360259150644527165770004452109773558589762265548494162171498953238342160011406295071849042778925855274303522139683567901807640604213830730877446017084268827226117718084266433365178000217190344923426426629226145600433738386833555534345300426481847398921562708609565062934040526494324426144566592129122564889356965500915430642613425266847259491431423939884543248632746184284665598533231221046625989014171210344608427161661900125719587079321756969854401339762209674945418540711844643394699016269835160784892451405894094639526780735457970030705116368251948770118976400282764841416058720618418529718915401968825328930914966534575357142731848201638464483249903788606900807270932767312758196656394114896171683298045513972950668760474091542042842999354102582911350224169076943166857424252250902693903481485645130306992519959043638402842926741257342244776558417788617173726546208549829449894678735092958165263207225899236876845701782303809656788311228930580914057261086588484587310165815116753332767488701482916741970151255978257270740643180860142814902414678047232759768426963393577354293018673943971638861176420900406866339885684168100387238921448317607011668450388721236436704331409115573328018297798873659091665961240202177855885487617616198937079438005666336488436508914480557103976521469602766258359905198704230017946553678
続行するには何かキーを押してください . . .

ケーリー=ディクソン構成二通り

背景

実数・複素数四元数八元数

複素数 a+bi を2つの実数(a,b)の組と考えて、その加減乗除の演算規則が適当に与えられている代数系を考えることが出来ます。ここで、a,b に実数じゃなくて複素数を突っ込んだらどうなるかと考えると、うまく適当な演算規則をあたえると、矛盾なく定義が出来て超複素数というべきもの(四元数)が作れることが知られています。この作り方はケーリー=ディクソン構成と言われるものです。

ケーリー=ディクソン構成
積 :(a,b)(c,d):=(ac-~db, da+b~c)
共役:~(a,b):=(~a,-b)

四元数は単なる空想の産物ではなく、自然界では量子力学のスピンのところでパウリのスピン行列として登場してきます。四元数は行列表現があることから推察できるように、交換則が成り立ちません。

調子に乗って進むともう一段階進むと、八元数というものも定義出来て加減乗除の演算規則が作れます。しかし、八元数では結合則も成立せず、だんだんと手足を切り取られてダルマさんになってしまい、この先は加減乗除可能な16元数というものは作れなくなってしまいます。

ここで、それぞれの数のノルムを考えると、実数ベクトルのノルムを保存するのは回転群、複素数のベクトルのノルムを保存するのはユニタリー群、四元数ベクトルのノルムを保存するのは斜交群(シンプレクティック群)、八元数のノルムを保存するのは例外群(特にG2)とリー群の分類と関係しています。

commutator・associator

交換則からの逸脱具合は、commutator(交換子積) [A,B]=AB-BA、結合則からの逸脱具合は、associator [X,Y,Z]=(XY)Z-X(YZ) で表現されます。 associator は三項演算子になっています。ところで交換子積は非結合積なので、[X,Y,Z]=[[X,Y],Z]-[X,[Y,Z]]となりますが、Jacobiの恒等式によりこの値は[Y,[X,Z]]と分かります。これが交換子積の非結合具合となります。

八元数では、前述のとおり一般には結合則は満たさないのですが、部分的に二つの元の演算では結合則が成り立ちます。すなわち[x,x,y]=[x,y,x]=[y,x,x]=0 となります。

プログラム

ケーリー=ディクソン構成は、実数からはじまって同じアルゴリズムが三回反復されて、複素数四元数八元数が作られます。Fortran90/95 の場合、派生型を使って下から組み上げていく形で順々に定義してゆき、最後に演算子オーバーロード二項演算子などを定義する形が素直だと思いますが、ほぼ同じ内容の繰り返しが必要となります。これに対し、Fortran2003/08では無制限ポインタを使って、上側から下側の実数に向かってゆく再帰的な定義で反復なしに1回の記述で定義することが出来ます。(ただし無制限多態ポインタ使用のため見苦しいプログラムになります。)

以下に両方式のプログラムを示します。ここで簡単のため、加減乗除のうち加算と乗算のみを定義しいます。減算と除算は、加算と乗算から定義されるのでここでは省きました。


ソースプログラム・出力結果

Fortran90/95
 (533.0000,0.0000000E+00)
   533.0000      0.0000000E+00 cc
   533.0000      0.0000000E+00  0.0000000E+00  0.0000000E+00
  -6.000000       13.00000       32.00000       1.000000       50.00000
  -1.000000      -12.00000       67.00000

   204.0000      0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
  0.0000000E+00  0.0000000E+00  0.0000000E+00
続行するには何かキーを押してください . . .
    module m_comp
      implicit none
      interface operator(+) 
        procedure :: plus_r, plus_c, plus_h, plus_o
      end interface
      interface operator(*) 
        procedure :: prod_r, prod_c, prod_h, prod_o
      end interface
      interface operator(-) 
        procedure :: minus_r, minus_c, minus_h, minus_o
      end interface
      interface operator(.cc.) 
        procedure :: conj_r, conj_c, conj_h, conj_o
      end interface
      interface conj 
        procedure :: conj_r, conj_c, conj_h, conj_o
      end interface
      type :: t_r
        real :: r
      end type t_r    

      type :: t_c
        type(t_r) :: re, im
      end type t_c    

      type :: t_h
        type(t_c) :: re, im
      end type t_h    

      type :: t_o
        type(t_h) :: re, im
      end type t_o    

    contains  
    
      type(t_r) function conj_r(a) result(c)
        type(t_r), intent(in) :: a
        c%r = a%r 
      end function conj_r
      type(t_r) function minus_r(a) result(c)
        type(t_r), intent(in) :: a
        c%r = -a%r 
      end function minus_r
      type(t_r) function plus_r(a, b) result(c)
        type(t_r), intent(in) :: a, b
        c%r = a%r + b%r
      end function plus_r
      type(t_r) function prod_r(a, b) result(c)
        type (t_r), intent(in) :: a, b
        c%r = a%r * b%r
      end function prod_r

      type(t_c) function conj_c(a) result(c)
        type(t_c), intent(in) :: a
        c%re =  a%re 
        c%im = -a%im 
      end function conj_c
      type(t_c) function minus_c(a) result(c)
        type(t_c), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_c
      type(t_c) function plus_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function plus_c
      type(t_c) function prod_c(a, b) result(c)
        type (t_c), intent(in) :: a, b
        c%re = a%re * b%re + (-b%im * a%im)
        c%im = b%im * a%re +   a%im * b%re
      end function prod_c
      type(t_c) function to_c(r0, r1)
        real, intent(in) :: r0, r1
        to_c = t_c(t_r(r0), t_r(r1))
      end function to_c  
      
      type(t_h) function conj_h(a) result(c)
        type(t_h), intent(in) :: a
        c%re = .cc.a%re 
        c%im =    -a%im 
      end function conj_h
      type(t_h) function minus_h(a) result(c)
        type(t_h), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_h
      type(t_h) function plus_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function plus_h
      type(t_h) function prod_h(a, b) result(c)
        type (t_h), intent(in) :: a, b
        c%re = a%re * b%re + (-(.cc.b%im) * a%im)
        c%im = b%im * a%re + a%im * (.cc.b%re)
      end function prod_h
      type(t_h) function to_h(r0, r1, r2, r3)
        real, intent(in) :: r0, r1, r2, r3
        to_h = t_h(to_c(r0, r1), to_c(r2, r3))
      end function to_h 
      
      type(t_o) function conj_o(a) result(c)
        type(t_o), intent(in) :: a
        c%re = .cc.a%re 
        c%im =    -a%im 
      end function conj_o
      type(t_o) function minus_o(a) result(c)
        type(t_o), intent(in) :: a
        c%re = -a%re 
        c%im = -a%im 
      end function minus_o
      type(t_o) function plus_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c%re = a%re + b%re
        c%im = a%im + b%im
      end function plus_o
      type(t_o) function prod_o(a, b) result(c)
        type (t_o), intent(in) :: a, b
        c%re = a%re * b%re + (-(.cc.b%im) * a%im)
        c%im = b%im * a%re + a%im * (.cc.b%re)
      end function prod_o
      type(t_o) function to_o(r0, r1, r2, r3, r4, r5, r6, r7)
        real, intent(in) :: r0, r1, r2, r3, r4, r5, r6, r7
        to_o = t_o(to_h(r0, r1, r2, r3), to_h(r4, r5, r6, r7))
      end function to_o  
    end module m_comp
    
    program supercomplex
      use m_comp
      implicit none
      complex :: a, b, c
      type(t_r) :: ra, rb, rc
      type(t_c) :: ca, cb, cc 
      type(t_h) :: ha, hb, hc 
      type(t_o) :: oa, ob, oc 
      ra = t_r(2.0)
      rb = t_r(3.0)
      
      a = (2.0, 3.0)
      b = (4.0, 5.0)
      c = a * b
      ca = to_c(2.0, 3.0)
      cb = to_c(4.0, 5.0)
      cc = ca * cb
      print *, conjg(c) * c
      print *, (.cc.cc) * cc, 'cc'
      
      ha = t_h(ca, to_c(0.0, 0.0))
      hb = t_h(cb, to_c(0.0, 0.0))
      hc = ha * hb
      print *, (.cc. hc) * hc
      hc = to_h(0.0, 0.0, 0.0, 0.0)

      oa = to_o(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)
      ob = t_o(hb, hc) 
      oc = oa * ob
      print *, oc
      print *
      print *, (.cc. oa) * oa
    end program supercomplex
Fortan2003/08

ケーリー=ディクソン構成を再帰的に実現しますが、再帰の出発値に当たるのは、組を作る数の型として intrinsic な real 型が現れた時になります。 intrinsic な real 型は継承できないなので、real 型を他の派生型と同等に扱うには、無制限多態ポインタ class(*) を使う必要があります。しかし class(*) は代入するにも出力するにも何するにも select type で型を確定する必要があるので厄介です。このため出力用のユーザー定義ルーチンも用意しておきました。(楽な抜け道があるのかもしれませんが、私の今の知識ではこれで精一杯)

   -3.000000
   -5.000000       10.00000
 (-5.000000,10.00000)
   -60.00000       12.00000       30.00000       24.00000
   -60.00000      -12.00000      -30.00000      -24.00000
   -1000.000      -1200.000      -1400.000      -1600.000       608.0000
   400.0000       600.0000       800.0000
   -1000.000      -1200.000      -1400.000      -1600.000       608.0000
   400.0000       600.0000       800.0000

   -1000.000       1264.000       1488.000       1712.000      -104.0000
  -288.0000      -472.0000      -656.0000
   -1000.000       1264.000       1488.000       1712.000      -104.0000
  -288.0000      -472.0000      -656.0000

   -1000.000      -1184.000      -1368.000      -1552.000      -104.0000
   528.0000       752.0000       976.0000
   -1000.000      -1184.000      -1368.000      -1552.000      -104.0000
   528.0000       752.0000       976.0000

    8489664.      0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
  0.0000000E+00  0.0000000E+00  0.0000000E+00

    350.0000      -390.0000      -198.0000      -186.0000       218.0000
  -254.0000      -222.0000      -270.0000
    350.0000      -42.00000      -158.0000      -470.0000       218.0000
  -206.0000      -190.0000      -294.0000
続行するには何かキーを押してください . . .

ここではノルムが実部のみになること、また八元数の非結合性や部分結合性等を確認しています。

module m_sc
  implicit none
  
  type :: t_sc
    class(*), allocatable :: re, im
  contains
    generic :: assignment(=) => assign_sc
    generic :: operator(-) => minus 
    generic :: operator(.cc.) => conj
    generic :: operator(+) => plus
    generic :: operator(*) => prod    
    procedure :: minus, plus, conj, prod
    generic :: write(formatted) => pr_sc
    procedure :: assign_sc, pr_sc
  end type t_sc
  
contains
  
  recursive function minus(a) result(c)
    class(t_sc), intent(in) :: a
    class(t_sc), allocatable:: c
    allocate(t_sc::c)
    select type (re => a%re)
    type is (real)
      c%re = -re
    class is (t_sc)
      allocate(c%re, source = -re)  
      select type (im => a%im)
      class is (t_sc)
      allocate(c%im, source = -im)  
      end select    
    end select
  end function minus 
  recursive function conj(a) result(c)
    class(t_sc), intent(in) :: a
    class(t_sc), allocatable:: c
    allocate(t_sc::c)
    select type (re => a%re)
    type is (real)
      c%re = re
    class is (t_sc)
      allocate(c%re, source = conj(re))  
      select type (im => a%im)
      class is (t_sc)
      allocate(c%im, source = -im)  
      end select    
    end select
  end function conj

  recursive function plus(a, b) result(c)
    class(t_sc), intent(in) :: a, b
    class(t_sc), allocatable:: c
    allocate(t_sc::c)
    select type (ar => a%re)
    type is (real)
      select type (br => b%re)
      type is (real)
      c%re = ar + br
      end select
    class is (t_sc)
      select type (br => b%re)
      class is (t_sc)
      allocate(c%re, source = ar + br)
      end select
      select type (ai => a%im)
      class is (t_sc)
      select type (bi => b%im)
      class is (t_sc)
      allocate(c%im, source = ai + bi)
      end select
      end select
    end select
  end function plus
  
  recursive function prod(a, b) result(c)
    class(t_sc), intent(in) :: a, b
    class(t_sc), allocatable:: c
    allocate(t_sc::c)
    select type (ar => a%re)
    type is (real)
      select type (br => b%re)
      type is (real)
      c%re = ar * br
      end select
    class is (t_sc)
      select type (br => b%re)
      class is (t_sc)
      select type (ai => a%im)
      class is (t_sc)
      select type (bi => b%im)
      class is (t_sc)
      allocate(c%re, source = ar * br + conj(-bi) * ai)
      allocate(c%im, source = bi * ar + ai * conj(br) )
      end select
      end select
      end select
    end select
  end function prod
  
  subroutine assign_sc(c, a)
    class(t_sc), intent(out) :: c
    real, intent(in) :: a(:)
    allocate(t_sc::c%re)
    allocate(t_sc::c%im)
    select case (size(a))
    case (1) ! R
      allocate(c%re, source = a(1))  
    case (2) ! C    
      select type (cr => c%re)
      type is (t_sc)
        cr = a(1:1)
      end select  
      select type (ci => c%im)
        type is (t_sc)  
        ci = a(2:2)
      end select
    case (4) ! H    
      select type (cr => c%re)
      type is (t_sc)
        cr = a(1:2)
      end select  
      select type (ci => c%im)
        type is (t_sc)  
        ci = a(3:4)
      end select
    case (8) ! O    
      select type (cr => c%re)
      type is (t_sc)
        cr = a(1:4)
      end select  
      select type (ci => c%im)
        type is (t_sc)  
        ci = a(5:8)
      end select
    case default
      stop 'assign_c: error!'
    end select    
  end subroutine assign_sc
  
  recursive subroutine pr_sc(dtv, unit, iotype, vlist, iostat, iomsg)
    class(t_sc), intent(in) :: dtv
    integer, intent(in) :: unit
    character (len = *), intent(in) :: iotype
    integer, intent(in) :: vlist(:)
    integer, intent(out) :: iostat
    character (len = *), intent(in out) :: iomsg
    select type (re => dtv%re)
    type is (real)
      write(unit, *, iostat = iostat) re
    type is (t_sc)
      call re%pr_sc(unit, iotype, vlist, iostat, iomsg)    
      select type (im => dtv%im)
      type is (t_sc)    
      call im%pr_sc(unit, iotype, vlist, iostat, iomsg)    
      end select
    end select      
  end subroutine pr_sc
end module m_sc


program hello
  use m_sc
  implicit none
  class(t_sc), allocatable :: ra, rb, rc, ca, cb, cc 
  class(t_sc), allocatable :: ha, hb, hc, oa, ob, oc, od 
  allocate(ra, rb)
  
  ra = [1.0]
  rb = [2.0]
  rc = -ra + (-rb)
  print *, rc
  
  allocate(ca, cb)
  ca = [1.0, 2.0]
  cb = [3.0, 4.0]
  cc = ca * cb
  print *, cc
  print *, (1.0, 2.0) * (3.0, 4.0)
!  print *, conj(cc)
  
  allocate(ha, hb, oa, ob)
  ha = [1.0, 2.0, 3.0, 4.0]
  hb = [5.0, 6.0, 7.0, 8.0]
  hc = ha * hb
  print *, hc
  print *, conj(hc)
  
  oa = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
  ob = [5.0, 6.0, 7.0, 8.0, -1.0, -2.0, -3.0, -4.0]
  oc = (oa * oa) * ob
  od = oa * (oa * ob)
  print *, oc
  print *, od
  print *
  oc = (oa * ob) * oa
  od = oa * (ob * oa)
  print *, oc
  print *, od
  print *
  oc = (ob * oa) * oa
  od = ob * (oa * oa)
  print *, oc
  print *, od
  print *
  print *, conj(od) * od
  print *

  oa = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
  ob = [5.0, 6.0, 7.0, 8.0, -1.0, -2.0, -3.0, -4.0]
  oc = [1.0, 1.0, 1.0, 1.0, -2.0, -2.0, -1.0, -1.0]

  print *, (oa * ob) * oc
  print *, oa * (ob * oc)    
end program Hello

a(:) は必ずしも a ならず

配列の全配列操作を記述するとき、スカラーと配列を明示的に区別するために、配列名のあとに (:) をつけることが推奨されることがありますが、文脈によって微妙に意味が違う場合もあり、また副プログラム呼び出しの引数にしたときの挙動など、コンパイラの実装にも依存するので、時には注意が必要かと思います。

特に Fortran 2003 で、allocatable 属性の配列に代入するときの挙動がそれまでのものと変わって、自動再割り付けが行われたりするので危険です。

Cray が 2005 年に出した、Fortran 2003 and Beyond という Fortran 2003 規格と Fortran 2008 規格案を紹介した文書に、いい実例が出ていたので少し変えて紹介します。

ソース・プログラム

(:) があるとたとえ全部分を指定していても部分配列となり、自動再割り付けは行われません。(文字列の場合も同様です)

    program Console6
      implicit none
      block 
        character(len = :), allocatable :: string
        allocate(character(16)::string)
        string = '0123456789abcdef'
        !
        print *, len(string), ':', string, ':' ! length = 16
        string(:) = 'pad'
        print *, len(string), ':', string, ':' ! length = 16
        string = 'short'
        print *, len(string), ':', string, ':' ! lenght =  5
      end block
      !
      print *
      !
      block
        real, allocatable :: a(:), b(:), c(:)
        allocate(a(10), b(20))
        a = 1.10
        b = 1.20
        c = a
        print *, size(c)  ! size(c) = 10
        c = b
        print *, size(c)  ! size(c) = 20
        c(:) = a(:)       ! error size-mismatch
      end block
    end program Console6

実行結果

          16 :0123456789abcdef:
          16 :pad             :
           5 :short:

          10
          20
forrtl: severe (408): fort: (2): Subscript #1 of the array A has value 11 which is greater than the upper bound of 10

Image              PC        Routine            Line        Source
libifcoremdd.dll   5A1B4138  Unknown               Unknown  Unknown
Console6.exe       00C323AF  _MAIN__                    26  Console6.f90
Console6.exe       00C327DF  Unknown               Unknown  Unknown
Console6.exe       00C3521E  Unknown               Unknown  Unknown
Console6.exe       00C35100  Unknown               Unknown  Unknown
Console6.exe       00C34FAD  Unknown               Unknown  Unknown
Console6.exe       00C35238  Unknown               Unknown  Unknown
KERNEL32.DLL       73F68744  Unknown               Unknown  Unknown
ntdll.dll          774C587D  Unknown               Unknown  Unknown
ntdll.dll          774C584D  Unknown               Unknown  Unknown
続行するには何かキーを押してください . . .