如何指定unsigned整数类型可表示的最大值?

我想知道如何在下面的循环中初始化min,该循环从某些结构迭代计算最小和最大长度。

1
2
3
4
5
6
7
8
9
10
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

  • 看看从golang.org/doc/effective_go.html#printing中提取的此片段int(^uint(0) >> 1) largest int

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

德语部分:

Since integer types use two's complement arithmetic, you can infer the
min/max constant values for int and uint. For example,

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

根据@CarelZA的评论:

1
2
3
4
5
6
7
8
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
  • 使用math中可用的内容:golang.org/pkg/math/#pkg-constants,您最希望math.MaxInt32
  • 有人可以确切解释^ uint(0)和^ uint(0)>> 1做什么吗?
  • @Arijoon,^表示表达式中的反转位,因此如果:uint(0)== 0000 ... 0000(取决于构建目标体系结构,则为32或64个零位),则^ unit(0)== 1111 ... 1111这为我们提供了无符号整数(全1)的最大值。现在,当您谈论带符号的整数时,第一个(最高有效)位用于存储符号,因此为带符号的int最大值-我们需要将所有位右移,这使我们获得^ uint(0)>> 1 = = 0111 ... 1111。给出最大正整数。
  • @CharlesL。只是int类型呢?
  • 我知道已经有一段时间了,但是以防万一有人今天来到这里并看到@ user960567s问题注释:int类型在32位系统上为32位长,在64位系统上为64位长。看这里。
  • 这种脆性和不透明性,并与二进制补码表示联系在一起吗?为什么不使用math.MaxInt16等?
  • @Jehan,因为有关int和int的主题是int32或int 64,不能为int16。

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

最大值在math软件包中定义,因此在您的情况下为:math.MaxUint32

当心,因为没有溢出-超过最大值会导致环绕。

  • 谢谢。我实际上使用的是uint,而不是uint32lencap使用的是int而不是int32,因此我想使用与所有体系结构的大小都匹配的东西。 mathconst.go定义了一堆Max,但没有为uint或`int定义。
  • 将其ID更改为uint32或unit64,然后确保其可跨体系结构移植。我认真地做所有事情。在将C移植到体系结构之间已经经历了多年的艰辛,我可以说"显式"将在以后提供很大帮助。
  • 谢谢。我的代码检查了uint(len(...)) < thing.minLen,但我不知道uint64(int)是否并且将保持定义的行为。
  • 如果您不知道,请阅读上面链接的规范...特别是golang.org/doc/go_spec.html#Conversions。对于"数字类型之间的转换"有一个仔细的定义。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func printMinMaxValue() {
    // integer max
    fmt.Printf("max int64 = %+v\
", math.MaxInt64)
    fmt.Printf("max int32 = %+v\
", math.MaxInt32)
    fmt.Printf("max int16 = %+v\
", math.MaxInt16)

    // integer min
    fmt.Printf("min int64 = %+v\
", math.MinInt64)
    fmt.Printf("min int32 = %+v\
", math.MinInt32)

    fmt.Printf("max flloat64= %+v\
", math.MaxFloat64)
    fmt.Printf("max float32= %+v\
", math.MaxFloat32)

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

Ouput:

1
2
3
4
5
6
7
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
  • 此代码不起作用。两个int64 s溢出int,如果没有在字符串插值之前显式键入常量,则会发生这种情况。请使用int64(math.MaxInt64),请参阅stackoverflow.com/questions/16474594/
  • 但除此之外,这是一个比公认的更好的答案。 :)
  • 如果在32位字长的计算机上使用int64,会发生什么情况?在C中,编译器决定INT_MIN

我最初使用了@nmichaels在他的答案中使用的讨论线程中的代码。我现在使用略有不同的计算。如果其他人与@Arijoon有相同的查询,我已经添加了一些评论

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
)

后两个步骤之所以有效,是因为在二进制补码运算中正数和负数的表示方式。有关数字类型的Go语言规范部分,请读者参考相关的Wikipedia文章。我还没有读过,但是我确实从Charles Petzold的《代码》一书中了解了二进制补码,这是对计算机和编码基础知识的入门。

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


快速总结:

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

背景:

如我所知,uint类型的大小与uint32uint64相同,这取决于所使用的平台。通常,只有在没有接近最大值的风险时才使用这些版本的未调整大小版本,因为没有大小规格的版本可以使用"本地"类型,具体取决于平台,这往往会更快。

请注意,它趋向于"更快",因为使用非本机类型有时需要处理器执行额外的数学运算和边界检查,以模拟更大或更小的整数。考虑到这一点,请注意,处理器(或编译器的优化代码)的性能几乎总是比添加自己的边界检查代码更好,因此,如果有发挥作用的风险,它可能会使简单地使用固定大小的版本,并让优化的仿真处理由此产生的任何后果是合理的。

说了这么多,在某些情况下了解您正在使用的内容很有用。

包" math / bits"包含uint的大小(以位为单位)。要确定最大值,请将1移位-1。

请注意,在计算uint的最大值时,通常需要将其显式放入uint(或更大)变量中,否则编译器可能会失败,因为它将默认尝试将该计算分配给已签名的int(显然不适合),因此:

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

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

根据规范,uintint总是相同的大小。

uint either 32 or 64 bits

int same size as uint

因此,我们也可以使用该常数来确定int的最大值,方法是采用相同的答案并除以2,然后减去1。即:(1 << bits.UintSize) / 2 - 1

int的最小值,方法是将1移位那么多位,然后将结果除以-2。即:(1 << bits.UintSize) / -2

综上所述:

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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\
", mi32)
    fmt.Printf(" MaxInt32:  %d\
", i32)
    fmt.Printf("MaxUint32:  %d\
", ui32)
    fmt.Printf(" MinInt64: %d\
", mi64)
    fmt.Printf(" MaxInt64:  %d\
", i64)
    fmt.Printf("MaxUint64:  %d\
", ui64)
    fmt.Printf("  MaxUint:  %d\
", ui)
    fmt.Printf("   MinInt: %d\
", mi)
    fmt.Printf("   MaxInt:  %d\
", i)
}
  • 谢谢。您对本机数字的注意事项已明确陈述,我不知道数学/位。
  • uint 32或64位,int与uint相同。如果一个有一个符号而另一个没有一个符号,它们怎么能一样大小?
  • 它们具有相同的位大小,没有相同的最大值/最小值。该大小的位之一是符号位。 (2部分是在计算int64的最小/最大大小时从考虑中除去该位的部分)

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

1
2
3
4
5
6
7
8
9
10
11
package main

import (
   "fmt"
   "math"
)

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

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

1
2
3
4
5
6
7
8
9
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
2
3
4
5
6
7
8
9
10
11
12
13
14
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
)

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

1
2
3
4
5
6
7
8
9
10
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

1
2
3
4
5
6
7
8
9
10
11
12
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