Introduction
Bienvenue, Gophers, dans ce nouveau chapitre. Dans cette section, nous allons découvrir les types numériques. Le contenu comprend les types entiers couramment utilisés, les types à virgule flottante, les types booléens, ainsi que les nombres complexes et la syntaxe des valeurs littérales introduite dans la version 1.13.
Points clés (Knowledge Points):
- Types entiers (Integer types)
- Types à virgule flottante (Floating-point types)
- Types booléens (Boolean types)
- Nombres complexes (Complex numbers)
- Syntaxe des valeurs littérales (Literal value syntax)
Entiers (Integers)
Les entiers peuvent être globalement divisés en deux catégories : les entiers non signés (unsigned integers) et les entiers signés (signed integers). Les entiers signés sont les plus largement utilisés.
Non signé (Unsigned) signifie qu'il ne peut représenter que des nombres non négatifs (0 et les nombres positifs), tandis que les nombres signés (signed) peuvent représenter à la fois les nombres négatifs et non négatifs.
Les entiers non signés peuvent être divisés en quatre tailles : 8 bits, 16 bits, 32 bits et 64 bits, représentés respectivement par uint8, uint16, uint32 et uint64. Les entiers signés correspondants sont int8, int16, int32 et int64. Le tableau suivant indique les différentes plages représentées par chaque type :
| Type | Description | Plage (Range) |
|---|---|---|
| uint8 | Entier non signé 8 bits (8-bit unsigned int) | 0 à 255 |
| int8 | Entier signé 8 bits (8-bit signed int) | -128 à 127 |
| uint16 | Entier non signé 16 bits (16-bit unsigned int) | 0 à 65535 |
| int16 | Entier signé 16 bits (16-bit signed int) | -32768 à 32767 |
| uint32 | Entier non signé 32 bits (32-bit unsigned int) | 0 à 4294967295 |
| int32 | Entier signé 32 bits (32-bit signed int) | -2147483648 à 2147483647 |
| uint64 | Entier non signé 64 bits (64-bit unsigned int) | 0 à 18446744073709551615 |
| int64 | Entier signé 64 bits (64-bit signed int) | -9223372036854775808 à 9223372036854775807 |
Prenons uint8 et int8 comme exemples. Ce sont tous deux des entiers de 8 bits et peuvent représenter 256 valeurs. Dans le type entier non signé uint8, la plage qu'il peut représenter va de 0 à 255, tandis que dans le type entier signé int8, la plage qu'il peut représenter va de -128 à 127.
En plus des 8 types ci-dessus, il existe trois autres types d'entiers spéciaux, uint, int et uintptr, où uint et int peuvent représenter différentes plages sur différentes plateformes, et uintptr est utilisé pour stocker les adresses de pointeur.
| Type | Plage (Range) the current environment is %d bits\n", unsafe.Sizeof(a)*8)
var b int8 = 125
// Use the %d placeholder in fmt.Printf to output the value of the integer
// Use the %T placeholder in fmt.Printf to output the type of the variable
fmt.Printf("The value of b is %d, and the type is %T\n", b, b)
// Integer operations
// Declare integers c and d, and calculate their sum
c, d := 2, 3
fmt.Printf("c + d = %d\n", c+d)
// 10 - 5
fmt.Printf("10 - 5 = %d\n", 10-5)
// 8 * 10
fmt.Printf("8 * 10 = %d\n", 8*10)
// Example of uintptr usage - storing an address
var ptr uintptr
x := 42
// Convert the pointer to x to uintptr
ptr = uintptr(unsafe.Pointer(&x))
fmt.Printf("The address of x stored in ptr is: %v\n", ptr)
}
After executing the program, we get the following output:
```bash
go run integer.go
The type int in the current environment is 64 bits
The value of b is 125, and the type is int8
c + d = 5
10 - 5 = 5
8 * 10 = 80
The address of x stored in ptr is: 824634818784
Explanation of the output:
The type int in the current environment is 64 bits: This line shows that theinttype on the system where the code is being run is 64 bits (or 8 bytes), indicating it is anint64. Theunsafe.Sizeof(a)returns the size of variableain bytes, and multiplying by 8 converts it to bits. This means that theinttype can hold larger integer values.The value of b is 125, and the type is int8: Here, we have declared a variablebof typeint8and assigned it the value 125. The output confirms this by showing both the value and the data type.c + d = 5,10 - 5 = 5,8 * 10 = 80: These lines showcase basic integer arithmetic operations: addition, subtraction, and multiplication. The output confirms the correct results of these calculations.The address of x stored in ptr is: 824634818784: This demonstrates howuintptrcan be used to store a memory address. We're converting a pointer to the integer variablexto auintptrtype. The actual address value will vary each time the program runs. This is an advanced use case typically found in unsafe operations and system programming.
In this file, the unsafe.Sizeof() function can be used to obtain the number of bytes occupied by the current variable type. 1 byte (byte) is equal to 8 bits, so unsafe.Sizeof()*8 can obtain the number of bits occupied by the type. From the output, we can see that the online environment is 64 bits. The actual type of int in the online environment is int64.
We can use the following command in the terminal to determine the current system architecture:
dpkg --print-architecture
amd64
Nombres à virgule flottante
Les nombres à virgule flottante représentent les nombres réels avec des parties fractionnaires en Go en utilisant deux types : float32 et float64. Le type de virgule flottante par défaut est float64.
float32 et float64 représentent différentes précisions. La précision par défaut de float64 est supérieure à celle de float32.
La norme IEEE 754 est la norme de calcul à virgule flottante la plus largement utilisée dans les ordinateurs, et les CPU modernes prennent tous en charge cette norme. Comme d'autres langages de programmation, Go utilise également IEEE 754 pour stocker les nombres à virgule flottante.
Nous savons qu'un octet (byte) dans un ordinateur peut stocker 8 bits. float32 est un nombre à virgule flottante simple précision et occupe 4 octets, soit 32 bits. float64 est une double précision et occupe 8 octets, soit 64 bits.
Dans float32, le bit de signe occupe 1 bit, l'exposant occupe 8 bits et les 23 bits restants sont utilisés pour représenter la mantisse.
Dans float64, le bit de signe occupe également 1 bit, l'exposant occupe 11 bits et les 52 bits restants sont utilisés pour représenter la mantisse.
La valeur maximale que float32 peut représenter est d'environ 3.4e+38 en notation scientifique, et la valeur minimale est de 1.4e-45. La valeur maximale que float64 peut représenter est d'environ 1.8e+308, et la valeur minimale est de 4.9e-324. Nous pouvons voir que la plage de valeurs à virgule flottante peut aller de très petite à très grande.
Nous pouvons utiliser la constante math.MaxFloat32 pour représenter la valeur maximale dans float32. Utilisez la constante math.MaxFloat64 pour représenter la valeur maximale dans float64.
Représentation des nombres à virgule flottante (Representation of Floating-Point Numbers)
Lors de l'affichage des nombres à virgule flottante, nous pouvons utiliser le marqueur de substitution (placeholder) %f de la fonction Printf du package fmt. Voici un exemple :
cd ~/project
touch float.go
package main
import (
"fmt"
"math"
)
func main() {
// Output without exponential form
fmt.Printf("2.333 without exponential form: %f\n", 2.333)
fmt.Printf("Pi without exponential form: %f\n", math.Pi)
// Use %.2f to keep two decimal places for Pi
fmt.Printf("Pi with two decimal places: %.2f\n", math.Pi)
fmt.Printf("The maximum value of float32: %f\n", math.MaxFloat32)
// Exponential form
fmt.Printf("2.333 in exponential form: %e", 2.333)
}
Exécutez la commande et vous verrez la sortie suivante.
go run float.go
2.333 without exponential form: 2.333000
Pi without exponential form: 3.141593
Pi with two decimal places: 3.14
The maximum value of float32: 340282346638528859811704183484516925440.000000
2.333 in exponential form: 2.333000e+00
Explication de la sortie (Explanation of the output):
2.333 without exponential form: 2.333000: Ceci montre le nombre2.333imprimé en utilisant le marqueur de substitution%f. Par défaut, le marqueur de substitution%faffiche 6 chiffres après la virgule, donc2.333devient2.333000.Pi without exponential form: 3.141593: Cette ligne affiche la valeur de la constantemath.Pi, qui est une approximation de la constante mathématique π. Le marqueur de substitution%fl'affiche avec une précision totale.Pi with two decimal places: 3.14: En utilisant%.2f, nous indiquons àfmt.Printfde formater le nombre à deux chiffres après la virgule, ce qui donne3.14. Ceci est très utile lorsque vous n'avez besoin que d'une certaine précision pour la sortie.The maximum value of float32: 340282346638528859811704183484516925440.000000: Ceci montre la valeur maximale qu'unfloat32peut représenter. Notez que c'est un très grand nombre, et lorsqu'il est imprimé avec%f, il sera représenté avec de nombreux chiffres.2.333 in exponential form: 2.333000e+00: Cette ligne montre comment représenter un nombre à virgule flottante en notation exponentielle (scientifique) en utilisant le marqueur de substitution%e. Lee+00à la fin indique que nous multiplions2.333000par 10 à la puissance de 0, ce qui est simplement2.333. Si l'exposant étaite+02, alors le nombre serait multiplié par10^2(100), ce qui donnerait233.3.
Types Booléens
Le type bool n'a que deux valeurs possibles : true ou false, avec false étant la valeur par défaut. Il possède les caractéristiques suivantes :
- Il ne peut pas être converti en d'autres types, comme convertir un entier en booléen ou convertir un booléen en entier.
- Il ne peut pas participer à des opérations arithmétiques.
Les types booléens sont généralement utilisés conjointement avec des opérateurs relationnels, tels que =, >, et <. Créons un fichier nommé bool.go pour voir une démonstration :
cd ~/project
touch bool.go
package main
import (
"fmt"
)
func main() {
// Use the %t placeholder in fmt.Printf to represent a boolean value
fmt.Printf("Is 3 equal to 2? %t\n", 3 == 2)
fmt.Printf("Is 2 equal to 2? %t\n", 2 == 2)
// Determine whether a and b are equal
a, b := 1, 2
fmt.Printf("a is %d, b is %d\n", a, b)
if a > b {
fmt.Println("a is greater than b")
} else if a == b {
fmt.Println("a is equal to b")
} else {
fmt.Println("b is greater than a")
}
}
Après avoir exécuté le programme, nous obtenons la sortie suivante :
go run bool.go
Is 3 equal to 2? false
Is 2 equal to 2? true
a is 1, b is 2
b is greater than a
Explication de la sortie (Explanation of the output):
Is 3 equal to 2? false: L'expression3 == 2est évaluée àfalse, qui est ensuite imprimée en utilisant le marqueur de substitution%t.Is 2 equal to 2? true: L'expression2 == 2est évaluée àtrue, qui est ensuite imprimée en utilisant le marqueur de substitution%t.a is 1, b is 2: Cette ligne affiche les valeurs attribuées aux variables entièresaetb.b is greater than a: L'instruction conditionnelleif-else if-elseest évaluée àa < b, qui est1 < 2(vrai), par conséquent l'instructionelseest exécutée, ce qui entraîne l'impression par le programme de "b is greater than a".
Dans ce programme, nous utilisons d'abord %t dans fmt.Printf pour représenter une valeur booléenne, puis nous utilisons l'instruction if pour déterminer la relation entre deux valeurs. Dans fmt.Printf, nous pouvons utiliser le marqueur de substitution %d pour représenter un entier, le marqueur de substitution %f pour représenter un nombre à virgule flottante et le marqueur de substitution %t pour représenter une valeur booléenne.
Nombres Complexes
Go possède également des types de nombres complexes intégrés, qui peuvent être divisés en types complex64 et complex128. Dans complex64, les parties réelle et imaginaire sont toutes deux sur 32 bits, tandis que dans complex128, les parties réelle et imaginaire sont toutes deux sur 64 bits. Nous pouvons facilement effectuer des opérations sur les nombres complexes en Go.
Créez un fichier nommé complex.go et entrez le code suivant :
cd ~/project
touch complex.go
package main
import (
"fmt"
)
func main() {
// Initialize complex numbers in different ways
c1 := complex(3, 1)
c2 := 4 + 5i
// Complex number operations
c3 := c1 + c2
c4 := c1 * c2
// Use the real() function to obtain the real part of a complex number, and the imag() function to obtain the imaginary part of a complex number
fmt.Printf("The real part of c1 is %v, the imaginary part is %v\n", real(c1), imag(c1))
// %v in fmt.Printf can be used to represent complex numbers
fmt.Printf("c1 + c2 is %v\n", c3)
fmt.Printf("c1 * c2 is %v\n", c4)
}
Après avoir exécuté le programme, nous obtenons la sortie suivante :
go run complex.go
The real part of c1 is 3, the imaginary part is 1
c1 + c2 is (7+6i)
c1 * c2 is (7+19i)
Explication de la sortie (Explanation of the output):
The real part of c1 is 3, the imaginary part is 1: La fonctionreal(c1)extrait la partie réelle du nombre complexec1, qui est3, etimag(c1)extrait la partie imaginaire dec1, qui est1. Ces valeurs sont ensuite imprimées en utilisant le marqueur de substitution%v.c1 + c2 is (7+6i): Cette ligne montre le résultat de l'addition des nombres complexesc1etc2.c1est défini comme3 + 1ietc2comme4 + 5i. L'addition des parties réelle et imaginaire séparément donne(3 + 4) + (1 + 5)i, soit7 + 6i.c1 * c2 is (7+19i): Cette ligne montre le résultat de la multiplication des nombres complexesc1etc2.(3 + 1i) * (4 + 5i)est calculé comme(3*4 - 1*5) + (3*5 + 1*4)i, ce qui se simplifie en(12-5) + (15+4)i, et finalement en7+19i.
Dans ce programme, nous avons démontré comment initialiser et effectuer des opérations sur des nombres complexes en utilisant la fonction complex et les opérateurs + et *. real() et imag() sont utilisés pour extraire respectivement les parties réelle et imaginaire d'un nombre complexe. Le verbe %v dans fmt.Printf est utilisé comme un marqueur de substitution général pour afficher les nombres complexes.
Syntaxe des Valeurs Littérales
Dans la version 1.13, Go a introduit la Numeric Literal Syntax (syntaxe des littéraux numériques). Elle définit la représentation des nombres dans différents systèmes numériques. Examinons ses règles.
- Binaire (Binary): Ajoutez
0bavant l'entier. Par exemple,0b101équivaut à5en décimal. - Octal (Octal): Ajoutez
0oou0Oavant l'entier. Par exemple,0o11équivaut à9en décimal. - Hexadécimal (Hexadecimal): Ajoutez
0xou0Xavant l'entier. Par exemple,0x1béquivaut à27en décimal. - Utilisez
_pour séparer les chiffres dans l'entier, par exemple,0b1000_0100_0010_0001équivaut à0b1000010000100001. Cela peut améliorer la lisibilité.
Illustrons cela en détail :
cd ~/project
touch literals.go
package main
import "fmt"
func main() {
// Binary, add 0b at the beginning
var a int = 0b101
fmt.Printf("Binary a is %b, decimal is %d\n", a, a)
// Octal, add 0o or 0O at the beginning
var b int = 0o11
fmt.Printf("Octal b is %o, decimal is %d\n", b, b)
// Hexadecimal, add 0x or 0X at the beginning
var c int = 0x1b
fmt.Printf("Hexadecimal c is %x, decimal is %d\n", c, c)
// Use separators
d := 0b1000_0100_0010_0001
e := 0b1000010000100001
if d == e {
fmt.Println("d is equal to e")
}
}
Après avoir exécuté le programme, nous obtenons la sortie suivante :
go run literals.go
Binary a is 101, decimal is 5
Octal b is 11, decimal is 9
Hexadecimal c is 1b, decimal is 27
d is equal to e
Explication de la sortie (Explanation of the output):
Binary a is 101, decimal is 5: Cette ligne montre la représentation binaire de0b101qui est101, et son équivalent décimal est5. Le marqueur de substitution%baffiche la valeur binaire dea, tandis que%daffiche la représentation décimale.Octal b is 11, decimal is 9: Le nombre octal0o11équivaut à1*8^1 + 1*8^0 = 8 + 1 = 9en décimal. Le marqueur de substitution%oaffiche la représentation octale deb, et%daffiche sa valeur décimale.Hexadecimal c is 1b, decimal is 27: Le nombre hexadécimal0x1béquivaut à1*16^1 + 11*16^0 = 16 + 11 = 27en décimal. Le marqueur de substitution%xaffiche la représentation hexadécimale dec, et%daffiche sa valeur décimale.d is equal to e: Ceci montre que le littéral binaire0b1000_0100_0010_0001est égal à0b1000010000100001en valeur. Les underscores (tirets bas) sont purement pour la lisibilité et ne modifient pas la valeur du nombre. La conditionifest correctement évaluée àtrue.
Dans ce programme, nous avons démontré la déclaration et la sortie de différents systèmes numériques, ainsi que l'utilisation de séparateurs. Dans fmt.Printf, nous avons utilisé différents marqueurs de substitution pour représenter différents systèmes numériques. Par exemple, %b représente le binaire et %x représente l'hexadécimal. Les maîtriser améliorera l'efficacité de la programmation.
Résumé
Récapitulons ce que nous avons appris dans cette section :
- Les entiers (Integers) peuvent être divisés en entiers signés (signed integers) et entiers non signés (unsigned integers)
- Les types d'entiers par défaut
intetuintont des plages (ranges) qui dépendent de la plateforme - Représentation des nombres à virgule flottante (floating-point numbers)
- Comment utiliser les nombres complexes (complex numbers)
- Introduction de la syntaxe des valeurs littérales (literal value syntax)
- Comment utiliser différents marqueurs de substitution (placeholders)
Dans cette section, nous avons expliqué et démontré les types d'entiers courants, les types à virgule flottante et les types booléens. Nous avons discuté de leurs tailles, de leurs plages et de leur utilisation. Nous avons également présenté les nombres complexes et les constantes littérales. Les types numériques sont la pierre angulaire des programmes Go, et il est important que les apprenants les étudient attentivement.



