• No results found

2.7. Programenheter i Fortran90

N/A
N/A
Protected

Academic year: 2021

Share "2.7. Programenheter i Fortran90"

Copied!
24
0
0

Loading.... (view fulltext now)

Full text

(1)

forts. p˚a f¨oreg˚aende f¨orel¨asning:

Som ett exempel p˚a anv¨andningen av TRANSPOSE och MATMUL, skall vi studera f¨oljande program:

PROGRAM matriser IMPLICIT NONE

INTEGER, DIMENSION(2,3) :: a INTEGER, DIMENSION(3,2) :: b INTEGER, DIMENSION(2,2) :: ab

INTEGER, DIMENSION(2) :: vc = (/1,2/) INTEGER :: vbc(3)

INTEGER :: va(6) INTEGER :: i

va = (/1,2,3,4,5,6/)

a = RESHAPE(va, (/2,3/)) PRINT *, ’a:’

DO i=1,2

(2)

b = TRANSPOSE(a) DO i=1,3

PRINT *, b(i,:) END DO

PRINT *, ’ab:’

ab = MATMUL(a,b) DO i=1,2

PRINT *, ab(i,:) END DO

PRINT *, ’vbc:’

vbc = MATMUL(b,vc) PRINT *, vbc

STOP

END PROGRAM matriser

(3)

I Fortran 90 kan en vektor, eller en matris behandlas som en enkel variabel, dvs vi kan t.ex. skriva REAL, DIMENSION(10) :: a,b,c,d

...

a = b + c*d ...

som skulle motsvaras av DO–slingan

REAL a(10), b(10), c(10), d(10) ...

DO 20 i = 1,10

a(i) = b(i) + c(i)*d(i) 20 CONTINUE

...

Detta g¨or det mycket l¨attare att behandla matriser i Fortran 90. Vi kan t.ex. skriva b = 10*b och a = 0, utan att beh¨ova anv¨anda DO-slingor, om a och b ¨ar matriser eller vektorer. Logiska operatorer kan ocks˚a behandlas p˚a liknande s¨att, s˚a att om x ¨ar en vektor med reeella element, s˚a ¨ar det logiska uttrycket

(4)

Matriser och vektorer kan ocks˚a anv¨andas som argument i en inbyggd funktion, s˚a att vi t.ex. kan skriva a = sin(b), d¨ar a och b antas ha samma form (samma antal dimensioner). ¨Aven subrutinen RANDOM_NUMBER, som alstrar slumptal, kan ha ett vektorargument. Ett annat exempel ¨ar amax = MAX(a,b,c,d), d¨ar elementen i vektorn amax kommer att bildas av de st¨orsta elementen i vektorerna a, b, c och d.

Som ett exempel p˚a anv¨andningen av vektorer som argument, skall vi studera f¨oljande program, som ber¨aknar en tabell f¨or sin x inom intervallet [0, π2]:

PROGRAM sintab IMPLICIT NONE

REAL, PARAMETER :: pi = 3.1415927 INTEGER, PARAMETER :: low=1, high=10 INTEGER :: i

INTEGER, DIMENSION(low:high) :: vinkel = (/(i*10,i=0,9)/) REAL, DIMENSION(low:high) :: angle = (/(pi*i/18,i=0,9)/) REAL, DIMENSION(low:high) :: sinus

! Ber¨akna sinus sinus = SIN(angle)

! Skriv ut en sinustabell DO i = low, high

PRINT *, "sin(",vinkel(i),") = ", sinus(i) END DO

END PROGRAM sintab

(5)

Observera hur vektorerna vinkel och angle konstrueras, definitionen av parameterkonstanterna pi samt low och high, som definierar vektorernas dimensionsgr¨anser.

Matriser anv¨ands ocks˚a f¨or att beskriva transformationer mellan olika koordinatsystem. Antag, att vi roterar ett kartesiskt koordinatsystem i tre dimensioner en viss vinkel θ kring en axel, som anges av enhetsvektorn a = axi + ayj + azk. Ortsvektorn r f¨or en punkt (x, y, z) transformeras d˚a enligt r0 = Rr, d¨ar rotationsmatrisen R ¨ar en funktion av rotationsvinkeln θ och enhetsvektorn a (Rodrigues rotationsformel)1:

R(θ, a) = I − sin θA + (1 − cos θ)A2. H¨ar betecknar I en diagonal enhetsmatris och A ¨ar matrisen

