El valor máximo para un tipo int en Go

132

¿Cómo se especifica el valor máximo representable para un unsignedtipo entero?

Me gustaría saber cómo inicializar minen el ciclo a continuación que calcula iterativamente las longitudes mínimas y máximas de algunas estructuras.

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
}

por lo que la primera vez a través de la comparación, minLen >= n.

Mike Samuel
fuente
2
eche un vistazo a este fragmento int(^uint(0) >> 1) // largest intextraído de golang.org/doc/effective_go.html#printing
Victor

Respuestas:

218

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

La parte pertinente:

Como los tipos enteros usan aritmética de complemento a dos, puede inferir los valores constantes min / max para inty uint. Por ejemplo,

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

Según el comentario 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
fuente
66
Utilice los disponibles en math: golang.org/pkg/math/#pkg-constants , lo math.MaxInt32más probable es que desee .
Charles L.
77
¿Alguien puede explicar exactamente qué hacen ^ uint (0) y ^ uint (0) >> 1?
Arijoon
16
@Arijoon, ^ significa invertir bits en la expresión, por lo que si: uint (0) == 0000 ... 0000 (exactamente 32 o 64 bits cero dependiendo de la arquitectura de destino de construcción) entonces ^ unidad (0) == 1111 ... 1111 que nos da el valor máximo para el entero sin signo (todos unos). Ahora, cuando se habla de un entero con signo, el primer bit (el más significativo) se usa para almacenar el signo, por lo tanto, al valor máximo int con signo: debemos desplazar todos los bits a la derecha, lo que nos da ^ uint (0) >> 1 = = 0111 ... 1111. Lo que da el número entero positivo máximo.
ninjaboy
44
@CharlesL. ¿Qué hay de solo int type?
user960567
1
Sé que ha pasado algún tiempo, pero en caso de que alguien venga hoy aquí y vea la pregunta-comentario de @ user960567: el inttipo tiene 32 bits de largo en un sistema de 32 bits y 64 bits de largo en un sistema de 64 bits. Ver aquí .
Christoph Harms-Ensink
73

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

Los valores máximos se definen en el paquete matemático, por lo que en su caso: math.MaxUint32

Tenga cuidado, ya que no hay desbordamiento: el incremento del pasado máximo provoca una envoltura.

