Hva er den eksplisitte forskjellen mellom Fortran intents (inn, ut, INOUT)?

stemmer
15

Etter å ha søkt en stund i bøker, her på Stackoverflow og på generell nettet, har jeg funnet ut at det er vanskelig å finne en grei forklaring til de reelle forskjellene mellom Fortran argument hensikter. Slik jeg har forstått det, er dette:

  • intent(in) - Selve argumentet er kopiert til dummy argument ved oppføring.
  • intent(out) - Blindargumentpunktene til selve argument (de begge peke til det samme sted i minnet).
  • intent(inout) - dummy argumentet er skapt lokalt, og deretter kopiert til selve argumentet når prosedyren er ferdig.

Hvis min forståelse er riktig, så jeg ønsker også å vite hvorfor en gang ønsker å bruke intent(out), siden det intent(inout)krever mindre arbeid (ingen kopiering av data).

Publisert på 18/06/2009 klokken 09:01
kilden bruker
På andre språk...                            


3 svar

stemmer
6
  • intent(in)- ser ut som pasning fra verdi (og endringer av dette er ikke reflektert i utenfor kode), men er i virkeligheten pass ved henvisning og endre det er forbudt av kompilatoren. Men det kan endres likevel.
  • intent(out) - pass eller annen måte ved henvisning, faktisk en retur argument
  • intent(inout) - pass ved referanse, normal-parameteren inn / ut.

Bruk intent(out)hvis er er vanlig ut, for å dokumentere din design. Bryr seg ikke for svært lite ytelsesgevinst hvis noen. (Kommentarene tyder på det er ingen som intent(in)er teknisk også passere som referanse.)

Svarte 18/06/2009 kl. 09:07
kilden bruker

stemmer
20

Hensikter er bare hint for kompilatoren, og du kan kaste denne informasjonen bort og bryter den. Hensikter finnes nesten utelukkende for å sørge for at du bare gjøre det du har planlagt å gjøre i en subrutine. En kompilator kan velge å stole på deg og optimalisere noe.

Dette betyr at intent(in)det ikke er forbi verdi. Du kan fortsatt overskrive den opprinnelige verdien.

program xxxx  
    integer i  
    i = 9  
    call sub(i)  
    print*,i ! will print 7 on all compilers I checked  
end  
subroutine sub(i)  
    integer,intent(in) :: i  
    call sub2(i)  
end  
subroutine sub2(i)  
    implicit none  
    integer i  
    i = 7  ! This works since the "intent" information was lost.  
end

program xxxx  
    integer i  
    i = 9  
    call sub(i)  
end  
subroutine sub(i)  
    integer,intent(out) :: i  
    call sub2(i)  
end  
subroutine sub2(i)  
    implicit none   
    integer i  
    print*,i ! will print 9 on all compilers I checked, even though intent was "out" above.  
end  
Svarte 07/01/2010 kl. 23:59
kilden bruker

stemmer
1

Det er ikke klart om deler av OP spørsmål faktisk ble besvart. I tillegg er sikkert det synes å være mye forvirring og ulike feil i de påfølgende svar / diskusjoner som kan ha nytte av noen avklaringer.

A) OP 'spørsmål Re

"Så jeg ønsker også å vite hvorfor en gang ønsker å bruke hensikt (ut), siden hensikten (inout) krever mindre arbeid (ingen kopiering av data)."

kanskje ikke har besvart, eller i det minste for direkte / riktig.

Først, for å være klar de Intentattributtene har minst to formål: "safety / hygiene", og "indirekte performance" problemer (ikke "direkte performance" problemer).

1) Sikkerhet / Hygiene: Å bistå i å produsere "safe / fornuftig" kode med redusert mulighet til å "rote ting" opp. Dermed kan en Intent (I) ikke overskrives (minst lokalt, eller "globalt" under noen omstendigheter, se nedenfor).

Tilsvarende Intent (Out) krever at Arg bli tildelt en "eksplisitt svar", og dermed bidra til å redusere "søppel" resultater.

For eksempel, i løsning av kanskje det vanligste problemet i beregningsorientert matematikk, det vil si den såkalte "Ax = b problem", den "direkte resultat / svar" man er ute etter er verdiene for vektoren x. De bør være Intent (Ut) for å sikre x er tildelt en "eksplisitt" svar. Hvis x ble erklært som, si, Intent (InOut) eller "nei Intent", deretter Fortran ville tildele x noen "standardverdier" (sannsynligvis "null er" i Debug mode, men sannsynlig "søppel" i versjon modus, er alt som er i minne på args pekerposisjonen), og hvis brukeren ikke deretter tildele de riktige verdiene til x eksplisitt, vil den returnere "søppel". Intent (Out) vil "minne / force" for brukeren å tilordne verdier eksplisitt til x, og dermed unngår denne typen "(utilsiktet) søppel".

