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

我想知道如何在下面的循环中初始化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。


当前回答

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

其他回答

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

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

我最初使用的代码取自@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的补码,这是一本非常容易理解的计算机和编码基础介绍。

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