La valeur maximale pour un type int dans Go

132

Comment spécifier la valeur maximale représentable pour un unsignedtype entier?

Je voudrais savoir comment initialiser mindans la boucle ci-dessous qui calcule de manière itérative les longueurs min et max de certaines structures.

var minLen uint = ???
var maxLen uint = 0
for _, thing := range sliceOfThings {
  if minLen > thing.n { minLen = thing.n }
  if maxLen < thing.n { maxLen = thing.n }
}
if minLen > maxLen {
  // If there are no values, clamp min at 0 so that min <= max.
  minLen = 0
}

de sorte que la première fois grâce à la comparaison, minLen >= n.

Mike Samuel
la source
2
jetez un oeil à cet extrait int(^uint(0) >> 1) // largest intextrait de golang.org/doc/effective_go.html#printing
Victor

Réponses:

219

https://groups.google.com/group/golang-nuts/msg/71c307e4d73024ce?pli=1

La partie pertinente:

Étant donné que les types entiers utilisent l'arithmétique du complément à deux, vous pouvez déduire les valeurs constantes min / max pour intet uint. Par exemple,

const MaxUint = ^uint(0) 
const MinUint = 0 
const MaxInt = int(MaxUint >> 1) 
const MinInt = -MaxInt - 1

Selon le commentaire de @ CarelZA:

uint8  : 0 to 255 
uint16 : 0 to 65535 
uint32 : 0 to 4294967295 
uint64 : 0 to 18446744073709551615 
int8   : -128 to 127 
int16  : -32768 to 32767 
int32  : -2147483648 to 2147483647 
int64  : -9223372036854775808 to 9223372036854775807
nmichaels
la source
66
Utilisez ceux disponibles dans math: golang.org/pkg/math/#pkg-constants , vous voudrez math.MaxInt32probablement.
Charles L.
7
Quelqu'un peut-il expliquer exactement ce que font ^ uint (0) et ^ uint (0) >> 1?
Arijoon
16
@Arijoon, ^ signifie inverser les bits dans l'expression donc si: uint (0) == 0000 ... 0000 (exactement 32 ou 64 bits zéro selon l'architecture cible de construction) alors ^ unit (0) == 1111 ... 1111 ce qui nous donne la valeur maximale de l'entier non signé (tous les uns). Maintenant, lorsque vous parlez d'entier signé, le premier bit (le plus significatif) est utilisé pour stocker le signe donc à la valeur maximale de l'int signé - nous devons décaler tous les bits vers la droite, ce qui nous donne ^ uint (0) >> 1 = = 0111 ... 1111. Ce qui donne le nombre entier positif maximum.
ninjaboy
4
@CharlesL. qu'en est-il juste du type int?
user960567
1
Je sais que cela fait un certain temps, mais juste au cas où quelqu'un viendrait ici aujourd'hui et verrait la question-commentaire de @ user960567: le inttype est de 32 bits sur un système 32 bits et de 64 bits sur un système 64 bits. Regardez ici .
Christoph Harms-Ensink
73

https://golang.org/ref/spec#Numeric_types pour les limites de type physique.

Les valeurs max sont définies dans le package math, donc dans votre cas: math.MaxUint32

Attention, il n'y a pas de débordement - l'incrémentation au-delà du max provoque un bouclage.

