Boolsk algebra

I artikkelen om sammenlikningsoperatorer lærer vi at boolske variablerer variabler som bare kan ha verdiene True og False.

I artikkelen om logiske operatorer lærer vi reglene for å bruke de logiske operatorene and, or og not på boolske variabler:

True and TrueTrue
True and FalseFalse
False and TrueFalse
False and FalseFalse

True or TrueTrue
True or FalseTrue
False or TrueTrue
False or FalseFalse

not TrueFalse
not FalseTrue

Disse reglene er eksempler på boolsk algebra, det vil si regneregler for boolske variabler.

Vi skal nå presentere noen flere regneregler som gir mulighet for forenklinger og omskrivinger. Hvis a og b er boolske variabler, har vi at

a == Truea

I stedet for å skrive for eksempel if (x < 0) == True kan vi skrive if x < 0. 

a == False → not a

I stedet for å skrive for eksempel if (x < 0) == False kan vi skrive if not x < 0.

a and Truea

Hvis vi bruker operatoren and på variabelen a og en variabel som er True, er resultatet lik verdien til a. Det vil si True hvis a er True, og False hvis a er False.

a and FalseFalse

Hvis vi bruker operatoren and på variabelen a og en variabel som er False, er resultatet False, uavhengig av a.

a or TrueTrue

Hvis vi bruker operatoren or på variabelen a og en variabel som er True, er resultatet True, uavhengig av a.

a or Falsea

Hvis vi bruker operatoren or på variabelen a og en variabel som er False, er resultatet lik verdien til a. Det vil si True hvis a er True, og False hvis a er False.

not not a → a

Dobbelt bruk av not endrer ikke verdien til a.

For operatorene and og or gjelder den distributive lov vi kjenner fra matematikken. Hvis vi bruker and eller or på et uttrykk i parentes, tilsvarer det å bruke and eller or på hver verdi i parentesen.

a and (b or c) → (a and b) or (a and c)

a or (b and c) → (a or b) and (a or c)

For operatoren not gjelder imidlertid egne distributive lover.

not (a and b) → not a or not b

and skifter til or når vi bruker not på et uttrykk i parentes.

For eksempel kan uttrykket if not(x < 0 and y < x) angis som if not x < 0 or not y < x.

not (a or b) → not a and not b

or skifter til and når vi bruker not på et uttrykk i parentes.

For eksempel kan uttrykket if not(x < 0 or y < x) angis som if not x < 0 and not y < x.

Regler i boolsk algebra er lette å bevise fordi variablene bare kan ha to verdier, True og False. Vi kan bruke det som kalles uttømmende bevis, og vise at to uttrykk gir samme resultat i alle kombinasjonsmuligheter.

Eksempel 1:

Vi skal bevise at not (a and b) og not a or not b er det samme. Vi setter opp alle kombinasjonsmulighetene i en såkalt sannhetstabell:

a True True False False
b True False True False
not (a and b) not (True and True)
not TrueFalse
not (True and False)
not FalseTrue
not (False and True)
not FalseTrue
not (False and False)
not FalseTrue
not a or not b not True or not True
False or FalseFalse
not True or not False
False or TrueTrue
not False or not True
True or FalseTrue
not False or not False
True or TrueTrue

Vi ser at resultatet er likt i alle 4 tilfeller.

Siden det ikke spiller noen rolle hva som er a og hva som er b, er det strengt tatt nok å sjekke 3 tilfeller:

        • a og b er begge True.
        • Den ene av a og b er True og den andre er False.
        • a og b er begge False.

Oppgave 1:

Bevis følgende ved å sette opp sannhetstabeller:

      • a == True er det samme som a.
         
      • not (a or b) er det samme som not a and not b.

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

Logiske operatorer

I artikkelen om aritmetiske operatorer og regneoperasjoner og artikkelen om  sammenlikningsoperatorer blir vi kjent med to typer operatorer. Her skal vi møte en tredje type, logiske operatorer.

