Numrat

Numrat ndahen në dy lloje kryesore:

  • Numra të plotë (integers), dhe
  • Numra me presje dhjetore (floating-point numbers).

Numrat e plotë

Numrat e plotë janë numra pa komponentën decimale. Të gjithë numrat e plotë kanë madhësi të caktuar kur ruhen apo procesohen në kompjuter.

Për shembull, një bajt (byte) përbëhet nga 8 bita, ku secili bit mund ta ketë vlerën 0 ose 1.
Kështu, në një bajt (8 bit) mund të ruhen 256 (2^8^) vlera të ndryshme pozitive, prej 0 deri 255, respektivisht prej 00000000 deri 11111111 nëse e shprehim numrin në formë binare.

Nëse duhet ta ruajmë një numër pozitiv më të madh se 255, na nevojitet edhe një bajt tjetër, pra gjithsej 2 bajtë (16 bit). Në këtë rast, vlerat do të shkojnë nga 0000000000000000 deri në 1111111111111111, që në numra me bazë 10 do të jetë nga 0 deri në 65.535, pra gjithsej 65.536 vlera (2^16^).

Me katër bajtë (32 bit), diapazoni i vlerave pozitive është 0 deri në 4.294.967.295, gjithsej 4.294.967.296 vlera (232), e kështu me radhë, për çdo bajt të shtuar diapazoni i vlerave zgjerohet 256 herë.

Kur duhet të ruhen numrat e plotë negativë, biti i parë i bajtit të parë (most significant bit) shfrytëzohet si indikator: vlera 0 tregon se është vlerë pozitive, ndërsa vlera 1 se është vlerë negative, prandaj diapazoni i vlerave përgjysmohet, ashtu siç është paraqitur në tabelë.

Kur ruajmë vetëm vlera pozitive, kemi të bëjmë me unsigned integers, ndërsa për pozitive dhe negative – signed integers.
Tipet e numrave të plotë, emrat e të cilëve fillojnë me u janë tipe pa parashenjë (unsigned types), të cilat përmbajnë vetëm vlera jonegative.

Numri pas emrit tregon numrin e bitave binarë (8, 16, 32, 64) që nevojiten për ruajtjen e vlerës në memorje. Për shembull uint8 zbërthehet si: numër i plotë jonegativ që okupon 8 bit në memorje, me çka mund të reprezentohen vlerat prej 0 deri 255 (2^8^-1). Ndërsa tipi int8: numër i plotë që okupon 8 bit n memorje dhe merr vlera prej -128 (-2^7^) deri në 127 (2^7^-1).

Vlera jonegative (unsigned)

  • Bit: 8, Bajt:1, Prej: 0, Deri: 255 (2^8^-1)
  • Bit: 16, Bajt:2, Prej: 0, Deri: 65.535 (2^16^-1)
  • Bit: 32, Bajt:4, Prej: 0, Deri: 4.294.967.295 (2^32^-1)
  • Bit: 64, Bajt:8, Prej: 0, Deri: 18.446.744.073.709.551.615 (2^64^-1)

Vlera negative dhe jonegative (signed)

  • Bit: 8, Bajt:1, Prej: -128 (-2^7^), Deri: 127 (2^7^-1)
  • Bit: 16, Bajt:2, Prej: -32.768 (-2^15^), Deri: 32,767 (2^15^-1)
  • Bit: 32, Bajt:4, Prej: -2.147.483.648 (-2^31^), Deri: 2.147.483.647 (2^31^-1)
  • Bit: 64, Bajt:8, Prej: -9.223.372.036.854.775.808 (-2^63^), Deri: 9,223,372,036,854,775,807 (2^63^-1)

Go përdor tipet vijuese të numrave të plotë:

8 bitë unsigned

  • uint8 (byte)

16 bitë unsigned

  • uint16

32 bitë unsigned

  • uint32
  • uint
  • uintptr

64 bitë unsigned

  • uint64
  • uint
  • uintptr

8 bitë signed

  • int8

16 bitë signed

  • int16

32 bitë signed

  • int32 (rune)
  • int

64 bitë signed

  • int64
  • int

Tipi byte është alias i uint8, d.m.th. janë të njëjtë.

Tipi rune është alias i int32.

Madhësitë e tipeve uint, int dhe uintptr varen nga platforma, respektivisht arkitektura e procesorit; në platformat 32 bitëshe kanë madhësi 32 bitëshe, ndërsa në platformat 64 bitëshe – madhësi 64 bitëshe.
Madhësia e vlerës uintptr duhet të jetë mjaft e madhe që të ruajë bitat e painterpretuar të një adrese memorike.

Duhet të kemi parasysh që vlerat që ia japim një tipi t’i përgjigjen diapazonit të vlerave të lejuara për atë tip. Për shembull, tipi int8 mund të përmbajë vlera prej -128 deri 127. Nëse në program i japim një vlerë më të madhe se 127 apo më të vogël se -128, kompajleri do të lajmërojë gabim dhe programi nuk do të kompajlohet fare.