A = 2

4 0 az −ay

−az 0 ax

ay −ax 0

3 5 .

Nedan visas ett program, som ber¨aknar matrisen R:

(6)

PROGRAM rotmat

! Program som ber¨aknar en tredimensionell rotationsmatris IMPLICIT NONE

REAL :: ax, ay, az, theta REAL, DIMENSION(9) :: a

REAL, DIMENSION(3,3) :: amat, rmat, imat INTEGER :: i

! Mata in axelriktningen och rotationsvinkeln PRINT *, ’Ange axelns riktning (ax, ay, az) : ’ READ *, ax, ay, az

a = (/0.,-az,ay,az,0.,-ax,-ay,ax,0./) PRINT *, ’Ange rotationsvinkeln (theta) :’

READ *, theta

! Bilda matrisen a, och skriv ut den:

amat = RESHAPE(a, (/3,3/)) PRINT *, ’Matrisen a:’

DO i=1,3

PRINT *, amat(i,:) END DO

! Konstruera identitetsmatrisen:

imat = RESHAPE((/1,0,0,0,1,0,0,0,1/),(/3,3/))

! R¨akna ut rotationsmatrisen, och skriv ut den

rmat = imat - amat*SIN(theta) + (1.-COS(theta))*MATMUL(amat,amat) PRINT *, ’Rotationsmatrisen’

DO i=1,3

PRINT *, rmat(i,:) END DO

STOP

END PROGRAM rotmat

(7)

Som en till¨ampning ber¨aknar vi matrisen f¨or en rotation 90 kring z-axeln:

Ange axelns riktning (ax, ay, az) : 0,0,1 Ange rotationsvinkeln (theta) : 1.5708 Matrisen a:

0.000000 1.00000 0.000000

-1.00000 0.000000 0.000000

0.000000 0.000000 0.000000

Rotationsmatrisen

-0.361999E-05 -1.00000 0.000000 1.00000 -0.361999E-05 0.000000

0.000000 0.000000 1.00000

(8)

2.7. Programenheter i Fortran90

I Fortran 90 kan man anv¨anda flere slag av programenheter, som i allm¨anhet inneh˚aller en begynnelsein- struktion (t.ex. PROGRAM), ett antal deklarationer, instruktioner som kan utf¨oras, samt till sist en END-sats.

Av dessa har vi redan behandlat huvudprogrammet, dessutom finns det funktioner och subrutiner (som med ett gemensamt namn kallas underprogram eller procedurer), samt moduler, ett helt nytt slag av programenheter, som inte fanns i tidigare Fortran-versioner.

Redan i det f¨orsta exemplet p˚a ett Fortran-program ingick en subrutin. Ett underprogram ¨ar en s¨arskild del av programmet, som inneh˚aller egna deklarationer. N¨ar man skriver program, ¨ar det ofta praktiskt att formulera ett delproblem som ett underprogram, som kan fels¨okas skilt f¨or sig. Uppdelningen i underprogram g¨or det l¨attare att skriva mera komplicerade program.

Det finns ocks˚a underprogram, som ing˚ar i Fortran-spr˚aket. De kallas inbyggda funktioner (eng. intrinsics), och har till uppgift att f¨orenkla programmeringen. Vi har redan st¨ott p˚a n˚agra av de matematiska rutinerna, s˚asom SQRT och EXP.

Man brukar indela underprogrammen i tv˚a kategorier, subrutiner och funktioner, beroende p˚a antalet vari- abler som ber¨aknas av programmet. Vi skall b¨orja med att studera funktionerna.

(9)

En funktionsrutin ¨ar ett program, som inleds av satsen typ FUNCTION namn (argument), d¨ar typ ( = REAL, INTEGER, etc.) deklarerar funktionens typ, och namn anger dess namn. Funktionens typ kan ocks˚a deklareras skilt. Innanf¨or parentesen anges funktionens argument, ˚atskiljda av kommatecken. Argumenten kan vara enkla variabelnamn eller uttryck. Efter FUNCTION-satsen f¨oljer ett vanligt Fortran-program, som