I løpet av oppløsningsprosessen, ville man (nesten helt sikkert) produserer den inverse av matrisen A. brukeren kan ønske å returnere den inverse til den anrop s / r i stedet for A, i hvilket tilfelle A bør være Intent (InOut).

Alternativt kan brukeren ønske å sikre at ingen endringer er gjort i matrisen A og vektoren b, i hvilket tilfelle de vil bli erklært Intent (I), og dermed sikre at kritiske verdier ikke blir overskrevet.

2 a) "Indirekte Performance" (og "global sikkerhet / hygiene"): Selv om hensikter er ikke direkte for å påvirke ytelsen, gjør de det indirekte. Spesielt, visse typer optimaliserings, og spesielt Fortran Pure og elementær-konstruksjoner, kan produsere mye bedre ytelse. Disse innstillingene vanligvis krever alle args å ha sin Intent uttalte eksplisitt.

Grovt sett, hvis kompilatoren vet på forhånd hensikten er av alle Vars, så det kan optimalisere og "dumhet check" koden med større letthet og effektivitet.

Avgjørende, hvis man bruker Pure osv konstruksjoner, da, med stor sannsynlighet, vil det være en "form for global sikkerhet / hygiene" også, siden Pure / Elemental s / p s kan bare kalle andre Pure / Elemental s / p og så en kan ikke komme på en situasjon av den typen som er angitt i "The Glazer Guy" eksempel.

For eksempel, hvis IG1- () er deklarert som Pure, så Sub2 () må også bli erklært som Pure, og da vil det være nødvendig å erklære Intents på alle nivåer, og så "søppel ut" produsert i "The Glazer Guy "eksempel ikke kunne skje. Det vil si at koden vil være:

Pure subroutine sub_P(i)
    integer,intent(in) :: i
    call sub2_P(i)
end  subroutine sub_P

Pure subroutine sub2_P(i)
    implicit none
!        integer i          ! not permitted to omit Intent in a Pure s/p
    integer,intent(in) :: i
    i = 7   ! This WILL NOT WORK/HAPPEN, since Pure obviates the possibility of omitting Intent, and Intent(In) prohibits assignment ... so "i" remains "safe".
end  subroutine sub2_P

... på kompilering, vil dette gi noe sånt

"|| Feil: Dummy argument 'i' med forsett (IN) i variable definisjon sammenheng (tilordning) ved (1) |"

Selvfølgelig SUB2 trenger ikke være Pure ha jeg erklært som Intent (I), som igjen vil gi "sikkerhet / hygiene" man er ute etter.

Legg merke til at selv om jeg ble erklært Intent (InOut) ville det fortsatt ikke med Pure-tallet. Det er:

Pure subroutine sub_P(i)
    integer,intent(in) :: i
    call sub2_P(i)
end  subroutine sub_P

Pure subroutine sub2_P(i)
    implicit none
    integer,intent(inOut) :: i
    i = 7   ! This WILL NOT WORK, since Pure obviates the possibility of "mixing" Intent's.
end  subroutine sub2_P

... på kompilering, vil dette gi noe sånt

"|| Feil: Dummy argument 'i' med forsett (IN) i variable definisjon sammenheng (faktisk argument for å INTENT = OUT / INOUT') ved (1) |"

Dermed vil streng eller bred tillit til Pure / Elemental konstruksjoner sikre (for det meste) "global sikkerhet / hygiene".

Det vil ikke være mulig å bruke Pure / Elemental etc i alle tilfeller (f.eks mange blandet språkinnstillinger, eller når stole på eksterne libs utenfor din kontroll, etc).

Likevel, konsekvent bruk av hensikter, og når det er mulig Pure etc, vil produsere mye nytte, og eliminere mye sorg.

Man kan bare komme inn i vanen med å erklære hensikter overalt hele tiden når det er mulig, enten Pure eller ikke ... det er den anbefalte kodepraksis.

... dette bringer også i forgrunnen en annen årsak til eksistensen av både Intent (InOut) og Intent (Out), siden Pure er må ha alle Arg hensikt uttalte, vil det være noen args som er ute bare, mens andre er InOut ( dvs. at det ville være vanskelig å ha Pure er uten hver av In, InOut, og ut hensikter).