La oss si at vi har Python-kode for å lese inn et antall som må være større enn 0 og mindre enn 100. Hvis vi leser inn et ulovlig antall, skal vi få en feilmelding. Kontrollen av antallet kan vi gjøre med en ifelif-konstruksjon, som i eksempel 1.

Eksempel 1:

Koden under leser inn et antall og skriver en feilmelding hvis antallet <= 0 eller >= 100

antall = int(input("Oppgi antall: "))
if antall <= 0:  # For lavt antall
    print("Antall må være større enn 0 og mindre enn 100.")
elif antall >= 100: # For stort antall
    print("Antall må være større enn 0 og mindre enn 100.")

Vi kan imidlertid skrive koden på en enklere måte ved å slå sammen de to kontrollene av antall ved hjelp av den logiske operatoren or, slik det er vist i eksempel 2.

Eksempel 2:

Koden under gjør det samme som koden i eksempel 1, men med betingelsene antall <= 0 og antall >= 100 kjedet sammen med or.

antall = int(input("Oppgi antall: "))
if antall <= 0 or antall >= 100:  # Ulovlig antall
    print("Antall må være større enn 0 og mindre enn 100.")

Operatoren or kjeder to betingelser sammen til én, som er sann hvis minst én av betingelsene er sann, men usann hvis begge betingelsene er usanne.

Dette er oppsummert under. Her bruker vi Python-kodeordene True for sann, og False for usann.

True or TrueTrue
True or FalseTrue
False or TrueTrue
False or FalseFalse

Vi har også en logisk operator som heter and. and kjeder to betingelser sammen til én som er sann hvis begge betingelsene er sanne, men usann ellers.

True and TrueTrue
True and FalseFalse
False and TrueFalse
False and FalseFalse

Eksempel 3:

Hvis vi kjører koden under i Python, får vi skrevet ut True.

x = 3
y = 4
print( x > 0 and y > 0)

Oppgave 1:

Analyser Python-koden under og avgjør om den vil skrive ut True eller False. Sjekk så om du har rett ved å kjøre koden.

x = -3
y = 4
print( x > 0 or x < y)

Se løsningsforslag

En tredje logisk operator er not, som gjør en sann betingelse usann, og en usann betingelse sann:

not TrueFalse
not FalseTrue

True, False, or, and og not er kodeord i Python. Legg merke til at True og False skrives med stor forbokstav, mens or, and og not skrives med liten forbokstav.

I artikkelen om sammenlikningsoperatorer lærer vi at True og False kalles boolske datatyper, og vi ser her at når vi bruker or, and eller not på boolske datatyper, er resultatet også en boolsk datatype.

Prioritet

Logiske operatorer har prioritet, på samme måte som aritmetiske operatorer. 

I sammensatte uttrykk brukes operatorene i denne rekkefølgen:

    1. () Parenteser. Parenteser inni hverandre beregnes innenfra og ut.
    2. not
    3. and
    4. or

Operatorer med samme prioritet brukes fra venstre mot høyre.

Eksempel 4:

Vi skal studere i hvilken rekkefølge operatorene brukes i uttrykket:
True or not True and False

not har høyest prioritet, det første som skjer er derfor at not True blir til False:
True or False and False

Deretter er det and som har høyest prioritet, så False and False blir False:
True or False

Så er det bare or igjen, og True or False blir True:
True

Oppgave 2:

Analyser de to linjene med Python-kode under, og avgjør om de vil skrive ut True eller False. Sjekk så om du har rett ved å kjøre koden.

print(True or False and False)
print(True and False or not(False and True))

Se løsningsforslag

Samme betingelse kan ofte formuleres på flere måter.

Eksempel 5:

I eksempel 2 brukte vi koden under for å sjekke om antall var mindre eller lik 0 eller større eller lik 100:

if antall <= 0 or antall >= 100:

Her sier vi altså «Hvis antall er mindre eller lik 0 eller antall er større eller lik 100″. En annen måte å uttrykke akkurat det samme på er «Hvis ikke antall er større enn 0 og antall samtidig er mindre enn 100″, som vi kan skrive slik i Python-kode:

if not(0 < antall and antall < 100):

Slå sammen betingelser

