Maksymalna wartość typu int w Go

142

Jak określić maksymalną wartość, jaką można przedstawić dla typu unsignedcałkowitego?

Chciałbym wiedzieć, jak zainicjować minw pętli poniżej, która iteracyjnie oblicza długości minimalne i maksymalne z niektórych struktur.

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
}

tak że po raz pierwszy przez porównania minLen >= n.

Mike Samuel
źródło
2
spójrz na ten fragment int(^uint(0) >> 1) // largest intwyodrębniony z golang.org/doc/effective_go.html#printing
Victor

Odpowiedzi:

236

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

Część niemiecka:

Ponieważ typy całkowite używają arytmetyki dopełnienia do dwóch, można wywnioskować wartości stałe min / max dla inti uint. Na przykład,

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

Zgodnie z komentarzem @ 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
źródło
79
Użyj tych dostępnych na math: golang.org/pkg/math/#pkg-constants , prawdopodobnie chcesz math.MaxInt32.
Charles L.
8
Czy ktoś może dokładnie wyjaśnić, co robią ^ uint (0) i ^ uint (0) >> 1?
Arijoon
18
@Arijoon, ^ oznacza odwrócenie bitów w wyrażeniu, więc jeśli: uint (0) == 0000 ... 0000 (dokładnie 32 lub 64 bity zerowe w zależności od architektury docelowej kompilacji) to ^ jednostka (0) == 1111 ... 1111 co daje nam maksymalną wartość dla liczby całkowitej bez znaku (wszystkie jedynki). Teraz, gdy mówimy o liczbie całkowitej ze znakiem, to pierwszy (najbardziej znaczący) bit jest używany do przechowywania znaku, a zatem do maksymalnej wartości int ze znakiem - musimy przesunąć wszystkie bity w prawo, co daje nam ^ uint (0) >> 1 = = 0111 ... 1111. Co daje maksymalną dodatnią liczbę całkowitą.
ninjaboy
4
@CharlesL. a co z typem int?
user960567
3
Wiem, że minęło trochę czasu, ale na wypadek, gdyby ktoś przyszedł tu dzisiaj i zobaczył pytanie-komentarz @ user960567: inttyp ma długość 32 bity w systemie 32-bitowym i 64 bity w systemie 64-bitowym. Zobacz tutaj .
Christoph Harms-Ensink,
75

https://golang.org/ref/spec#Numeric_types dla fizycznych ograniczeń typu.

Maksymalne wartości są zdefiniowane w pakiecie matematycznym, więc w twoim przypadku: math.MaxUint32

Uważaj, ponieważ nie ma przepełnienia - przekroczenie wartości maksymalnej powoduje zawijanie.