˚atminstone en g˚ang b¨or inneh˚alla en tilldelningssats av formen namn = uttryck, d¨ar funktionens namn tilldelas ett v¨arde. Som avslutande sats i en funktion kan man anv¨anda END FUNCTION namn, d¨ar namn betecknar funktionens namn. M˚anga kompilatorer kr¨aver dessutom att den avslutande satsen f¨oreg˚as av RETURN, liksom den sista satsen i ett huvudprogram borde vara STOP. Alla variabler i funktionsrutinen ¨ar lokala, utom de som finns i argumentlistan, eller p˚a annat s¨att (som senare omtalas) ¨overf¨ors till rutinen.

Detta betyder att man kan anv¨anda samma namn p˚a variabler som i det anropande programmet.

I Fortran 90 b¨or man ange om ett argument i argumentlistan anv¨ands f¨or inmatning eller utmatning. Detta sker med ett s¨arskilt attribut i typdeklarationen, som kallas INTENT. I en funktionsrutin kan argumenten endast vara avsedda f¨or inmatning (som vi konstaterat f¨orut), vilket kan anges t.ex. p˚a f¨oljande s¨att:

REAL FUNCTION func(x) IMPLICIT NONE

REAL, INTENT(IN) :: x

(10)

En annan viktig skillnad mellan Fortran 90 och tidigare Fortran-versioner ¨ar att man (helst) b¨or anv¨anda ett explicit gr¨anssnitt, som antyddes redan i det f¨orsta exemplet (f¨or ELF90-kompilatorn ¨ar denna konstruktion t.o.m. obligatorisk). Orsaken h¨artill ¨ar att kompilatorn borde k¨anna till vissa egenskaper hos underprogram- met, s˚asom namn, antal argument och argumenttyperna. P˚a detta s¨att kan man undvika fel i argumentens ordningsf¨oljd eller datatyper. INTERFACE-konstruktionen beh¨ovs inte f¨or inbyggda rutiner, d˚a ifr˚agavarande information ¨ar k¨and f¨or kompilatorn.

Ett s.k. interface-block f¨oreg˚as av instruktionen INTERFACE och avslutas av END INTERFACE. Den b¨or inneh˚alla typdeklarationer f¨or alla argument i funktionsanropet. Ett exempel p˚a ett dylikt gr¨anssnitt ges av f¨oljande enkla program, som anropar en funktionsrutin som adderar tv˚a tal:

PROGRAM addtest IMPLICIT NONE REAL :: a,b,c interface

FUNCTION ADD (X,Y) IMPLICIT NONE REAL :: ADD

REAL, INTENT(IN) :: X,Y END FUNCTION ADD

(11)

end interface

PRINT *, "Input a,b:"

READ *, A,B C = ADD(A,B) PRINT *, C STOP

END PROGRAM addtest FUNCTION ADD (X,Y)

IMPLICIT NONE REAL :: ADD

REAL, INTENT(IN) :: X,Y ADD = X + Y

RETURN

END FUNCTION ADD

Som ett ytterligare exempel p˚a en funktionsrutin skall vi se p˚a ett program, som ber¨aknar en fakultet:

(12)

FUNCTION FAC(n)

! Funktion som ber¨aknar n!

IMPLICIT NONE

INTEGER, INTENT(IN) :: n INTEGER :: FAC, i

! Kontrollera att n ¨ar positivt IF (n >= 0) THEN

FAC = 1

! Ber¨akna fakulteten DO i=2,n

FAC = i*FAC END DO

ELSE

FAC = 0

PRINT *, ’Illegal fakultet’

RETURN END IF RETURN

END FUNCTION fac

(13)

Som vi ser, kommer ett negativt v¨arde p˚a argumentet att leda till att fakulteten nollst¨alls, och ett felmed- delande skrivs ut.

Ett m¨ojligt huvudprogram skulle d˚a kunna vara f¨oljande, som r¨aknar ut fakulteterna f¨or alla tal mellan 0 och 10:

PROGRAM faclis

! Program som listar fakulteter mellan 0 och 10 IMPLICIT NONE

INTEGER :: i,faci interface

function fac(i) implicit none

integer, intent(in) :: i integer :: fac

end function fac end interface

DO i=0,10

! Anropa funktionsrutinen FAC:

faci=FAC(i)

PRINT *, ’Fakulteten av ’,i,’ ¨ar ’,faci

(14)