La oss si at vi har en variabel, x, og at vi skal gjøre en forgreining hvis x er større enn 5 og samtidig mindre enn 10. Det kan vi gjøre med følgende Python-kode, der vi har to betingelser kombinert med and:

if 5 < x and x < 10:

Python lar oss imidlertid slå sammen de to betingelsene slik vi ville gjort i matematisk notasjon:

if 5 < x < 10:

Eksempel 6:

I eksempel 5 hadde vi følgende kode:

if not(0 < antall and antall < 100):

Denne koden kan vi ved å slå sammen betingelsene omforme til

if not(0 < antall < 100):

Den kompakte, matematiske notasjonen i eksempel 5 og 6 er lett å lese. Men medaljen har en bakside. Når Python treffer på et uttrykk på formen a operator b operator c, blir dette mekanisk tolket som a operator b and b operator c. Det betyr at uttrykk som er ugyldige matematisk, allikevel vil være akseptable i Python, for eksempel vil > b bli tolket som x and x > b.

Det er også viktig å være oppmerksom på at den kompakte notasjonsformen er spesiell for Python. I programmeringsspråk som C og JavaScript vil sammenslåtte betingelser bli tolket på en måte som høyst sannsynlig ikke er den vi ønsker.

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

True og False har også aritmetiske verdier i Python, True har verdien 1, og False har verdien 0. Det betyr at hvis vi skriver print(True + True), skriver Python ut 2, mens hvis vi skriver print(False + False), skriver Python ut 0.

I JavaScript skrives True og False med liten forbokstav, altså true og false. C har ikke boolske datatyper, i stedet brukes 1 som True og 0 som False.

Hvis vi i språk som C og JavaScript setter sammen uttrykk med flere sammenlikningsoperatorer, for eksempel 5 < x < 10, blir operatorene brukt fra venstre mot høyre. Resultatet av en sammenlikning er enten sann eller usann, noe som representeres med henholdsvis 1 eller 0. Denne verdien blir så brukt i neste sammenlikning.
I C eller JavaScript vil et uttrykk som 5 < 20 < 10 bli sant fordi det blir regnet ut slik:
(5 < 20) < 10 → 1 < 10 → 1
I Python blir imidlertid resultatet usant fordi det blir regnet ut slik:
 (5 < 20) and (20 < 10) → 1 and 0 → 0

Aritmetiske operatorer og regneoperasjoner

Aritmetiske operatorer

Når vi utfører regneoperasjoner i Python, for eksempel beregner 2 + 2, bruker vi aritmetiske operatorer.

Operatorene for de fire vanlige regneartene er

+ Addisjon
Subtraksjon
* Multiplikasjon
/ Divisjon

I tillegg har vi

** Eksponentiering
// Heltallsdivisjon
% Modulus

En heltallsdivisjon er en divisjon der resultatet rundes nedover til nærmeste heltall. For eksempel er 43 // 8 = 5.

Modulus er resten vi får ved heltallsdivisjon. For eksempel er 43 % 8 = 3 fordi 43 = 5 · 8 + 3.

Eksempel 1:

Vi skal bruke Python til å regne ut 5 · 32.

I editoren skriver vi

print(5 * 3**2)

Når vi kjører koden, svarer Python 45.

Oppgave 1:

Bruk Python til å regne ut 7 + 42.

Se løsningsforslag

Sammensatte uttrykk

Alle de nevnte operatorene er binære, det vil si at de opererer på to verdier av gangen, for eksempel 2 + 3 og 3 * 5. Vi kan riktignok sette opp uttrykk med flere operatorer, for eksempel 2 + 3 * 5, men operatorene brukes likevel på to verdier av gangen. Det gjøres imidlertid ikke slavisk i den rekkefølgen operatorene står, men etter en fast definert prioritering. Multiplikasjon og divisjon har for eksempel høyere prioritet enn addisjon og subtraksjon, og alt med samme prioritet gjøres fra venstre mot høyre. For eksempel:
2 + 3 * 5 → 2 + 15 → 17.
og
2 + 3 * 4 / 2 * 7 → 2 + 12 / 2 * 7 → 2 + 6 * 7 → 2 + 42 → 44.