Usunięto
źródło
3
Dzięki. Właściwie używam uint, nie uint32. lenI capstosowanie intnie int32tak chcę użyć czegoś, co odpowiada wielkości tych wszystkich architekturach. math/const.godefiniuje kilka Max<type>, ale żaden z obu uintlub `int.
Mike Samuel
Zmieniłbym to na uint32 lub unit64, aby upewnić się, że jest przenośny w różnych architekturach. Robię to ze wszystkim religijnie. Przeszedłem przez lata piekielnego przenoszenia C pomiędzy różnymi architekturami i mogę powiedzieć, że „bycie wyraźnym” znacznie później pomoże.
Usunięto
1
Dzięki. Mój kod sprawdza to, uint(len(...)) < thing.minLenale nie wiem, czy uint64(int)jest i pozostanie zdefiniowanym zachowaniem.
Mike Samuel
1
Jeśli nie wiesz, przeczytaj specyfikację, do której link znajduje się powyżej ... a konkretnie golang.org/doc/go_spec.html#Conversions . Istnieje dokładna definicja „konwersji między typami liczbowymi”.
Anschel Schaffer-Cohen
34

Użyłbym mathpakietu do uzyskania wartości maksymalnej i minimalnej:

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
źródło
1
Ten kod nie działa. int64Przepełnienie dwóch wartości int, co się dzieje, jeśli nie podasz jawnie stałych przed interpolacją ciągów. Użyj int64(math.MaxInt64)zamiast tego, zobacz stackoverflow.com/questions/16474594/ ...
domoarigato,
3
Ale poza tym jest lepszą odpowiedzią niż zaakceptowana. :)
domoarigato
co się stanie, jeśli użyjesz int64 na maszynie z 32-bitowym rozmiarem słowa? w C kompilator decyduje o INT_MIN
segue_segway
14

Pierwotnie użyłem kodu zaczerpniętego z wątku dyskusji, którego @nmichaels użył w swojej odpowiedzi. Teraz używam nieco innego obliczenia. Dołączyłem kilka komentarzy na wypadek, gdyby ktoś inny miał takie samo zapytanie jak @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
)

Ostatnie dwa kroki działają z powodu tego, jak liczby dodatnie i ujemne są reprezentowane w arytmetyce uzupełnień do dwóch. Sekcja specyfikacji języka Go dotycząca typów liczbowych odsyła czytelnika do odpowiedniego artykułu w Wikipedii . Nie czytałem tego, ale dowiedziałem się o uzupełnieniu do dwóch z książki Code Charlesa Petzolda , która jest bardzo przystępnym wprowadzeniem do podstaw komputerów i kodowania.

Umieściłem powyższy kod (bez większości komentarzy) w małym pakiecie matematycznym całkowitoliczbowym .

crantok
źródło
11

Szybkie podsumowanie:

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

Tło:

Jak przypuszczam, wiesz, uinttyp jest tego samego rozmiaru co jeden z nich uint32lub uint64, w zależności od platformy, na której się znajdujesz. Zwykle używa się ich wersji bez rozmiaru tylko wtedy, gdy nie ma ryzyka zbliżenia się do wartości maksymalnej, ponieważ wersja bez specyfikacji rozmiaru może używać typu „natywnego”, w zależności od platformy, który jest zwykle szybszy.

Zwróć uwagę, że zwykle jest to „szybsze”, ponieważ użycie typu innego niż natywny czasami wymaga dodatkowego obliczenia matematycznego i sprawdzenia granic, które musi wykonać procesor, aby emulować większą lub mniejszą liczbę całkowitą. Mając to na uwadze, pamiętaj, że wydajność procesora (lub zoptymalizowanego kodu kompilatora) prawie zawsze będzie lepsza niż dodawanie własnego kodu sprawdzającego granice, więc jeśli istnieje jakiekolwiek ryzyko, że wejdzie on do gry, może to spowodować sens, aby po prostu użyć wersji o stałym rozmiarze i pozwolić zoptymalizowanej emulacji poradzić sobie z jakimkolwiek opadem.

Mając to na uwadze, nadal istnieją sytuacje, w których warto wiedzieć, z czym się pracuje.

Pakiet „ math / bits ” zawiera rozmiar uintw bitach. Aby określić wartość maksymalną, przesuń 1o tyle bitów, minus 1, tj .:(1 << bits.UintSize) - 1

Zwróć uwagę, że podczas obliczania maksymalnej wartości uintzazwyczaj musisz umieścić ją jawnie w uintzmiennej (lub większej), w przeciwnym razie kompilator może się nie powieść, ponieważ domyślnie spróbuje przypisać to obliczenie do podpisanej int(gdzie, jak powinno byłoby oczywiste, nie pasowałoby), więc:

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

To jest bezpośrednia odpowiedź na Twoje pytanie, ale istnieje również kilka powiązanych obliczeń, które mogą Cię zainteresować.

Według specyfikacji , uinti intzawsze są tej samej wielkości.

uint 32 lub 64 bity

int taki sam rozmiar jak uint

Więc możemy również użyć tej stałej do określenia maksymalnej wartości int, biorąc tę ​​samą odpowiedź i dzieląc ją przez 2odjęcie 1. to znaczy:(1 << bits.UintSize) / 2 - 1

I minimalna wartość int, przesuwając 1o tyle bitów i dzieląc wynik przez -2. to znaczy:(1 << bits.UintSize) / -2

W podsumowaniu:

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

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

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

pełny przykład (powinien być taki sam jak poniżej)

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
źródło
Dzięki. Twoje zastrzeżenia dotyczące rodzimych liczb są dobrze sformułowane, a ja nie byłem świadomy matematyki / bitów.
Mike Samuel
uint 32 lub 64 bity, int taki sam rozmiar jak uint. Jak mogą mieć ten sam rozmiar, jeśli jeden ma znak, a drugi nie?
themiDdlest
Mają ten sam rozmiar bitu, nie mają takich samych wartości maksymalnych / minimalnych. Jeden z bitów w tym rozmiarze to bit znaku. (ta /2część usuwa ten bit z rozważenia przy obliczaniu rozmiaru min / max dla int64)
Will Palmer
4

Jednym ze sposobów rozwiązania tego problemu jest pobranie punktów początkowych z samych wartości:

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
źródło
1

Zawiera je lekki pakiet (a także ograniczenia innych typów int i niektóre powszechnie używane funkcje liczb całkowitych):

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
źródło
1

Użyj stałych zdefiniowanych w pakiecie matematycznym :

const (
    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
)
M. Leonhard
źródło
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
Pokój
źródło