2 b) OP kommentarer forventer "ytelsesforbedringer 'siden ingen kopiering er nødvendig' indikerer en misforståelse av Fortran og sin omfattende bruk av pass ved referanse. Vedtatt av referanse midler, i hovedsak, er bare pekere nødvendig, og faktisk ofte bare pekeren til det første element i et array (pluss noen skjult litt matrise informasjon) som kreves.

Faktisk kan noen innsikt bli tilbudt ved å vurdere "gamle dager" (f.eks Fortran IV, 77, etc), når du passerer en rekke kan ha blitt kodet som følger:

Real*8 A(1000)

Call Sub(A)

Subroutine Sub(A)

Real*8 A(1) ! this was workable since Fortran only passes the pointer/by ref to the first element of A(1000)
                ! modern Fortran may well throw a bounds check warning

I moderne Fortran, den "tilsvarende" er å erklære A som ekte (DP) A (:) i s / r (selv om strengt tatt er det ulike innstillinger som kommer fra å passere tabellens grenser og erklære eksplisitt med grensene, men at ville en lang digresjon for en annen dag).

Det vil si, ikke Fortran ikke passerer verdi, eller "lage kopier" for args / Dummy vars. A () i kall s / r er "samme A" som brukes i s / r (Selvfølgelig, i s / r, kunne man lage en kopi av A () eller hva som ville skape ekstra arbeid / plassbehov, men det er en annen sak).

Det er av denne grunn først og fremst at hensikten er ikke direkte påvirke ytelsen til en stor grad, selv for stort utvalg Arg osv

B) Når det gjelder "passerer Value" forvirring: Selv om de ulike svar ovenfor bekrefter at bruk Intent er "ikke passerer verdi", kan det være nyttig å avklare saken.

Det kan hjelpe å endre ordlyden til "Intent alltid passerer referanse". Dette er ikke det samme som "ikke passerer verdi", og det er en viktig finesse. Spesielt ikke bare er Intents "ByRef", Intent kan hindre pasning fra verdi.

Selv om det er spesielle / mye mer kompleks innstillinger (f.eks blandet språk Fortran DLL osv) hvor mye ytterligere diskusjon er nødvendig, for det meste av "standard Fortran", er args vedtatt av Ref. En demonstrasjon av denne "Intent finesse" kan sees i en enkel forlengelse av "Glazer Gutter" eksempel som:

subroutine sub(i)
    integer, intent(in) :: i, j
    integer, value     :: iV, jV
    call sub2(i)
    call sub3(i, j, jV, iV)
end
subroutine sub2(i)
    implicit none
    integer i
    i = 7  ! This works since the "intent" information was lost.
end
subroutine sub3(i, j, jV, iV)
    implicit none
    integer, value, Intent(In)          :: i    ! This will work, since passed in byRef, but used locally as byVal
    integer, value, Intent(InOut)       :: j    ! This will FAIL, since ByVal/ByRef collision with calling s/r,
                                                ! ||Error: VALUE attribute conflicts with INTENT(INOUT) attribute at (1)|
    integer, value, Intent(InOut)       :: iV   ! This will FAIL, since ByVal/ByRef collision with calling s/r,
                                                ! ... in spite of "byVal" in calling s/r
                                                ! ||Error: VALUE attribute conflicts with INTENT(INOUT) attribute at (1)|
    integer, value, Intent(Out)         :: jV   ! This will FAIL, since ByVal/ByRef collision with calling s/r
                                                ! ... in spite of "byVal" in calling s/r
                                                ! ||Error: VALUE attribute conflicts with INTENT(OUT) attribute at (1)|
    jV = -7
    iV = 7
end

Det vil si, noe med en "Out" aspekt til det må være "ByRef" (minst i normale innstillinger), siden kall s / r forventer "ByRef". Dermed, selv om alle s / r er erklære args som "verdi", de "ByVal" bare lokalt (igjen i standardinnstillingene). Så vil ethvert forsøk fra såkalte s / r for å returnere en Arg som er erklært som verdi med noen form for Out Intent, FAIL på grunn av "kollisjon" av de passerende stiler.

Hvis det må være "ut" eller "InOut" og "verdi", så kan man ikke bruke Intent: som er noe mer enn bare å si at "det ikke er forbi verdi".

Svarte 31/12/2016 kl. 08:49
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more