Supprimé
la source
2
Merci. J'utilise réellement uint, non uint32. Le lenet ne l' caputilisez intpas, int32donc je veux utiliser quelque chose qui correspond à la taille de ceux sur toutes les architectures. math/const.godéfinit un tas de Max<type>mais aucun pour l'un uintou l' autre ou `int.
Mike Samuel du
Je le changerais en uint32 ou unit64 pour m'assurer qu'il soit portable à travers les architectures. Je fais cela avec tout religieusement. J'ai traversé des années de portage de C entre les architectures et je peux dire que "être explicite" aidera considérablement plus tard.
Supprimé le
Merci. Mon code a vérifié cela uint(len(...)) < thing.minLenmais je ne sais pas si uint64(int)c'est et restera un comportement défini.
Mike Samuel
1
Si vous ne le savez pas, lisez les spécifications liées ci-dessus ... en particulier golang.org/doc/go_spec.html#Conversions . Il existe une définition précise des «conversions entre types numériques».
Anschel Schaffer-Cohen
29

J'utiliserais mathpackage pour obtenir la valeur maximale et la valeur minimale:

func printMinMaxValue() {
    // integer max
    fmt.Printf("max int64 = %+v\n", math.MaxInt64)
    fmt.Printf("max int32 = %+v\n", math.MaxInt32)
    fmt.Printf("max int16 = %+v\n", math.MaxInt16)

    // integer min
    fmt.Printf("min int64 = %+v\n", math.MinInt64)
    fmt.Printf("min int32 = %+v\n", math.MinInt32)

    fmt.Printf("max flloat64= %+v\n", math.MaxFloat64)
    fmt.Printf("max float32= %+v\n", math.MaxFloat32)

    // etc you can see more int the `math`package
}

Sortie:

max int64 = 9223372036854775807
max int32 = 2147483647
max int16 = 32767
min int64 = -9223372036854775808
min int32 = -2147483648
max flloat64= 1.7976931348623157e+308
max float32= 3.4028234663852886e+38
Gujarat Santana
la source
1
Ce code ne fonctionne pas. Les deux int64débordent int, ce qui se produit si vous ne tapez pas explicitement les constantes avant l'interpolation de chaîne. Utilisez à la int64(math.MaxInt64)place, voir stackoverflow.com/questions/16474594/…
domoarigato
3
Mais sinon, est une meilleure réponse que celle acceptée. :)
domoarigato
que se passe-t-il si vous utilisez int64 sur une machine avec une taille de mot de 32 bits? en C, le compilateur décide du INT_MIN
segue_segway
12

J'ai utilisé à l'origine le code tiré du fil de discussion que @nmichaels a utilisé dans sa réponse. J'utilise maintenant un calcul légèrement différent. J'ai inclus quelques commentaires au cas où quelqu'un d'autre aurait la même requête que @Arijoon

const (
    MinUint uint = 0                 // binary: all zeroes

    // Perform a bitwise NOT to change every bit from 0 to 1
    MaxUint      = ^MinUint          // binary: all ones

    // Shift the binary number to the right (i.e. divide by two)
    // to change the high bit to 0
    MaxInt       = int(MaxUint >> 1) // binary: all ones except high bit

    // Perform another bitwise NOT to change the high bit to 1 and
    // all other bits to 0
    MinInt       = ^MaxInt           // binary: all zeroes except high bit
)

Les deux dernières étapes fonctionnent en raison de la façon dont les nombres positifs et négatifs sont représentés dans l'arithmétique du complément à deux. La section de spécification du langage Go sur les types numériques renvoie le lecteur à l'article Wikipédia pertinent . Je n'ai pas lu cela, mais j'ai appris le complément à deux dans le livre Code de Charles Petzold , qui est une introduction très accessible aux principes fondamentaux de l'informatique et du codage.

J'ai mis le code ci-dessus (moins la plupart des commentaires) dans un petit package mathématique entier .

crantok
la source
9

Résumé rapide:

import "math/bits"
const (
    MaxUint uint = (1 << bits.UintSize) - 1
    MaxInt int = (1 << bits.UintSize) / 2 - 1
    MinInt int = (1 << bits.UintSize) / -2
)

Contexte:

Comme je suppose que vous le savez, le uinttype est de la même taille que l'un uint32ou l' autre uint64, selon la plate-forme sur laquelle vous vous trouvez. Habituellement, on n'utiliserait la version non dimensionnée de ceux-ci que lorsqu'il n'y a pas de risque de se rapprocher de la valeur maximale, car la version sans spécification de taille peut utiliser le type "natif", selon la plate-forme, qui a tendance à être plus rapide.

Notez qu'il a tendance à être "plus rapide" car l'utilisation d'un type non natif nécessite parfois des calculs supplémentaires et une vérification des limites à effectuer par le processeur, afin d'émuler le plus grand ou le plus petit entier. Dans cet esprit, sachez que les performances du processeur (ou du code optimisé du compilateur) seront presque toujours meilleures que l'ajout de votre propre code de vérification des limites, donc s'il y a un risque qu'il entre en jeu, cela peut faire sens d'utiliser simplement la version de taille fixe et de laisser l'émulation optimisée gérer toutes les conséquences de cela.

Cela dit, il existe encore des situations dans lesquelles il est utile de savoir avec quoi vous travaillez.

Le package " math / bits " contient la taille de uint, en bits. Pour déterminer la valeur maximale, décalez 1de ce nombre de bits, moins 1, c'est-à-dire:(1 << bits.UintSize) - 1

Notez que lors du calcul de la valeur maximale de uint, vous devrez généralement la placer explicitement dans une uintvariable (ou plus grande), sinon le compilateur peut échouer, car il tentera par défaut d'assigner ce calcul dans un signe int(où, comme il se doit être évident, cela ne rentrerait pas), donc:

const MaxUint uint = (1 << bits.UintSize) - 1

C'est la réponse directe à votre question, mais il y a aussi quelques calculs connexes qui pourraient vous intéresser.

Selon les spécifications , uintet intsont toujours de la même taille.

uint soit 32 ou 64 bits

int même taille que uint

Nous pouvons donc également utiliser cette constante pour déterminer la valeur maximale de int, en prenant cette même réponse et en divisant 2puis en soustrayant 1. c'est à dire:(1 << bits.UintSize) / 2 - 1

Et la valeur minimale de int, en décalant 1de autant de bits et en divisant le résultat par -2. c'est à dire:(1 << bits.UintSize) / -2

En résumé:

MaxUint: (1 << bits.UintSize) - 1

MaxInt: (1 << bits.UintSize) / 2 - 1

MinInt: (1 << bits.UintSize) / -2

exemple complet (devrait être le même que ci-dessous)

package main

import "fmt"
import "math"
import "math/bits"

func main() {
    var mi32 int64 = math.MinInt32
    var mi64 int64 = math.MinInt64

    var i32 uint64 = math.MaxInt32
    var ui32 uint64 = math.MaxUint32
    var i64 uint64 = math.MaxInt64
    var ui64 uint64 = math.MaxUint64
    var ui uint64 = (1 << bits.UintSize) - 1
    var i uint64 = (1 << bits.UintSize) / 2 - 1
    var mi int64 = (1 << bits.UintSize) / -2

    fmt.Printf(" MinInt32: %d\n", mi32)
    fmt.Printf(" MaxInt32:  %d\n", i32)
    fmt.Printf("MaxUint32:  %d\n", ui32)
    fmt.Printf(" MinInt64: %d\n", mi64)
    fmt.Printf(" MaxInt64:  %d\n", i64)
    fmt.Printf("MaxUint64:  %d\n", ui64)
    fmt.Printf("  MaxUint:  %d\n", ui)
    fmt.Printf("   MinInt: %d\n", mi)
    fmt.Printf("   MaxInt:  %d\n", i)
}
Will Palmer
la source
Merci. Vos mises en garde concernant les valeurs numériques natives sont bien formulées et je n'étais pas au courant des maths / bits.
Mike Samuel
uint 32 ou 64 bits, int de la même taille que uint. Comment peuvent-ils avoir la même taille si l'un a un signe et l'autre pas?
themiDdlest le
Ils ont la même taille de bits, ils n'ont pas les mêmes valeurs maximum / minimum. L'un des bits de cette taille est le bit de signe. (la /2partie est ce qui supprime ce bit de considération lors du calcul de la taille de min / max pour int64)
Will Palmer
4

Une façon de résoudre ce problème consiste à obtenir les points de départ des valeurs elles-mêmes:

var minLen, maxLen uint
if len(sliceOfThings) > 0 {
  minLen = sliceOfThings[0].minLen
  maxLen = sliceOfThings[0].maxLen
  for _, thing := range sliceOfThings[1:] {
    if minLen > thing.minLen { minLen = thing.minLen }
    if maxLen < thing.maxLen { maxLen = thing.maxLen }
  }
}
SteveMcQwark
la source
1

Un package léger les contient (ainsi que d'autres limites de types int et certaines fonctions entières largement utilisées):

import (
    "fmt"
    "<Full URL>/go-imath/ix"
    "<Full URL>/go-imath/ux"
)
...
fmt.Println(ix.Minimal) // Output: -2147483648 (32-bit) or -9223372036854775808 (64-bit)
fmt.Println(ix.Maximal) // Output: 2147483647 or 9223372036854775807
fmt.Println(ux.Minimal) // Output: 0
fmt.Println(ux.Maximal) // Output: 4294967295 or 18446744073709551615
AmourRick
la source
0
MaxInt8   = 1<<7 - 1
MinInt8   = -1 << 7
MaxInt16  = 1<<15 - 1
MinInt16  = -1 << 15
MaxInt32  = 1<<31 - 1
MinInt32  = -1 << 31
MaxInt64  = 1<<63 - 1
MinInt64  = -1 << 63
MaxUint8  = 1<<8 - 1
MaxUint16 = 1<<16 - 1
MaxUint32 = 1<<32 - 1
MaxUint64 = 1<<64 - 1
Paix
la source