Eliminado
fuente
2
Gracias. En realidad estoy usando uint, no uint32. El leny no capuso, por lo que quiero usar algo que coincida con el tamaño de aquellos en todas las arquitecturas. define un montón de pero ninguno para cualquiera o `int. intint32math/const.goMax<type>uint
Mike Samuel
Lo cambiaría a uint32 o unit64 para asegurarme de que sea portátil en todas las arquitecturas. Lo hago con todo religiosamente. He pasado por años de infierno portando C entre arquitecturas y puedo decir que "ser explícito" ayudará considerablemente más adelante.
Borrado el
Gracias. Mi código tiene comprobaciones de eso, uint(len(...)) < thing.minLenpero no sé si uint64(int)es y seguirá siendo un comportamiento definido.
Mike Samuel
1
Si no sabe, lea la especificación vinculada anteriormente ... específicamente golang.org/doc/go_spec.html#Conversions . Hay una definición cuidadosa de "conversiones entre tipos numéricos".
Anschel Schaffer-Cohen
29

Usaría el mathpaquete para obtener el valor máximo y el valor 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
fuente
1
Este código no funciona El int64overflow de los dos int, que es lo que sucede si no escribe explícitamente constantes antes de la interpolación de cadenas. Utilice en su int64(math.MaxInt64)lugar, consulte stackoverflow.com/questions/16474594/…
domoarigato
3
Pero por lo demás, es una mejor respuesta que la aceptada. :)
domoarigato
¿Qué sucede si usa int64 en una máquina con un tamaño de palabra de 32 bits? en C, el compilador decide el INT_MIN
segue_segway
12

Originalmente usé el código tomado del hilo de discusión que @nmichaels usó en su respuesta. Ahora uso un cálculo ligeramente diferente. He incluido algunos comentarios en caso de que alguien más tenga la misma 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
)

Los dos últimos pasos funcionan debido a cómo se representan los números positivos y negativos en la aritmética del complemento a dos. La sección de especificación del lenguaje Go sobre Tipos numéricos remite al lector al artículo relevante de Wikipedia . No he leído eso, pero aprendí sobre el complemento de dos del libro Code de Charles Petzold , que es una introducción muy accesible a los fundamentos de las computadoras y la codificación.

Puse el código de arriba (menos la mayoría de los comentarios) en un pequeño paquete matemático entero .

Crantok
fuente
9

Sumario 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
)

Antecedentes:

Como supongo que ya sabes, el uinttipo es del mismo tamaño que sea uint32o uint64, dependiendo de la plataforma que se encuentra. Por lo general, uno usaría la versión sin tamaño de estos solo cuando no haya riesgo de acercarse al valor máximo, ya que la versión sin una especificación de tamaño puede usar el tipo "nativo", dependiendo de la plataforma, que tiende a ser más rápido.

Tenga en cuenta que tiende a ser "más rápido" porque el uso de un tipo no nativo a veces requiere que el procesador realice una comprobación matemática y de límites adicional para emular el número entero más grande o más pequeño. Con eso en mente, tenga en cuenta que el rendimiento del procesador (o el código optimizado del compilador) casi siempre será mejor que agregar su propio código de verificación de límites, por lo que si existe algún riesgo de que entre en juego, puede tiene sentido usar simplemente la versión de tamaño fijo y dejar que la emulación optimizada se encargue de las consecuencias de eso.

Dicho esto, todavía hay algunas situaciones en las que es útil saber con qué está trabajando.

El paquete " matemáticas / bits " contiene el tamaño de uint, en bits. Para determinar el valor máximo, cambie 1esa cantidad de bits, menos 1. es decir:(1 << bits.UintSize) - 1

Tenga en cuenta que al calcular el valor máximo de uint, generalmente tendrá que ponerlo explícitamente en una uintvariable (o más grande), de lo contrario, el compilador puede fallar, ya que de forma predeterminada intentará asignar ese cálculo a un signoint (donde, como debería sea ​​obvio, no encajaría), entonces:

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

Esa es la respuesta directa a su pregunta, pero también hay algunos cálculos relacionados que pueden interesarle.

Según la especificación , uinty intsiempre son del mismo tamaño.

uint ya sea 32 o 64 bits

int mismo tamaño que uint

Entonces, también podemos usar esta constante para determinar el valor máximo de int, tomando esa misma respuesta y dividiendo para 2luego restar1 . es decir:(1 << bits.UintSize) / 2 - 1

Y el valor mínimo de int, cambiando 1por tantos bits y dividiendo el resultado entre -2. es decir:(1 << bits.UintSize) / -2

En resumen:

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

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

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

ejemplo completo (debe ser el mismo que se muestra a continuación)

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
fuente
Gracias. Sus advertencias sobre los números nativos están bien establecidas, y yo no estaba al tanto de las matemáticas / bits.
Mike Samuel
uint 32 o 64 bits, int mismo tamaño que uint. ¿Cómo pueden ser del mismo tamaño si uno tiene un signo y el otro no?
themiDdlest
Tienen el mismo tamaño de bit, no tienen los mismos valores máximos / mínimos. Uno de los bits de ese tamaño es el bit de signo. (la /2parte es lo que elimina ese bit de consideración al calcular el tamaño de min / max para int64)
Will Palmer
4

Una forma de resolver este problema es obtener los puntos de partida de los valores mismos:

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

Un paquete liviano los contiene (así como otros límites de tipos int y algunas funciones enteras ampliamente utilizadas):

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
fuente
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
fuente