Nilai maksimum untuk tipe int di Go

132

Bagaimana cara menentukan nilai maksimum yang dapat diwakili untuk unsignedtipe integer?

Saya ingin tahu bagaimana menginisialisasi mindalam loop di bawah ini yang secara iteratif menghitung panjang min dan max dari beberapa struct.

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
}

sehingga pertama kali melalui perbandingan minLen >= n,.

Mike Samuel
sumber
2
Lihatlah cuplikan ini int(^uint(0) >> 1) // largest intdiekstrak dari golang.org/doc/effective_go.html#printing
Victor

Jawaban:

218

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

Bagian erat:

Karena tipe integer menggunakan aritmatika komplemen dua, Anda dapat menyimpulkan nilai konstan min / max untuk intdan uint. Sebagai contoh,

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

Sesuai komentar @ 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
sumber
66
Gunakan yang tersedia di math: golang.org/pkg/math/#pkg-constants , yang paling Anda inginkan math.MaxInt32.
Charles L.
7
Adakah yang bisa menjelaskan dengan tepat apa yang ^ uint (0) dan ^ uint (0) >> 1 lakukan?
Arijoon
16
@Arijoon, ^ berarti membalikkan bit dalam ekspresi jadi jika: uint (0) == 0000 ... 0000 (tepatnya 32 atau 64 bit nol tergantung pada arsitektur target build) maka ^ unit (0) == 1111 ... 1111 yang memberi kami nilai maksimum untuk bilangan bulat yang tidak ditandatangani (semuanya). Sekarang ketika Anda berbicara tentang integer yang ditandatangani, maka bit pertama (yang paling signifikan) digunakan untuk menyimpan tanda karena itu ke nilai maksimum int yang ditandatangani - kita perlu menggeser semua bit ke kanan yang memberi kita ^ uint (0) >> 1 = = 0111 ... 1111. Yang memberikan bilangan bulat positif maksimum.
ninjaboy
4
@CharlesL. bagaimana dengan tipe int saja?
user960567
1
Saya tahu ini sudah lama, tapi kalau-kalau ada orang datang ke sini hari ini dan melihat Pertanyaan-Komentar @ user960567: intjenisnya panjang 32 bit pada sistem 32 bit dan 64 bit panjang pada sistem 64 bit. Lihat di sini .
Christoph Harms-Ensink
73

https://golang.org/ref/spec#Numeric_types untuk batas tipe fisik.

Nilai-nilai maks didefinisikan dalam paket matematika sehingga dalam kasus Anda: math.MaxUint32

Berhati-hatilah karena tidak ada overflow - penambahan max yang lalu menyebabkan sampul.

