O valor máximo para um tipo int em Go

132

Como se especifica o valor máximo representável para um unsignedtipo inteiro?

Gostaria de saber como inicializar minno loop abaixo que iterativamente calcula os comprimentos mínimo e máximo de algumas estruturas.

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
}

para que a primeira vez através da comparação minLen >= n,.

Mike Samuel
fonte
2
dê uma olhada neste snippet int(^uint(0) >> 1) // largest intextraído de golang.org/doc/effective_go.html#printing #
Victor Victor

Respostas:

218

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

A parte pertinente:

Como os tipos inteiros usam a aritmética de complemento de dois, é possível inferir os valores constantes mín / máx para inte uint. Por exemplo,

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

De acordo com o comentário 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
fonte
66
Use os disponíveis em math: golang.org/pkg/math/#pkg-constants , você provavelmente desejaria math.MaxInt32.
Charles L.
7
Alguém pode explicar exatamente o que ^ uint (0) e ^ uint (0) >> 1 fazem?
Arijoon 29/06
16
@Arijoon, ^ significa inverter bits na expressão, então se: uint (0) == 0000 ... 0000 (exatamente 32 ou 64 bits zero, dependendo da arquitetura de destino da construção), então ^ unit (0) == 1111 ... 1111 o que nos fornece o valor máximo para o número inteiro não assinado (todos). Agora, quando você está falando sobre número inteiro assinado, o primeiro bit (o mais significativo) é usado para armazenar o sinal, portanto, para o valor máximo int assinado - precisamos mudar todos os bits para a direita, o que nos dá ^ uint (0) >> 1 = = 0111 ... 1111. O que fornece o número inteiro máximo positivo.
Ninjaboy 9/05
4
@CharlesL. e quanto ao tipo int?
user960567
1
Sei que já faz algum tempo, mas caso alguém venha aqui hoje e veja o comentário-pergunta do @ user960567: o inttipo tem 32 bits de comprimento em um sistema de 32 bits e 64 bits de comprimento em um sistema de 64 bits. Veja aqui .
Christoph Harms-Ensink
73

https://golang.org/ref/spec#Numeric_types para limites de tipo físico.

Os valores máximos são definidos no pacote matemático, portanto, no seu caso: math.MaxUint32

Cuidado, pois não há transbordamento - o incremento de um número máximo máximo de passado causa um desvio.