var muaji int8
muaji = 500

Mirëpo, nëse vlera e një tipi caktohet gjatë ekzekutimit të programit, me ç’rast kompajleri nuk e di paraprakisht vlerën, do të ndodhin situata konfuze, me ç’rast programi nuk lajmëron gabim por ndodh overflow. Për shembull, meqë vlera maksimale e int8 është 127 dhe nëse gjatë kohës së ekzekutimit merr vlerën 128, vlera rezultuese do të jetë -127! Kjo për shkak se pas arritjes së vlerës maksimale, programi fillon prej vlerës më të vogël për aq sa sa vlera e re dallon nga vlera maksimale.

Me fjalë të tjera, nëse int8 merr vlerën 150, në fakt ai do ta ketë vlerën -105 sepse 150-127=23 dhe -128+23 = -105. Ky mund të jetë burim vështirë i detektueshëm i gabimeve në rezultatet e programit sepse sistemi i kohës së ekzekutimit (runtime system) i Go nuk do të na lajmërojë për ndonjë gabim eventual.

Duhet të kemi parasysh edhe faktin që ndaj numrave të plotë të tipeve të ndryshme nuk mund të kryejmë operacione aritmetikore. Për shembull, nuk mund ta mbledhim një numër të tipit uint8 me një numër të tipit int16. Për ta realizuar operacionin e mbledhjes, të dy tipet duhet më parë t’i konvertojmë në një tip të njëjtë e më pas ta kryejmë veprimin aritmetikor. Në shembullin vijues, konvertimi bëhet në tipin int nëpërmes funksionit int(), i cili ka madhësinë 32 apo 64 bitë, në varësi prej arkitekturës, por gjithsesi është më i madh se 8 bitë (tipi uint8) dhe 16 bitë (int16).

var m uint8
m = 5
var f int16
f = 6

var n int
// kjo shkakton gabim kompajlimi
n = m + f
// prandaj variablat m dhe f duhet te konvertohen
// me funksionin int()
n = int(m) + int(f)

Numrat me presje dhjetore

Numrat me presje dhjetore (floating-point numbers) janë numra që përmbajnë komponentën decimale. Paraqitja e tyre në kompjuter është më e ndërlikuar se e numrave të plotë. Kjo bën që saktësia e këtyre numrave të jetë e kufizuar dhe rrjedhimisht edhe e llogaritjeve që bëhen me këto numra.

Në memorje, të gjitha vlerat e numrave me presje dhjetore ruhen në formatin IEEE-754.

Numrat me presje dhjetore kanë madhësi (numra bitash) të caktuar, 32 bitë (single precision) apo 64 bitë (double precision), sikurse edhe numrat e plotë.

Numrat më të mëdhenj kanë saktësi më të vogël, sepse duke qenë se kanë madhësi fikse (32/64 bitë), sa më e madhe pjesa e plotë, aq më pak shifra ngelen në dispozicion djathtas prej presjes dhjetore, me çka zvogëlohet saktësia e pjesës decimale.

Mund të përmbajnë edhe vlera jonumerike siç janë:

  • NaN (not a number)
  • Infinit pozitiv (+∞)
  • Infininit negativ (−∞)

Shembull me infinit:

package main

import (
    "fmt"
)

func main() {
    var c float32 = 0
    var d float32 = 0


    var a float32 = 24
    d = a / c
    fmt.Printf("result = %.2f \n", d)

    var b float32 = -15
    d = b / c
    fmt.Printf("result = %.2f \n", d)
}

https://play.golang.org/p/ZrzSGo-MnzA

Rezultati:

result = +Inf 
result = -Inf 

Go ka dy tipe për paraqitjen e numrave kompleksë:

  • complex64, dhe
  • complex128.

Pjesa reale dhe imagjinare e një vlere complex64 janë të dyja vlera float32, ndërsa pjesët reale dhe imagjinare të një vlere complex128 janë të dyja vlera float64.

Në Go përdoren operatorët standard vijues:

  • Mbledhja +
  • Zbritja –
  • Shumëzimi *
  • Pjestimi /
  • Modulusi %

Numrat kompleks

Numrat kompleks përbëhen nga dy pjesë:

  • pjesa reale, dhe
  • pjesa imagjinare.

Go mundëson kryerjen e drejtpërsëdrejtë të operacioneve aritmetikore ndaj numrave kompleks. Numri kompleks është 128 bitësh, float64 për pjesën reale, float64 për pjesën imagjinare, apo 64 bitësh – float32 për pjesën reale, float32 për pjesën imagjinare.

package main

import "fmt"