Dihapus
sumber
2
Terima kasih. Saya sebenarnya menggunakan uint, bukan uint32. The lendan cappenggunaan inttidak int32jadi saya ingin menggunakan sesuatu yang sesuai dengan ukuran mereka pada semua arsitektur. math/const.gomendefinisikan sekelompok Max<type>tetapi tidak ada untuk salah uintatau `int.
Mike Samuel
Saya akan mengubahnya menjadi uint32 atau unit64 kemudian untuk memastikan itu portabel di seluruh arsitektur. Saya melakukan itu dengan segalanya secara religius. Saya telah melalui bertahun-tahun neraka porting C antara arsitektur dan saya dapat mengatakan bahwa "menjadi eksplisit" akan sangat membantu nantinya.
Dihapus
Terima kasih. Kode saya sudah memeriksa itu, uint(len(...)) < thing.minLentetapi saya tidak tahu apakah uint64(int)itu perilaku tetap dan akan didefinisikan.
Mike Samuel
1
Jika Anda tidak tahu maka bacalah spec yang ditautkan di atas ... khusus golang.org/doc/go_spec.html#Conversions . Ada definisi yang cermat tentang "konversi antar jenis numerik".
Anschel Schaffer-Cohen
29

Saya akan menggunakan mathpaket untuk mendapatkan nilai maksimal dan nilai minimal:

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
sumber
1
Kode ini tidak berfungsi. int64Overflow int keduanya , yang terjadi jika Anda tidak secara eksplisit mengetikkan konstanta sebelum interpolasi string. Gunakan int64(math.MaxInt64)sebaliknya, lihat stackoverflow.com/questions/16474594/…
domoarigato
3
Tetapi sebaliknya, adalah jawaban yang lebih baik daripada yang diterima. :)
domoarigato
apa yang terjadi jika Anda menggunakan int64 pada mesin dengan ukuran kata 32-bit? dalam C, kompilator memutuskan INT_MIN
segue_segway
12

Saya awalnya menggunakan kode yang diambil dari utas diskusi yang @nmichaels gunakan dalam jawabannya. Saya sekarang menggunakan perhitungan yang sedikit berbeda. Saya telah memasukkan beberapa komentar jika ada orang lain yang memiliki pertanyaan yang sama dengan @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
)

Dua langkah terakhir bekerja karena bagaimana angka positif dan negatif direpresentasikan dalam aritmatika komplemen dua. Bagian spesifikasi bahasa Go pada tipe Numerik merujuk pembaca ke artikel Wikipedia yang relevan . Saya belum membaca itu, tapi saya belajar tentang pelengkap dua dari buku Code oleh Charles Petzold , yang merupakan pengantar yang sangat mudah diakses dengan dasar-dasar komputer dan pengkodean.

Saya memasukkan kode di atas (minus sebagian besar komentar) ke dalam paket matematika integer kecil .

Crantok
sumber
9

Ringkasan cepat:

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

Latar Belakang:

Seperti yang saya kira Anda tahu, uintjenisnya adalah ukuran yang sama uint32atau uint64, tergantung pada platform Anda. Biasanya, seseorang akan menggunakan versi unsized ini hanya ketika tidak ada risiko mendekati nilai maksimum, karena versi tanpa spesifikasi ukuran dapat menggunakan tipe "asli", tergantung pada platform, yang cenderung lebih cepat.

Perhatikan bahwa itu cenderung "lebih cepat" karena menggunakan tipe non-asli kadang-kadang membutuhkan matematika tambahan dan pemeriksaan batas yang harus dilakukan oleh prosesor, untuk meniru bilangan bulat yang lebih besar atau lebih kecil. Dengan mengingat hal tersebut, ketahuilah bahwa kinerja prosesor (atau kode yang dioptimalkan kompiler) hampir selalu akan lebih baik daripada menambahkan kode pemeriksaan batas Anda sendiri, jadi jika ada risiko prosesor ikut bermain, itu mungkin membuat akal untuk hanya menggunakan versi ukuran tetap, dan biarkan emulasi yang dioptimalkan menangani dampak dari itu.

Dengan itu, masih ada beberapa situasi di mana berguna untuk mengetahui apa yang Anda kerjakan.

Paket " math / bits " berisi ukuran uint, dalam bits. Untuk menentukan nilai maksimum, bergeser 1dengan banyak bit itu, minus 1. yaitu:(1 << bits.UintSize) - 1

Perhatikan bahwa ketika menghitung nilai maksimum uint, Anda biasanya harus memasukkannya secara eksplisit ke dalam uintvariabel (atau lebih besar), jika tidak kompiler akan gagal, karena akan gagal untuk menetapkan penetapan perhitungan ke dalam tanda tangan int(di mana, sebagaimana seharusnya menjadi jelas, itu tidak akan cocok), jadi:

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

Itulah jawaban langsung untuk pertanyaan Anda, tetapi ada juga beberapa perhitungan terkait yang mungkin menarik bagi Anda.

Menurut spesifikasi , uintdanint ukurannya selalu sama.

uint baik 32 atau 64 bit

int ukuran yang sama dengan uint

Jadi kita juga dapat menggunakan konstanta ini untuk menentukan nilai maksimum int, dengan mengambil jawaban yang sama dan membaginya dengan 2kemudian mengurangi 1. yaitu:(1 << bits.UintSize) / 2 - 1

Dan nilai minimum int, dengan menggeser 1banyak bit dan membagi hasilnya dengan -2. yaitu:(1 << bits.UintSize) / -2

Singkatnya:

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

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

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

contoh lengkap (harus sama dengan di bawah ini)

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
sumber
Terima kasih. Peringatan Anda tentang angka asli dinyatakan dengan baik, dan saya tidak mengetahui matematika / bit.
Mike Samuel
uint baik 32 atau 64 bit, ukuran int sama seperti uint. Bagaimana ini bisa menjadi ukuran yang sama jika satu memiliki tanda dan yang lainnya tidak?
themiDdlest
Mereka memiliki ukuran bit yang sama, mereka tidak memiliki nilai maksimum / minimum yang sama. Salah satu bit dalam ukuran itu adalah bit tanda. ( /2bagian inilah yang menghilangkan bit itu dari pertimbangan ketika menghitung ukuran min / maks untuk int64)
Will Palmer
4

Salah satu cara untuk mengatasi masalah ini adalah dengan mendapatkan titik awal dari nilai-nilai itu sendiri:

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

Paket ringan berisi mereka (serta batas tipe int lainnya dan beberapa fungsi integer yang banyak digunakan):

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
sumber
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
Perdamaian
sumber