00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Numeri

Tipi numerici in Go

Go offre una vasta gamma di tipi numerici per gestire interi, numeri decimali e numeri complessi. Ogni tipo ha una dimensione precisa in bit, il che permette un controllo fine sull’utilizzo della memoria e sull’intervallo di valori rappresentabili.

Tipi interi con segno

I tipi interi con segno possono rappresentare numeri positivi e negativi:

package main

import "fmt"

func main() {
    var a int8 = 127        // 8 bit: da -128 a 127
    var b int16 = 32767     // 16 bit: da -32768 a 32767
    var c int32 = 2147483647 // 32 bit: da -2^31 a 2^31-1
    var d int64 = 9223372036854775807 // 64 bit: da -2^63 a 2^63-1

    fmt.Println(a, b, c, d)
}

Il tipo int ha una dimensione che dipende dalla piattaforma: 32 bit su sistemi a 32 bit e 64 bit su sistemi a 64 bit. Nella maggior parte dei casi, int e il tipo da utilizzare per i numeri interi:

var numero int = 42 // 32 o 64 bit a seconda della piattaforma

Tipi interi senza segno

I tipi senza segno (uint) rappresentano solo numeri positivi (e zero), con un intervallo doppio rispetto alla controparte con segno:

package main

import "fmt"

func main() {
    var a uint8 = 255       // 8 bit: da 0 a 255
    var b uint16 = 65535    // 16 bit: da 0 a 65535
    var c uint32 = 4294967295 // 32 bit: da 0 a 2^32-1
    var d uint64 = 0        // 64 bit: da 0 a 2^64-1

    fmt.Println(a, b, c, d)
}

Esiste anche il tipo uintptr, usato per memorizzare valori di puntatori come interi, utile principalmente nella programmazione di sistema.

Tipi speciali: byte e rune

Go definisce due alias importanti per i tipi interi:

package main

import "fmt"

func main() {
    // byte e un alias per uint8
    var b byte = 'A'
    fmt.Printf("byte: %c = %d\n", b, b) // A = 65

    // rune e un alias per int32
    // rappresenta un code point Unicode
    var r rune = 'Z'
    fmt.Printf("rune: %c = %d\n", r, r) // Z = 90

    // Le rune supportano caratteri Unicode
    var emoji rune = '\u2764'
    fmt.Printf("rune Unicode: %c\n", emoji)
}

Tipi floating-point

I numeri decimali (in virgola mobile) sono rappresentati da due tipi:

package main

import "fmt"

func main() {
    var x float32 = 3.14       // precisione singola (32 bit)
    var y float64 = 3.141592653589793 // precisione doppia (64 bit)

    fmt.Printf("float32: %.10f\n", x) // perde precisione dopo ~7 cifre
    fmt.Printf("float64: %.15f\n", y) // perde precisione dopo ~15 cifre
}

Il tipo float64 e il tipo predefinito per i numeri decimali e dovrebbe essere usato nella maggior parte dei casi per la sua maggiore precisione:

piGreco := 3.14159 // tipo float64 (inferito)

Attenzione alla precisione

I numeri in virgola mobile hanno problemi di precisione intrinseci alla loro rappresentazione binaria:

package main

import "fmt"

func main() {
    a := 0.1
    b := 0.2
    c := a + b

    fmt.Println(c)        // 0.30000000000000004
    fmt.Println(c == 0.3) // false!

    // Per confronti sicuri, usa una tolleranza
    const epsilon = 1e-9
    fmt.Println(c-0.3 < epsilon) // true
}

Numeri complessi

Go supporta nativamente i numeri complessi con parte reale e parte immaginaria:

package main

import (
    "fmt"
    "math/cmplx"
)

func main() {
    // Dichiarazione diretta
    var c1 complex64 = 3 + 4i
    var c2 complex128 = 5 + 12i

    // Con la funzione complex()
    c3 := complex(2.5, 7.3) // complex128

    fmt.Println(c1)           // (3+4i)
    fmt.Println(c2)           // (5+12i)
    fmt.Println(c3)           // (2.5+7.3i)

    // Estrarre parte reale e immaginaria
    fmt.Println(real(c2))     // 5
    fmt.Println(imag(c2))     // 12

    // Modulo di un numero complesso
    fmt.Println(cmplx.Abs(c2)) // 13
}