F¨ordelen med separata funktionsrutiner ¨ar att de ¨ar portabla, dvs kan anv¨andas i vilket program som helst (dock b¨or man minnas, att det inte alltid automatiskt g˚ar att anv¨anda Fortran-subrutiner i program skrivna p˚a andra spr˚ak). I ovanst˚aende exempel ¨ar funktionsrutinens namn FAC samtidigt namnet p˚a den variabel, som tilldelas funktionens v¨arde.

Det finns fall, d˚a funktionen inte beh¨over n˚agot argument. I ett s˚adant fall m˚aste man ¨and˚a uts¨atta parenteserna, t.ex.

REAL FUNCTION LN2() IMPLICIT NONE

LN2 = LOG(2.0) END

som kan anv¨andas p˚a f¨oljande s¨att: hlife = LN2()/decay (minns om man anv¨ander ELF90, att det beh¨ovs ett explicit gr¨anssnitt).

En funktionsrutin f˚ar inte f¨or¨andra n˚agot av sina argument. Vad detta kan inneb¨ara, skall vi f¨orklara med ett exempel:

(15)

( Huvudprogram ) ...

x = 1.0 a = BAD(x) ...

( Funktionsrutin )

REAL FUNCTION BAD(z) IMPLICIT NONE

REAL :: z ...

z = z + 1.0 ...

BAD = 3.5 END

Som vi ser, har funktionsrutinen efter f¨orsta anropet ¨andrat v¨ardet av variabeln x till 2.0, vilket inte ¨ar s˚a bra. Isynnerhet om anropet sker med satsen a=BAD(1.0), d¨ar argumentet ¨ar en konstant, kan det ha drastiska f¨oljder p˚a endel datorer!

(16)

Om man vill f¨or¨andra v¨ardet av n˚agot argument i argumentlistan, skall man inte anv¨anda en funktions- rutin, utan ist¨allet en subrutin. En subrutin ¨ar ett program, som inleds av satsen SUBROUTINE namn (argumentlista). Observera, att subrutinens namn inte typdeklareras. Argumentlistan f¨oljer samma regler som f¨or en funktionsrutin. Vanligen brukar man skilja mellan invariabler, som inte f¨or¨andras av subrutinen, och utvariabler, som ber¨aknas av subrutinen. En subrutin beh¨over inte ha argument. I s˚adant fall beh¨over parenteserna inte uts¨attas, i motsats till vad som g¨aller funktionsrutiner.

En subrutin avslutas p˚a samma s¨att som en funktionsrutin antingen av en RETURN-sats eller END SUBROUTINE-sats, som flyttar kontrollen tillbaka till det anropande programmet. Anropet sker med en sats av formen CALL namn (argumentlista), d¨ar namn ¨ar subrutinens namn, och argumentlista inneh˚aller (de verkliga) in- och utvariablernas namn, ˚atskiljda av kommatecken.

Som vi tidigare konstaterat, kan argumenten f¨or en subrutin anv¨andas b˚ade f¨or inmatning och utmatning.

I Fortran 90 anges detta med INTENT-attributet. I en subrutin med fem argument a,b,c,d,e , av vilka de tre f¨orsta anger invariabler och de tv˚a sista utvariabler, kan typdeklarationerna se ut p˚a f¨oljande s¨att:

SUBROUTINE sub(a,b,c,d,e) IMPLICIT NONE

REAL, INTENT(IN) :: a,b,c REAL, INTENT(OUT) :: d,e ...

(17)

Observera, att INTENT-attributet endast kan anv¨andas i underprogrammet, men inte i det anropande programmet! INTENT-attributet kan ha tre olika former:

– INTENT(IN) anger att ifr˚agavarande argument endast ¨overf¨or information till underprogrammet, och att dess v¨arde s˚alunda inte f˚ar f¨or¨andras,

– INTENT(OUT) anger att argumentet endast ¨overf¨or information fr˚an underprogrammet till det anropande programmet. Argumentet har s˚aledes inte n˚agot best¨amt v¨arde d˚a underprogrammet startas, och m˚aste d¨arf¨or ges ett v¨arde av rutinen,

– INTENT(INOUT) anger att argumentet kan anv¨andas f¨or att ¨overf¨ora information b˚ade till och fr˚an underprogrammet.

Vi skall studera ett litet programexempel (utan gr¨anssnitt), som visar vikten av att anv¨anda INTENT- attributet:

PROGRAM intent_test IMPLICIT NONE

INTEGER :: x=2, y=3, v

(18)

PRINT *, "u =",u," och x =",x END PROGRAM intent_test

