如何为无符号整数类型指定可表示的最大值?

我想知道如何在下面的循环中初始化min,迭代计算一些结构的min和max长度。

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
}

使第一次通过比较,minLen >= n。


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

相关部分:

由于整数类型使用二补运算,因此可以推断 int和uint的最小/最大常量值。例如, const maxint = ^uint(0) const MinUint = 0 const MaxInt = int(MaxInt >> 1) const MinInt = - maxint - 1

根据@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

https://golang.org/ref/spec#Numeric_types为物理类型限制。

最大值是在math包中定义的,在你的例子中是math。MaxUint32

注意,因为没有溢出-超过最大值的增量会导致环绕。


解决这个问题的一种方法是从值本身获取起始点:

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

我最初使用的代码取自@nmichaels在他的回答中使用的讨论线程。现在我用了一个稍微不同的计算方法。我附上了一些评论,以防其他人有和@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
)

最后两个步骤是有效的,因为正数和负数在2的补数算术中是如何表示的。关于数字类型的Go语言规范部分建议读者参考维基百科的相关文章。我还没有读过,但我确实从Charles Petzold的Code一书中了解了two的补码,这是一本非常容易理解的计算机和编码基础介绍。

我将上面的代码(减去大部分注释)放入一个小整数数学包中。


我将使用math包来获取整数的最大值和最小值:

package main

import (
    "fmt"
    "math"
)

func main() {
    // 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 float64 = %+v\n", math.MaxFloat64)
    fmt.Printf("max float32 = %+v\n", math.MaxFloat32)

    // etc you can see more int the `math`package
}

输出:

max int64   = 9223372036854775807
max int32   = 2147483647
max int16   = 32767
min int64   = -9223372036854775808
min int32   = -2147483648
max float64 = 1.7976931348623157e+308
max float32 = 3.4028234663852886e+38

注意:这个答案在go 1.17中被取代,其中包括e8eb1d8;例如:math包现在包含了用于math的常量。MaxUint,数学。MaxInt和math。minint。

快速总结:

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

背景:

我假设你知道,uint类型的大小与uint32或uint64相同,这取决于你所在的平台。通常,只有在没有接近最大值的风险时,才会使用这些类型的非大小版本,因为没有大小规范的版本可以使用“本机”类型,这取决于平台,往往更快。

Note that it tends to be "faster" because using a non-native type sometimes requires additional math and bounds-checking to be performed by the processor, in order to emulate the larger or smaller integer. With that in mind, be aware that the performance of the processor (or compiler's optimised code) is almost always going to be better than adding your own bounds-checking code, so if there is any risk of it coming into play, it may make sense to simply use the fixed-size version, and let the optimised emulation handle any fallout from that.

尽管如此,在某些情况下,了解自己在处理什么还是很有用的。

“math/bits”包包含uint的大小,以比特为单位。要确定最大值,将1移位那么多位,减去1。例如:(1 << bits.UintSize) - 1

注意,在计算uint的最大值时,你通常需要将它显式地放入一个uint(或更大的)变量中,否则编译器可能会失败,因为它将默认尝试将该计算分配到一个带符号的int中(很明显,它不适合),因此:

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

这是对你问题的直接回答,但还有一些相关的计算你可能会感兴趣。

根据规范,uint和int的大小总是相同的。

单位32或64位 Int与uint大小相同

所以我们也可以用这个常数来确定int的最大值,通过取相同的答案,然后除以2再减去1。ie:(1 << bits.UintSize) / 2 - 1

int的最小值,通过将1移动这么多位然后除以-2得到。ie:(1 << bits.UintSize) / -2

总而言之:

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

最小化:/ 2 - 1

薄荷糖:(1 << tbits .UintSize) / -2

完整示例(应与下面相同)

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

来自数学库:https://github.com/golang/go/blob/master/src/math/const.go#L39

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("max int64: %d\n", math.MaxInt64)
}

一个轻量级包包含了它们(以及其他int类型的限制和一些广泛使用的整数函数):

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

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

使用数学包中定义的常量:

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
)

我一直记得的方法是,取比特(int8是8位,int是 32位),除以8,你得到字节(int8将是一个字节,int 应该是四个字节)。

每个字节都是0xFF(有符号整数除外,在这种情况下是最有效的 字节将是0x7F)。结果如下:

package main

func main() {
   {
      var n int8 = 0x7F
      println(n) // 127
   }
   {
      var n uint8 = 0xFF
      println(n) // 255
   }
   {
      var n int = 0x7FFF_FFFF
      println(n) // 2147483647
   }
   {
      var n uint = 0xFFFF_FFFF
      println(n) // 4294967295
   }
}

Go 1.17(2021年第四季度)可能会有所帮助,提交e8eb1d8,正如Go101所指出的:

在Go 1.17之前,我们可以使用下面的技巧来定义MaxInt: const MaxInt = int(^uint(0) >> 1) 从Go 1.17开始,我们可以直接使用数学。MaxInt相反

修复了Silentd00m报告的问题28538,并使用CL 247058进行了审查。

由于我们有int8到int64 min max和uint8到uint64 max常量,我们可能也应该有一些字大小类型。

测试说明了这是如何工作的:

    if v := int(MaxInt); v+1 != MinInt {
        t.Errorf("MaxInt should wrap around to MinInt: %d", v+1)
    }
    if v := int8(MaxInt8); v+1 != MinInt8 {
        t.Errorf("MaxInt8 should wrap around to MinInt8: %d", v+1)
    }
    if v := int16(MaxInt16); v+1 != MinInt16 {
        t.Errorf("MaxInt16 should wrap around to MinInt16: %d", v+1)
    }
    if v := int32(MaxInt32); v+1 != MinInt32 {
        t.Errorf("MaxInt32 should wrap around to MinInt32: %d", v+1)
    }
    if v := int64(MaxInt64); v+1 != MinInt64 {
        t.Errorf("MaxInt64 should wrap around to MinInt64: %d", v+1)
    }

Go-1.17现在在数学包中定义了MaxInt, MaxInt和MinInt常量。

package main

import "fmt"
import "math"

const maxUint = uint(math.MaxUint)

func main() {
    fmt.Println("Integer range on your system")

    // .Println("MaxUint:", math.MaxUint)  ERROR constant 18446744073709551615 overflows int
    fmt.Println("MaxUint:", maxUint)

    fmt.Println("MinInt:", math.MinInt)
    fmt.Println("MaxInt:", math.MaxInt)
}

测试上面的代码:https://play.golang.org/p/5R2iPasn6OZ 来自Go 1.17发布说明:https://golang.org/doc/go1.17#math

数学包现在又定义了三个常量:MaxInt、MaxInt和MinInt。 对于32位系统,它们的值分别是2^32 - 1,2 ^31 - 1和-2^31。 对于64位系统,它们的值分别是2^64 - 1,2 ^63 - 1和-2^63。

提交:https://github.com/golang/go/commit/e8eb1d82 文档:https://pkg.go.dev/math pkg-constants

const (
    MaxInt    = 1<<(intSize-1) - 1   // New
    MinInt    = -1 << (intSize - 1)  // New
    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
    MaxUint   = 1<<intSize - 1       // New
    MaxUint8  = 1<<8 - 1
    MaxUint16 = 1<<16 - 1
    MaxUint32 = 1<<32 - 1
    MaxUint64 = 1<<64 - 1
)

参见Go源代码:https://github.com/golang/go/blob/master/src/math/const.go#L39