Der Maximalwert für einen int-Typ in Go

132

Wie gibt man den Maximalwert an, der für einen unsignedInteger-Typ darstellbar ist?

Ich möchte wissen, wie man minin der folgenden Schleife initialisiert , die iterativ die minimalen und maximalen Längen einiger Strukturen berechnet.

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
}

damit das erste mal durch den vergleich , minLen >= n.

Mike Samuel
quelle
2
Schauen Sie sich dieses Snippet an, int(^uint(0) >> 1) // largest intdas aus golang.org/doc/effective_go.html#printing
Victor

Antworten:

218

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

Der deutsche Teil:

Da Ganzzahltypen die Zweierkomplementarithmetik verwenden, können Sie die Min / Max-Konstantenwerte für intund ableiten uint. Beispielsweise,

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

Gemäß dem Kommentar von @ 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
quelle
65
Verwenden Sie die , die in math: golang.org/pkg/math/#pkg-constants , würden Sie wollen , math.MaxInt32am wahrscheinlichsten.
Charles L.
7
Kann jemand genau erklären, was ^ uint (0) und ^ uint (0) >> 1 tun?
Arijoon
16
@Arijoon, ^ bedeutet invertierte Bits im Ausdruck. Wenn also: uint (0) == 0000 ... 0000 (genau 32 oder 64 Nullbits, abhängig von der Build-Zielarchitektur), dann ^ unit (0) == 1111 ... 1111 Dies gibt uns den Maximalwert für die vorzeichenlose Ganzzahl (alle). Wenn Sie nun von einer vorzeichenbehafteten Ganzzahl sprechen, wird das erste (höchstwertige) Bit verwendet, um das Vorzeichen auf den vorzeichenbehafteten int-Maximalwert zu speichern. Wir müssen alle Bits nach rechts verschieben, was uns ^ uint (0) >> 1 = ergibt = 0111 ... 1111. Welches gibt die maximale positive ganze Zahl.
Ninjaboy
4
@ CharlesL. Was ist mit nur int Typ?
user960567
1
Ich weiß, es ist einige Zeit her, aber nur für den Fall, dass heute jemand hierher kommt und @ user960567s Frage-Kommentar sieht: Der intTyp ist auf einem 32-Bit-System 32 Bit lang und auf einem 64-Bit-System 64 Bit lang. Siehe hier .
Christoph Harms-Ensink
73

https://golang.org/ref/spec#Numeric_types für physikalische Typbeschränkungen.

Die Maximalwerte werden im Mathematikpaket definiert, also in Ihrem Fall: math.MaxUint32

Achten Sie darauf, dass kein Überlauf auftritt. Wenn Sie das Maximum überschreiten, wird dies umgangen.