SUBROUTINE sub(a,b,c) IMPLICIT NONE

INTEGER :: a,b,c a = b*c

END SUBROUTINE sub

Som vi ser, kommer det f¨orsta anropet av subroutinen sub att ¨andra v¨ardet av argumentet a. Det verkliga argumentet ¨ar i detta fall u, som ¨ar en parameterkonstant! I det andra anropet av samma rutin ber¨aknas produkten av y och v, men v har inte givits n˚agot v¨arde, och ¨ar s˚aledes odefinierad!

Om argumentdeklarationen i subrutinen skulle ¨andras till INTEGER, INTENT(IN) :: a,b

INTEGER, INTENT(OUT) :: c

s˚a skulle detta leda till ett kompileringsfel, eftersom subrutinen f¨ors¨oker f¨or¨andra v¨ardet av a. Om argu- mentdeklarationen ˚a andra sidan skulle ¨andras till

INTEGER, INTENT(IN) :: b,c INTEGER, INTENT(OUT) :: a

(19)

skulle man kanske inte f˚a ett kompileringsfel, men s¨akert ett exekveringsfel, p˚a grund av man f¨ors¨oker ¨andra v¨ardet av en konstant.

Som ett exempel p˚a en subrutin skall vi studera ett program, som konverterar r¨atvinkliga koordinater till pol¨ara koordinater i planet:

SUBROUTINE POLAR(xkor, ykor, r, phi) IMPLICIT NONE

REAL, INTENT(IN) :: xkor, ykor REAL, INTENT(OUT) :: r, phi

r = SQRT(xkor*xkor + ykor*ykor) phi = ATAN2(ykor,xkor)

END

Den inbyggda funktionen ATAN2(Y,X) ber¨aknar arcus tangenten f¨or f¨orh˚allandet mellan de tv˚a ar- gumenten f¨or en vinkel inom intervallet [−π, +π]. Subrutinen kan anropas t.ex. med satsen CALL POLAR(x,y,r,v).

(20)

Argumentlistans l¨angd ¨ar i allm¨anhet begr¨ansad, och l˚anga argumentlistor leder ofta till programmeringsfel, om de ofta skall upprepas vid anrop av subrutinen. Ist¨allet f¨or att ¨overf¨ora data via argumentlistor, anv¨ands i FORTRAN 77 den s.k. COMMON-satsen (som ersatts av de mera praktiska moduler i Fortran 90, som vi senare skall beskriva).

Lokala variabler bevaras inte alltid mellan tv˚a anrop av en subrutin. Om man ¨onskar bevara t.ex. v¨ardet av n˚agra konstanter, som t.ex. bara ber¨aknas en g˚ang anv¨ands SAVE-attributet. Som exempel skall vi se p˚a f¨oljande subrutin:

SUBROUTINE TEST(x,y,z) IMPLICIT NONE

REAL, INTENT(IN) :: x,y REAL, INTENT(OUT) :: z INTEGER, save :: callnr ...

callnr = callnr + 1

PRINT *, ’Anrop nr ’,callnr RETURN

END SUBROUTINE TEST

(21)

Om man inte skulle ha anv¨ant SAVE i denna subrutin, skulle utskriften p˚a endel datorer alltid vara Anrop nr 1.

En subrutin kan anv¨anda namnet p˚a en annan subrutin, eller funktionsrutin, som argument, om det deklar- eras med attributet EXTERNAL (denna sats anv¨ands ocks˚a i huvudprogrammet f¨or att deklarera det verkliga argumentnamnet). Observera dock, att EXTERNAL inte fungerar med ELF90-kompilatorn, d¨ar man ist¨allet m˚aste anv¨anda ett explicit gr¨anssnitt. Om argumentet syftar p˚a en inbyggd funktion, anv¨ands ist¨allet satsen INTRINSIC. Som ett exempel p˚a anv¨andningen skall vi se p˚a f¨oljande subrutin, som anv¨ands f¨or att rita en enkel funktionsgraf p˚a sk¨armen med hj¨alp av tecknen + och *:

SUBROUTINE PLOT(FUNC,X,FMAX,FMIN) IMPLICIT NONE

REAL, EXTERNAL :: FUNC

REAL, INTENT(IN) :: X, FMAX, FMIN

CHARACTER (LEN=1) :: PLUS="+",BLANK=" ",STAR="*"