Dette er vanlige prioriteringsregler som vi kjenner fra matematikken. Vil vi endre på prioriteringen, setter vi inn parenteser.

Oppgave 2:

Beregn 3 + (8 + 2) / 5 * 3.
Gjør først beregningen i hodet, eller med penn og papir, og sjekk så i Python om du har rett.

Se løsningsforslag

Desimaltall og desimalskilletegn

Beregner vi uttrykket 4 / 2 i Python, får vi svaret 2.0, ikke 2. Det er fordi resultatet av en divisjon i Python alltid blir regnet som et desimaltall, selv om divisjonen går opp. 

Vi legger også merke til at det er punktum, ikke komma, som er desimalskilletegn. Det er ganske standard i programmering, antakelig fordi punktum fungerer som desimalskilletegn i mange land. Det er imidlertid en feilkilde for oss som er vant med å bruke komma, for komma har en annen betydning i Python. Skriver vi for eksempel 2,3 i stedet for 2.3, tolker Python det som tallparet (2, 3).

Bruk av mellomrom

I oppgave 2 skrev vi uttrykket 3 + (8 + 2) / 5 * 3. Der brukte vi mellomrom, altså blanke tegn, rundt en del av operatorene. Det har egentlig ingen betydning for Python, om vi skriver 3+(8+2)/5*3, blir resultatet akkurat det samme. Mellomrom gjør imidlertid ofte uttrykk lettere å lese for mennesker. Pythons stilguide, PEP 8, krever ikke mellomrom, men sier at hvis vi bruker mellomrom, skal det være maksimum ett mellomromstegn av gangen, og tegnene skal brukes symmetrisk. Altså for eksempel 2 + 3, ikke 2   + 3 eller 2+ 3. PEP 8 foreslår også å bruke mellomrom til å indikere prioritet, slik som for eksempel i uttrykket fra eksempel 1, print(5 * 3**2), der vi ikke har mellomrom rundt eksponentieringsoperatoren ** for å presisere at eksponentieringen gjøres før multiplikasjonen. Det viktigste er imidlertid at uttrykkene blir lesbare.

Unære operatorer

Av og til ønsker vi å skifte fortegn på noe, og det gjør vi ved å sette et minus-tegn foran det vi skal skifte fortegn på, for eksempel -2 eller -x. Dette er egentlig bruk av en aritmetisk operator som skifter fortegn på det som følger etter. Selv om vi benytter akkurat samme symbol som ved subtraksjon, er det allikevel ikke samme operator.

Minus-tegnet vi bruker ved subtraksjon, er binært, vi bruker det altså på to verdier, for eksempel 5 - 3. Minus-tegnet vi bruker ved fortegnsskifte, er unært, vi bruker det altså på en enkelt verdi, for eksempel -3. Grunnen til at vi poengterer dette, er at de to variantene har forskjellig prioritet. Det finnes også et unært pluss, det har ingen effekt, men vi kan teknisk sett bruke det, og for eksempel skrive 3 som +3.

Prioriteringsrekkefølge

I sammensatte uttrykk brukes operatorene i denne rekkefølgen:

    1. () Parenteser. Parenteser inni hverandre beregnes innenfra og ut.
    2. ** Eksponentiering.
    3. + og – Unært pluss og minus.
    4. * og / og // og % Multiplikasjon, divisjon, heltallsdivisjon og modulus.
    5. + og – Addisjon og subtraksjon.

Operatorer med samme prioritet brukes fra venstre mot høyre.

SkjermfilmSe film om aritmetiske operatorer

Oppgave 3:

−1 opphøyd i andre er 1. Men hvis vi skriver -1**2 i Python, får vi −1 i stedet for 1. Hva er grunnen til det, og hva må vi gjøre for å få det riktig?

Se løsningsforslag

Kilder

    • Matthes A. (2019). Python Crash Course. no starch press

I mange programmeringsspråk, som C og JavaScript, brukes «hatt», altså symbolet ^, i stedet for ** for eksponentiering.