Excluído
fonte
2
Obrigado. Na verdade uint, estou usando , não uint32. O lene capuse intnão, int32então eu quero usar algo que corresponda ao tamanho daqueles em todas as arquiteturas. math/const.godefine um monte de Max<type>mas nenhum para um uintou para `int.
Mike Samuel
Eu mudaria para uint32 ou unit64 e, em seguida, para garantir que ele seja portável entre arquiteturas. Eu faço isso com tudo religiosamente. Passei anos infernal portando C entre arquiteturas e posso dizer que "ser explícito" ajudará consideravelmente mais tarde.
Excluído
Obrigado. Meu código verifica isso, uint(len(...)) < thing.minLenmas não sei se uint64(int)é e continuará sendo um comportamento definido.
Mike Samuel
1
Se você não souber, leia as especificações vinculadas acima ... especificamente golang.org/doc/go_spec.html#Conversions . Há uma definição cuidadosa de "conversões entre tipos numéricos".
Anschel Schaffer-Cohen
29

Eu usaria o mathpacote para obter o valor máximo e o mínimo:

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
}

Ouput:

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
fonte
1
Este código não funciona. O int64overflow dos dois int, que é o que acontece se você não digitar explicitamente constantes antes da interpolação de string. Em int64(math.MaxInt64)vez disso, use stackoverflow.com/questions/16474594/…
domoarigato
3
Mas, caso contrário, é uma resposta melhor do que a aceita. :)
domoarigato
o que acontece se você usar o int64 em uma máquina com tamanho de palavra de 32 bits? em C, o compilador decide o INT_MIN
segue_segway
12

Originalmente, usei o código retirado do tópico de discussão que @nmichaels usou em sua resposta. Agora eu uso um cálculo ligeiramente diferente. Incluí alguns comentários caso alguém tenha a mesma consulta 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
)

Os dois últimos passos funcionam devido à forma como os números positivos e negativos são representados na aritmética do complemento de dois. A seção de especificação de idioma Go em Tipos numéricos refere o leitor ao artigo relevante da Wikipedia . Não li isso, mas aprendi sobre o complemento de dois no livro Code, de Charles Petzold , que é uma introdução muito acessível aos fundamentos dos computadores e da codificação.

Coloquei o código acima (menos a maioria dos comentários) em um pequeno pacote inteiro de matemática .

Crantok
fonte
9

Resumo rápido:

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

Fundo:

Como presumo que você saiba, o uinttipo é do mesmo tamanho que um uint32ou outro uint64, dependendo da plataforma em que você está. Normalmente, a versão sem tamanho seria usada apenas quando não há risco de se aproximar do valor máximo, pois a versão sem especificação de tamanho pode usar o tipo "nativo", dependendo da plataforma, que tende a ser mais rápida.

Observe que ele tende a ser "mais rápido" porque o uso de um tipo não-nativo às vezes exige que seja feita uma verificação matemática e de limites adicional pelo processador, a fim de emular o número inteiro maior ou menor. Com isso em mente, esteja ciente de que o desempenho do processador (ou código otimizado do compilador) quase sempre será melhor do que adicionar seu próprio código de verificação de limites; portanto, se houver algum risco de entrar em jogo, isso poderá prejudicar É bom usar simplesmente a versão de tamanho fixo e deixar a emulação otimizada lidar com qualquer problema disso.

Com isso dito, ainda existem algumas situações em que é útil saber com o que você está trabalhando.

O pacote " math / bits " contém o tamanho de uint, em bits. Para determinar o valor máximo, altere 1o número de bits menos 1. ie:(1 << bits.UintSize) - 1

Observe que, ao calcular o valor máximo de uint, geralmente você precisará colocá-lo explicitamente em uma uintvariável (ou maior); caso contrário, o compilador poderá falhar, pois o padrão será tentar atribuir esse cálculo a um sinal assinado int(onde, como deveria seja óbvio, não caberia), então:

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

Essa é a resposta direta à sua pergunta, mas também existem alguns cálculos relacionados nos quais você pode estar interessado.

De acordo com as especificações , uinte intsão sempre do mesmo tamanho.

uint 32 ou 64 bits

int mesmo tamanho que uint

Portanto, também podemos usar essa constante para determinar o valor máximo de int, pegando a mesma resposta e dividindo 2e subtraindo 1. ou seja:(1 << bits.UintSize) / 2 - 1

E o valor mínimo de int, deslocando-se 1por tantos bits e dividindo o resultado por -2. ou seja:(1 << bits.UintSize) / -2

Em suma:

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

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

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

exemplo completo (deve ser o mesmo que abaixo)

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
fonte
Obrigado. Suas advertências sobre os números nativos estão bem definidas, e eu não tinha conhecimento de matemática / bits.
Mike Samuel
uint de 32 ou 64 bits, com o mesmo tamanho que uint. Como podem ter o mesmo tamanho se um tem um sinal e o outro não?
themiDdlest 15/01
Eles têm o mesmo tamanho de bit, não têm os mesmos valores máximo / mínimo. Um dos bits desse tamanho é o bit de sinal. (a /2parte é o que remove esse bit de consideração ao calcular o tamanho de min / max para int64)
Will Palmer
4

Uma maneira de resolver esse problema é obter os pontos de partida dos próprios valores:

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
fonte
1

Um pacote leve os contém (assim como outros limites de tipos int e algumas funções inteiras amplamente usadas):

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
LoveRick
fonte
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
Paz
fonte