func main() {
    var a = 4 + 3i
    var b = 6 + 2i

    fmt.Println(a + b)
    fmt.Println(a - b)
    fmt.Println(a * b)
    fmt.Println(a / b)
}

https://play.golang.org/p/-qHz2eUw9B8

Rezultati:

(10+5i)
(-2+1i)
(18+26i)
(0.75+0.25i)

Me përdorimin e pakos “math/cmplx”, mund të kryejmë edhe veprime të tjera matematikore.

  • Abs(x complex128) float64
  • Acos(x complex128) complex128
  • Acosh(x complex128) complex128
  • Asin(x complex128) complex128
  • Asinh(x complex128) complex128
  • Atan(x complex128) complex128
  • Atanh(x complex128) complex128
  • Conj(x complex128) complex128
  • Cos(x complex128) complex128
  • Cosh(x complex128) complex128
  • Cot(x complex128) complex128
  • Exp(x complex128) complex128
  • Inf() complex128
  • IsInf(x complex128) bool
  • IsNaN(x complex128) bool
  • Log(x complex128) complex128
  • Log10(x complex128) complex128
  • NaN() complex128
  • Phase(x complex128) float64
  • Polar(x complex128) (r, θ float64)
  • Pow(x, y complex128) complex128
  • Rect(r, θ float64) complex128
  • Sin(x complex128) complex128
  • Sinh(x complex128) complex128
  • Sqrt(x complex128) complex128
  • Tan(x complex128) complex128
  • Tanh(x complex128) complex128

Rrënja katrore e numri kompleks:

package main

import (
    "fmt"
    "math/cmplx"
)

func main() {
    var a = 4 + 3i
    fmt.Println(cmplx.Sqrt(a))
}

https://play.golang.org/p/8aXVwGwWjW1

Rezultati:

(2.1213203435596424+0.7071067811865476i)

Po të përdorej funksioni Sqrt() nga pakoja math:

    var a = 4 + 3i
    fmt.Println(math.Sqrt(a))

do të lajmërohej gabimi:

cannot use a (type complex128) as type float64 in argument to math.Sqrt

Ngritja në fuqi e numrit kompleks

E marrim rezultatin e shembullit me rrënjë katrore të numrave kompleks, dhe e ngrisim në katror, për të verifikuar a e fitojmë rezultatin e pritur (4 + 3i).

package main

import (
    "fmt"
    "math/cmplx"
)

func main() {
    var a = 2.1213203435596424 + 0.7071067811865476i
    fmt.Println(cmplx.Pow(a,2 ))
}

https://play.golang.org/p/pmQpPC2q8k5

Rezultati:

(4+3.000000000000001i)

Shohim që e kemi fituar rezultatin përafërsisht të njëjtë, diferenca është 0.000000000000001 apo 10^-14^, diferencë kjo që mund të jetë e papërfillshme në varësi prej natyrës së problemit që zgjidhet.

Pasaktësia buron nga fakti e komponentet e numrit kompleks janë float64 dhe domosdo do të ndodhin përafrime të vlerave sepse këtë e imponon vetë natyra e numrave të tipit float.

Bitwise operators

Bitwise AND operator

Kryhet operacioni AND ndaj vlerave binare të dy numrave bit për bit në pozita të njëjta. Rezultati i fituar është:

  • 0 & 0 = 0
  • 0 & 1 = 0
  • 1 & 0 = 0
  • 1 & 1 = 1
package main

import (
    "fmt"
)

func main() {
    var x = 202
    var y = 107
    fmt.Printf("%4v| %08b\n", x, x)
    fmt.Printf("%4v| %08b\n", y, y)
    fmt.Println("______________")
    fmt.Printf("%4v| %08b\n", x&y, x&y)
}

https://play.golang.org/p/fE6bLqAKff5

Rezultati:

 202| 11001010
 107| 01101011
