Go'da bir int türü için maksimum değer


132

Bir unsignedtamsayı türü için gösterilebilen maksimum değer nasıl belirlenir ?

minBazı yapılardan minimum ve maksimum uzunlukları yinelemeli olarak hesaplayan aşağıdaki döngüde nasıl başlatılacağını bilmek istiyorum .

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
}

böylece ilk kez karşılaştırma yoluyla minLen >= n.


2
golang.org/doc/effective_go.html#printingint(^uint(0) >> 1) // largest int
Victor

Yanıtlar:


220

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

Alman bölümü:

Tamsayı türleri ikinin tümleyici aritmetiği kullandığınız için, min / max sabit değerleri çıkarabiliriz intve uint. Örneğin,

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

@ CarelZA'nın yorumuna göre:

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

66
Mevcut olanları kullanın math: golang.org/pkg/math/#pkg-constants , istediğiniz olur math.MaxInt32büyük ihtimalle.
Charles L.

7
Birisi ^ uint (0) ve ^ uint (0) >> 1'in tam olarak ne yaptığını açıklayabilir mi?
Arijoon

16
@Arijoon, ^ ifadedeki bitleri ters çevirmek anlamına gelir, bu nedenle eğer: uint (0) == 0000 ... 0000 (yapı hedef mimarisine bağlı olarak tam olarak 32 veya 64 sıfır bit) sonra ^ unit (0) == 1111 ... 1111 bu bize işaretsiz tam sayı (tümü) için maksimum değeri verir. Şimdi, işaretli tamsayı hakkında konuşurken, ilk önce (en önemli) bit işareti depolamak için kullanılır, bu nedenle işaretli int maksimum değerine - tüm bitleri sağa kaydırmamız gerekir ki bu da bize ^ uint (0) >> 1 = verir. = 0111 ... 1111. Bu, maksimum pozitif tamsayıyı verir.
ninjaboy

4
@CharlesL. int type ne olacak?
user960567

1
Biraz zaman geçtiğini biliyorum, ancak birisinin bugün buraya gelip @ user960567'nin Soru-Yorumunu görmesi durumunda: inttür 32 bitlik bir sistemde 32 bit uzunluğunda ve 64 bitlik bir sistemde 64 bit uzunluğundadır. Buraya bakın .
Christoph Harms-Ensink

73

Fiziksel tür sınırları için https://golang.org/ref/spec#Numeric_types .

Maksimum değerler matematik paketinde tanımlanır, bu nedenle sizin durumunuzda: math.MaxUint32

Taşma olmadığına dikkat edin - maksimum geçen süreyi artırmak sarmaya neden olur.