INTEGER :: IC,K

IC = 50*(FUNC(X)-FMIN)/(FMAX-FMIN)

(22)

Denna rutin kan t.ex. anv¨andas p˚a f¨oljande s¨att:

PROGRAM sinplot

! Program f¨or att rita en sinuskurva IMPLICIT NONE

REAL, INTRINSIC :: SIN

REAL :: SMAX=1., SMIN=-1., PI=3.1416, xi INTEGER :: i

interface

SUBROUTINE PLOT(FNC,A,B,C) IMPLICIT NONE

REAL, external :: fnc

REAL, INTENT(IN) :: A, B, C END SUBROUTINE plot

end interface DO i=1,21

xi = pi*(i-1.)/10.

CALL PLOT(SIN,xi,SMAX,SMIN) END DO

STOP

END PROGRAM sinplot

(23)

Namnet p˚a en vektor eller matris kan ¨overf¨oras till en subrutin via argumentlistan. Men om en subrutin t.ex. inleds av f¨oljande satser:

SUBROUTINE PROG(a,b,c) IMPLICIT NONE

REAL, INTENT (IN) :: a(100), b(100), c(100)

s˚a betyder det att man ocks˚a i det anropande programmet borde reservera samma utrymme f¨or de verkliga variablerna.

F¨or att g¨ora rutinen mera portabel, kan man anv¨anda justerbara dimensioner, som ing˚ar i argumentlistan:

SUBROUTINE PROG(a,b,c,na,nb,nc) IMPLICIT NONE

INTEGER, INTENT(IN) :: na, nb, nc

REAL, INTENT(IN) :: a(na), b(nb), c(nc)

Till subrutinen kan d˚a de verkliga dimensionerna ¨overf¨oras via CALL-satsen i det anropande programmet.

(24)

Samma metod kan ocks˚a anv¨andas f¨or att ¨overf¨ora dimensionerna f¨or en matris till en subrutin. En kom- plikation orsakas dock av att matriser lagras kolumnvis. I huvudprogrammet deklareras t.ex. matrisens fysiska dimension, medan vi i verkligheten behandlar en matris med mindre (logisk) dimension. B˚ada dessa dimensioner b¨or d˚a ¨overf¨oras till subrutinen. En subrutin f¨or att l¨osa ett ekvationssystem med Gauss’

elimineringsmetod skulle kunna b¨orja p˚a f¨oljande s¨att (NP betecknar den fysiska dimensionen):

SUBROUTINE GAUSS(A,Y,X,N,NP) IMPLICIT NONE

REAL, INTENT(IN) :: A(NP,NP), Y(N) REAL, INTENT(OUT) :: X(N)

INTEGER, INTENT(IN) :: N INTEGER, INTENT(IN) :: NP

F¨or att g¨ora det enklare att ¨overf¨ora vektorer och matriser till underprogram kan i Fortran 90 dessu- tom anv¨andas s.k. antagna m¨onster i deklarationen, t.ex. REAL, DIMENSION (:,:), INTENT(IN) ::

A, f¨orutsatt att ett explicit gr¨anssnitt anv¨ands i det anropande programmet, f¨orutom en normal explicit deklaration av matrisen A.

References

Related documents

[r]

Att leva med DMT2 gav upphov till flera olika upplevelser såsom kontroll, att inte bli definierad av diabetes, behov av stöd, ansvar, skuld och rädsla.. Rädsla är

För att sjuksköterskan ska kunna ge patienten stöd, anser vi att det är viktigt att förstå patienters upplevelser av att leva med diabetes.. Diabetes uppstår när kroppens

Om du har klagomål på vår behandling av dina personuppgifter har du rätt att inge klagomål till tillsynsmyndigheten Datainspektionen.

• Smoking and SE alleles are associated with strong interaction regarding risk of developing anti-CCP + RA. • Gene-gene interaction between SE and PTPN22 alleles regarding risk

Lektorn lefde alldeles för mycket för sina böcker och sina » skrifverier » ; han ville bara få vara i fred, och det var derför han aldrig kommit sig för att taga tyglarne i

Den egna insulinproduktionen räcker då inte längre till: man går ned i vikt och får kanske syror i urinen (något som sällan förekommer vid

Det är också en tendens att de patienterna som inte har en indikation på recepten har större följsamhet om man tittar procentmässigt, men det är inte heller statistiskt