______________
  74| 01001010
    ```

### Bitwise OR operator

Kryhet operacioni **OR** ndaj vlerave binare të dy numrave  bit për bit në pozita të njëjta. Rezultati i fituar është:

* 0 | 0 = 0
* 0 | 1 = 1
* 1 | 0 = 1
* 1 | 1 = 1    

package main

import (
“fmt”
)

func main() {
var x = 202
var y = 107
fmt.Printf(“%4v| %08b\n”, x, x)
fmt.Printf(“%4v| %08b\n”, y, y)
fmt.Println(“__“)
fmt.Printf(“%4v| %08b\n”, x|y, x|y)
}

<https://play.golang.org/p/zjE0213pbil>

**Rezultati:**

202| 11001010
107| 01101011


235| 11101011

 ### Bitwise XOR operator

Kryhet operacioni **XOR** ndaj vlerave binare të dy numrave  bit për bit në pozita të njëjta. Rezultati i fituar është:

* 0 | 0 = 0
* 0 | 1 = 1
* 1 | 0 = 1
* 1 | 1 = 0

package main

import (
“fmt”
)

func main() {
var x = 202
var y = 107
fmt.Printf(“%4v| %08b\n”, x, x)
fmt.Printf(“%4v| %08b\n”, y, y)
fmt.Println(“__“)
fmt.Printf(“%4v| %08b\n”, x^y, x^y)
}

<https://play.golang.org/p/nmpYzMQdCWi>

**Rezultati:**

202| 11001010
107| 01101011


161| 10100001

### Bitwise NOT operator

Ky operator, zerot i kthen në njësha, njëshat në zero.

* ^0 = 1
* ^1 = 0

package main

import (
“fmt”
)

func main() {
var x uint8 = 123
fmt.Printf(“%4v| %08b\n”, x, x)
fmt.Println(“__“)
fmt.Printf(“%4v| %08b\n”, ^x, ^x)
}

<https://play.golang.org/p/hie6IHjoRDu>

**Rezultati:**

123| 01111011


132| 10000100

### Bitwise AND NOT operator

Biti i numrit të parë kryen operacionin AND me NOT-in e numrit të dytë.

* 0 &^ 0 = 0
* 0 &^ 1 = 0
* 1 &^ 0 = 1
* 1 &^ 1 = 0

package main

import (
“fmt”
)

func main() {
var x = 123
var y = 6
fmt.Printf(“%4v| %08b\n”, x, x)
fmt.Printf(“%4v| %08b\n”, y, y)
fmt.Println(“__“)
fmt.Printf(“%4v| %08b\n”, x&^y, x&^y)
}

<https://play.golang.org/p/c7UyUxnCKUz>

**Rezultati:**

123| 01111011
6| 00000110


121| 01111001

### Bitwise shift operators

Operatorët për zhvendosje të bitave *(bitwise shift operators)* bëjnë zhvendosjen e vlerës së një objekti binar. Operandi i majtë paraqet vlerën, ndërsa i djathti numrin e pozitave për zhvendosjen e bitave të vlerës.

package main

import (
“fmt”
)

func main() {
fmt.Printf(“%3v << %v | %3v (%08b)\n”, 2, 5, 2<<5, 2<<5) fmt.Printf(“%3v >> %v | %3v (%08b)\n”, 64, 5, 64>>5, 64>>5)
}

<https://play.golang.org/p/Rknmaievs2w>

**Rezultati:**

2 << 5 | 64 (01000000) 64 >> 5 | 2 (00000010)

Në rreshtin 8 kryhet operacioni 2<< 5, që do të thotë që vlera e numrit 2 (që në formë binare është 00000010), të zhvendoset për 5 pozita majtas. Pra, njësi do të zhvendoset 5 herë majtas, me ç'rast formohet numri binar 01000000, e që është vlera 64.

 Në rreshtin 9 kryhet veprim i kundërt: vlera e numrit 64 (01000000) do të zhvendoset djathtas, pra njëshi do të zhvendoset për pesë pozita më djathtas, me çka fitohet numri binar 00000010, që është numri 2.


### Bitwise left shift operator

package main

import (
“fmt”
)

func main() {
var x uint = 1
fmt.Printf(“%v = %08b\n”, x, x)
fmt.Println(“____________“)
var i uint
for i = 0; i < 8; i++ {
r := x << i
fmt.Printf(“%v << %v | %3v (%08b)\n”, x, i, r, r)
}
}

<https://play.golang.org/p/yIC7d1CT5NF>

**Rezultati:**

1 = 00000001


1 << 0 | 1 (00000001)
1 << 1 | 2 (00000010)
1 << 2 | 4 (00000100)
1 << 3 | 8 (00001000)
1 << 4 | 16 (00010000)
1 << 5 | 32 (00100000)
1 << 6 | 64 (01000000)
1 << 7 | 128 (10000000)

E vërejmë njëshin binar si zhvendoset nga një pozitë majtas, prej vlerës binare **00000001** deri në vlerën binare **10000000**.

### Bitwise right shift operator

package main

import (
“fmt”
)

func main() {
var x uint = 128
fmt.Printf(“%v = %08b\n”, x, x)
fmt.Println(“____________“)
var i uint
for i = 0; i < 8; i++ { r := x >> i
fmt.Printf(“%v >> %v | %3v (%08b)\n”, x, i, r, r)
}
}

<https://play.golang.org/p/Yl3YULGqkdj>

Rezultati:

128 = 10000000


128 >> 0 | 128 (10000000)
128 >> 1 | 64 (01000000)
128 >> 2 | 32 (00100000)
128 >> 3 | 16 (00010000)
128 >> 4 | 8 (00001000)
128 >> 5 | 4 (00000100)
128 >> 6 | 2 (00000010)
128 >> 7 | 1 (00000001)
“`

All Rights Reserved Theme by 404 THEME.