2
Teşekkürler. Aslında kullanıyorum uint, değil uint32. lenVe capkullanımı intdeğil int32bu yüzden tüm mimariler üzerinde bu boyutuyla eşleşen kullanımı şey istiyorum. ya da `int için math/const.gobir demet Max<type>ama hiçbiri tanımlar uint.
Mike Samuel

Mimariler arasında taşınabilir olduğundan emin olmak için onu uint32 veya unit64 olarak değiştirirdim. Bunu her şeyle dini olarak yapıyorum. Yıllarca C'yi mimariler arasında taşıyarak cehennemde bulundum ve "açık sözlü olmanın" daha sonra önemli ölçüde yardımcı olacağını söyleyebilirim.
Silinmiş

Teşekkürler. Kodumda bunu kontrol ediyor, uint(len(...)) < thing.minLenancak uint64(int)tanımlanmış davranış olup olmadığını ve kalacağını bilmiyorum .
Mike Samuel

1
Bilmiyorsanız, yukarıda bağlantısı verilen spesifikasyonu okuyun ... özellikle golang.org/doc/go_spec.html#Conversions . "Sayısal türler arasındaki dönüşümler" in dikkatli bir tanımı vardır.
Anschel Schaffer-Cohen

29

mathMaksimum değeri ve minimum değeri elde etmek için paketi kullanırdım :

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
}

Çıktı:

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

1
Bu kod çalışmıyor. İki int64açıkça dize enterpolasyon öncesinde sabitlerini yazmazsanız böyle olur 'ın taşma int. int64(math.MaxInt64)Bunun yerine kullanın , bkz. Stackoverflow.com/questions/16474594/…
domoarigato

3
Ancak aksi takdirde, kabul edilen yanıttan daha iyi bir cevaptır. :)
domoarigato

32 bit kelime boyutuna sahip bir makinede int64 kullanırsanız ne olur? C'de, derleyici INT_MIN
segue_segway

12

Başlangıçta @nmichaels'in yanıtında kullandığı tartışma dizisinden alınan kodu kullandım. Şimdi biraz farklı bir hesaplama kullanıyorum. @Arijoon ile aynı sorguya sahip başka birinin olması durumunda bazı yorumlar ekledim

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
)

Son iki adım, ikisinin tamamlayıcı aritmetiğinde pozitif ve negatif sayıların nasıl temsil edildiğinden dolayı çalışır. Sayısal türler hakkındaki Go dili belirtimi bölümü okuyucuyu ilgili Wikipedia makalesine yönlendirir . Bunu okumadım, ancak ikisinin tamamlayıcısı hakkında , bilgisayarların ve kodlamanın temellerine çok erişilebilir bir giriş olan Charles Petzold'un Code kitabından öğrendim .

Yukarıdaki kodu (yorumların çoğu eksi) küçük bir tamsayı matematik paketine koydum .


9

Hızlı özet:

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

Arka fon:

Bildiğinizi tahmin ettiğim uintgibi , bulunduğunuz platforma bağlı olarak tür uint32veya ile aynı boyutta uint64. Genellikle, bunların boyutlandırılmamış versiyonu yalnızca maksimum değere yaklaşma riski olmadığında kullanılır, çünkü boyut belirtimi olmayan sürüm, platforma bağlı olarak daha hızlı olma eğiliminde olan "yerel" türü kullanabilir.

Yerel olmayan bir tür kullanmak bazen daha büyük veya daha küçük tamsayıyı taklit etmek için işlemci tarafından gerçekleştirilecek ek matematik ve sınır denetimi gerektirdiğinden "daha hızlı" olma eğiliminde olduğuna dikkat edin. Bunu akılda tutarak, işlemcinin (veya derleyicinin optimize edilmiş kodunun) performansının neredeyse her zaman kendi sınır kontrol kodunuzu eklemekten daha iyi olacağının farkında olun, bu nedenle devreye girme riski varsa, sadece sabit boyutlu sürümü kullanmayı hissedin ve optimize edilmiş öykünmenin bundan kaynaklanan herhangi bir sonucu ele almasına izin verin.

Bununla birlikte, neyle çalıştığınızı bilmenin yararlı olduğu bazı durumlar hala var.

" Math / bit " paketi uint, bit cinsinden boyutunu içerir . Maksimum değeri belirlemek için, 1bu kadar bit kadar kaydırın, eksi 1. yani:(1 << bits.UintSize) - 1

Maksimum değerini hesaplarken, uintgenellikle bunu açıkça bir uint(veya daha büyük) değişkene koymanız gerekeceğini unutmayın ; aksi takdirde derleyici, bu hesaplamayı bir işaretli int(nerede, olması gerektiği gibi) atamaya çalışacağı için başarısız olabilir. açık olun, uygun olmaz), yani:

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

Sorunuzun doğrudan cevabı bu, ancak ilginizi çekebilecek birkaç ilgili hesaplama da var.

Göre spec , uintve inthep aynı boyda.

uint 32 veya 64 bit

int aynı boyutta uint

Bu sabiti int, aynı cevabı alıp 2çıkararak bölerek maksimum değerini belirlemek için de kullanabiliriz 1. yani:(1 << bits.UintSize) / 2 - 1

Ve minimum değeri, bu kadar bit intkaydırarak 1ve sonucu şuna bölerek -2. yani:(1 << bits.UintSize) / -2

Özetle:

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

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

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

tam örnek (aşağıdaki ile aynı olmalıdır)

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

Teşekkürler. Yerli sayısallarla ilgili uyarılarınız iyi belirtilmiş ve ben matematik / bitlerin farkında değildim.
Mike Samuel

uint ile aynı boyutta, 32 veya 64 bit. Birinin işareti varken diğeri yoksa bunlar nasıl aynı büyüklükte olabilir?
themiDlest

Aynı bit boyutuna sahipler, aynı maksimum / minimum değerlere sahip değiller. O boyuttaki bitlerin biri olan işaret bitidir. ( /2kısım, int64 için min / maks boyutunu hesaplarken bu biti dikkate almayan şeydir)
Will Palmer


4

Bu sorunu çözmenin bir yolu, başlangıç ​​noktalarını değerlerin kendilerinden almaktır:

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

1

Hafif bir paket bunları içerir (ayrıca diğer int türü limitleri ve yaygın olarak kullanılan bazı tamsayı fonksiyonları):

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

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.