Letterali numerici

Go supporta diverse notazioni per i letterali numerici:

package main

import "fmt"

func main() {
    // Decimale
    dec := 1000000

    // Con separatore underscore (Go 1.13+)
    grande := 1_000_000
    fmt.Println(dec == grande) // true

    // Binario (prefisso 0b)
    bin := 0b1010 // 10 in decimale
    fmt.Printf("Binario: %d\n", bin)

    // Ottale (prefisso 0o)
    ott := 0o17 // 15 in decimale
    fmt.Printf("Ottale: %d\n", ott)

    // Esadecimale (prefisso 0x)
    hex := 0xFF // 255 in decimale
    fmt.Printf("Esadecimale: %d\n", hex)

    // Floating-point con esponente
    sci := 1.5e3 // 1500.0
    fmt.Printf("Scientifico: %f\n", sci)

    // Esadecimale floating-point (Go 1.13+)
    hexF := 0x1.0p10 // 1024.0
    fmt.Printf("Hex float: %f\n", hexF)
}

Operazioni aritmetiche

Go supporta le operazioni aritmetiche standard per i numeri:

package main

import "fmt"

func main() {
    a, b := 17, 5

    fmt.Println("Somma:      ", a+b)  // 22
    fmt.Println("Sottrazione:", a-b)   // 12
    fmt.Println("Prodotto:   ", a*b)   // 85
    fmt.Println("Divisione:  ", a/b)   // 3 (divisione intera!)
    fmt.Println("Resto:      ", a%b)   // 2

    // Divisione decimale: almeno un operando deve essere float
    x, y := 17.0, 5.0
    fmt.Println("Divisione decimale:", x/y) // 3.4
}

Divisione intera

Un aspetto importante: la divisione tra interi restituisce un intero, troncando la parte decimale:

package main

import "fmt"

func main() {
    fmt.Println(7 / 2)   // 3 (non 3.5!)
    fmt.Println(-7 / 2)  // -3

    // Per ottenere il risultato decimale
    fmt.Println(float64(7) / float64(2)) // 3.5
}

Il pacchetto math

Il pacchetto math della libreria standard fornisce costanti e funzioni matematiche:

package main

import (
    "fmt"
    "math"
)

func main() {
    // Costanti
    fmt.Println("Pi:", math.Pi)
    fmt.Println("E:", math.E)
    fmt.Println("MaxInt64:", math.MaxInt64)
    fmt.Println("MaxFloat64:", math.MaxFloat64)

    // Funzioni comuni
    fmt.Println("Sqrt(16):", math.Sqrt(16))     // 4
    fmt.Println("Pow(2, 10):", math.Pow(2, 10)) // 1024
    fmt.Println("Abs(-42):", math.Abs(-42))      // 42
    fmt.Println("Ceil(3.2):", math.Ceil(3.2))    // 4
    fmt.Println("Floor(3.8):", math.Floor(3.8))  // 3
    fmt.Println("Round(3.5):", math.Round(3.5))  // 4
    fmt.Println("Max(5, 9):", math.Max(5, 9))    // 9
    fmt.Println("Min(5, 9):", math.Min(5, 9))    // 5
}

Conversioni tra tipi numerici

Go richiede conversioni esplicite tra tipi numerici diversi:

package main

import "fmt"

func main() {
    var intero int = 42
    var piccolo int8 = int8(intero)    // possibile perdita di dati
    var grande int64 = int64(intero)
    var decimale float64 = float64(intero)
    var indietro int = int(decimale)   // tronca la parte decimale

    fmt.Println(piccolo, grande, decimale, indietro)

    // Attenzione all'overflow
    var x int8 = 127
    y := x + 1
    fmt.Println(y) // -128 (overflow silenzioso!)
}

Conclusione

Go offre un sistema numerico completo e preciso. I tipi interi con e senza segno permettono di scegliere la dimensione giusta per ogni esigenza. I tipi floating-point gestiscono i numeri decimali con diversi livelli di precisione. I numeri complessi sono supportati nativamente. I letterali numerici supportano diverse basi e il separatore underscore per la leggibilita. Il pacchetto math completa l’offerta con funzioni matematiche essenziali.