Gelöscht
quelle
2
Vielen Dank. Ich benutze eigentlich uintnicht uint32. Die lenund capVerwendung intnicht int32so möchte ich nutzen , um etwas, das die Größe von denen auf allen Architekturen übereinstimmt. math/const.godefiniert eine Reihe von, Max<type>aber keine für entweder uintoder `int.
Mike Samuel
Ich würde es dann in uint32 oder unit64 ändern, um sicherzustellen, dass es über Architekturen hinweg portierbar ist. Ich mache das mit allem religiös. Ich habe jahrelang die Hölle durchgemacht, um C zwischen Architekturen zu portieren, und ich kann sagen, dass "explizit sein" später erheblich helfen wird.
Gelöscht
Vielen Dank. Mein Code hat dies überprüft, uint(len(...)) < thing.minLenaber ich weiß nicht, ob uint64(int)definiertes Verhalten ist und bleiben wird.
Mike Samuel
1
Wenn Sie es nicht wissen, lesen Sie die oben verlinkte Spezifikation ... speziell golang.org/doc/go_spec.html#Conversions . Es gibt eine sorgfältige Definition von "Konvertierungen zwischen numerischen Typen".
Anschel Schaffer-Cohen
29

Ich würde das mathPaket verwenden, um den Maximalwert und den Minimalwert zu erhalten:

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
}

Ausgabe:

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
quelle
1
Dieser Code funktioniert nicht. Der int64Überlauf der beiden int, was passiert, wenn Sie Konstanten vor der String-Interpolation nicht explizit eingeben. Verwenden Sie int64(math.MaxInt64)stattdessen, siehe stackoverflow.com/questions/16474594/…
domoarigato
3
Aber sonst ist eine bessere Antwort als die akzeptierte. :)
Domoarigato
Was passiert, wenn Sie int64 auf einem Computer mit 32-Bit-Wortgröße verwenden? in C entscheidet der Compiler den INT_MIN
segue_segway
12

Ich habe ursprünglich den Code aus dem Diskussionsthread verwendet, den @nmichaels in seiner Antwort verwendet hat. Ich benutze jetzt eine etwas andere Berechnung. Ich habe einige Kommentare eingefügt, falls jemand die gleiche Abfrage wie @Arijoon hat

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
)

Die letzten beiden Schritte funktionieren aufgrund der Darstellung positiver und negativer Zahlen in der Zweierkomplementarithmetik. Der Abschnitt zur Go-Sprachspezifikation für numerische Typen verweist den Leser auf den entsprechenden Wikipedia-Artikel . Ich habe das nicht gelesen, aber ich habe aus dem Buch Code von Charles Petzold , das eine sehr leicht zugängliche Einführung in die Grundlagen von Computern und Codierung darstellt, etwas über die Ergänzung von zwei gelernt .

Ich habe den obigen Code (abzüglich der meisten Kommentare) in ein kleines ganzzahliges Mathematikpaket eingefügt .

Crantok
quelle
9

Kurze Zusammenfassung:

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

Hintergrund:

Wie Sie wahrscheinlich wissen, hat der uintTyp die gleiche Größe wie entweder uint32oder uint64, abhängig von der Plattform, auf der Sie sich befinden. Normalerweise würde man die nicht dimensionierte Version davon nur verwenden, wenn kein Risiko besteht, sich dem Maximalwert anzunähern, da die Version ohne Größenangabe je nach Plattform den "nativen" Typ verwenden kann, der tendenziell schneller ist.

Beachten Sie, dass es tendenziell "schneller" ist, da die Verwendung eines nicht nativen Typs manchmal zusätzliche Berechnungen und Grenzüberprüfungen durch den Prozessor erfordert, um die größere oder kleinere Ganzzahl zu emulieren. Beachten Sie vor diesem Hintergrund, dass die Leistung des Prozessors (oder des optimierten Codes des Compilers) fast immer besser ist als das Hinzufügen eines eigenen Codes zur Überprüfung der Grenzen. Wenn also das Risiko besteht, dass dieser ins Spiel kommt, kann dies zu einer Beeinträchtigung führen Es ist sinnvoll, einfach die Version mit fester Größe zu verwenden und die optimierte Emulation alle daraus resultierenden Folgen bewältigen zu lassen.

Nachdem dies gesagt wurde, gibt es immer noch Situationen, in denen es nützlich ist zu wissen, mit was Sie arbeiten.

Das Paket " math / bits " enthält die Größe von uintin Bits. Um den Maximalwert zu bestimmen, verschieben Sie 1um so viele Bits minus 1. Das heißt:(1 << bits.UintSize) - 1

Beachten Sie, dass Sie bei der Berechnung des Maximalwerts von im uintAllgemeinen explizit in eine uint(oder eine größere) Variable einfügen müssen, da der Compiler sonst möglicherweise fehlschlägt, da standardmäßig versucht wird, diese Berechnung einer signierten int(wo, wie sollte) zuzuweisen offensichtlich sein, es würde nicht passen), also:

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

Das ist die direkte Antwort auf Ihre Frage, aber es gibt auch einige verwandte Berechnungen, an denen Sie interessiert sein könnten.

Gemäß der Spezifikation , uintund intsind immer gleich groß.

uint entweder 32 oder 64 Bit

int gleiche Größe wie uint

Wir können diese Konstante also auch verwenden, um den Maximalwert von zu bestimmen int, indem wir dieselbe Antwort nehmen und durch 2Subtrahieren dividieren 1. dh:(1 << bits.UintSize) / 2 - 1

Und der Minimalwert von intdurch Verschieben 1um so viele Bits und Teilen des Ergebnisses durch -2. dh:(1 << bits.UintSize) / -2

Zusammenfassend:

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

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

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

vollständiges Beispiel (sollte das gleiche sein wie unten)

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
quelle
Vielen Dank. Ihre Vorbehalte gegen native Zahlen sind gut formuliert, und ich war mir der Mathematik / Bits nicht bewusst.
Mike Samuel
uint entweder 32 oder 64 Bit, int gleiche Größe wie uint. Wie können diese gleich groß sein, wenn einer ein Schild hat und der andere nicht?
Der
Sie haben die gleiche Bitgröße, sie haben nicht die gleichen Maximal- / Minimalwerte. Eines der Bits in dieser Größe ist das Vorzeichenbit. (Der /2Teil ist das, was dieses Bit bei der Berechnung der Größe von min / max für int64 aus der Betrachtung entfernt.)
Will Palmer
4

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, die Ausgangspunkte aus den Werten selbst zu ermitteln:

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

Ein leichtes Paket enthält sie (sowie andere Grenzwerte für Int-Typen und einige weit verbreitete Ganzzahlfunktionen):

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
quelle
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
Frieden
quelle