Go 中 int 类型的最大值

Posted

技术标签:

【中文标题】Go 中 int 类型的最大值【英文标题】:The maximum value for an int type in Go 【发布时间】:2011-10-16 06:06:57 【问题描述】:

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

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

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 &gt;= n

【问题讨论】:

看看从golang.org/doc/effective_go.html#printing提取的这个sn-p int(^uint(0) &gt;&gt; 1) // largest int 【参考方案1】:

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

相关部分:

由于整数类型使用二进制补码算法,您可以推断 intuint 的最小/最大常量值。例如,

const MaxUint = ^uint(0) 
const MinUint = 0 
const MaxInt = int(MaxUint >> 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

【讨论】:

使用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 类型呢? 我知道已经有一段时间了,但以防有人今天来到这里并看到@user960567 的问题评论:int 类型在 32 位系统上是 32 位长,在 64 位长64位系统。见here。【参考方案2】:

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

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

注意没有溢出 - 增加超过最大值会导致回绕。

【讨论】:

谢谢。我实际上使用的是uint,而不是uint32lencap 使用 int 而不是 int32 所以我想使用与所有架构上的大小相匹配的东西。 math/const.go 定义了一组 Max&lt;type&gt;,但对于 uint 或 `int 都没有。 我会将其更改为 uint32 或 unit64 以确保它可跨架构移植。我虔诚地对待一切。我已经经历了多年在架构之间移植 C 的地狱,我可以说“明确”将在以后有很大帮助。 谢谢。我的代码检查了uint(len(...)) &lt; thing.minLen,但我不知道uint64(int) 是否是并且将保持定义的行为。 如果您不知道,请阅读上面链接的规范...特别是golang.org/doc/go_spec.html#Conversions。 “数字类型之间的转换”有一个仔细的定义。【参考方案3】:

我会使用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

【讨论】:

此代码不起作用。两个int64 的溢出int,如果在字符串插值之前没有显式键入常量,就会发生这种情况。请改用int64(math.MaxInt64),请参阅***.com/questions/16474594/… 但除此之外,这是一个比公认的更好的答案。 :) 如果在 32 位字长的机器上使用 int64 会发生什么?在 C 中,编译器决定 INT_MIN【参考方案4】:

我最初使用的代码取自 @nmichaels 在他的回答中使用的讨论线程。我现在使用稍微不同的计算。我已经包含了一些 cmets,以防其他人有与 @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
)

最后两个步骤有效,因为正数和负数在二进制补码算术中的表示方式。 Numeric types 上的 Go 语言规范部分将读者引向相关的 Wikipedia article。我没有读过,但我确实从书 Code by Charles Petzold 中了解了二进制补码,这是一本非常容易理解的计算机和编码基础介绍。

我将上面的代码(减去大部分 cmets)放入了一点 integer math package。

【讨论】:

【参考方案5】:

快速总结:

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。即:(1 &lt;&lt; bits.UintSize) - 1

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

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

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

根据spec,uintint 的大小始终相同。

uint 32 位或 64 位

intuint大小相同

所以我们也可以使用这个常数来确定int 的最大值,方法是用同样的答案除以2,然后减去1。即:(1 &lt;&lt; bits.UintSize) / 2 - 1

还有int 的最小值,通过将1 移位那么多位并将结果除以-2。即:(1 &lt;&lt; bits.UintSize) / -2

总结:

MaxUint: (1 &lt;&lt; bits.UintSize) - 1

MaxInt: (1 &lt;&lt; bits.UintSize) / 2 - 1

MinInt: (1 &lt;&lt; bits.UintSize) / -2

full example(应与下同)

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)

【讨论】:

谢谢。您对本机数字的警告已经很好地说明了,我不知道数学/位。 uint 32 位或 64 位,int 大小与 uint 相同。如果一个有标志而另一个没有,它们怎么可能是相同的尺寸? 它们具有相同的位大小,它们没有相同的最大/最小值。该大小中的一位 符号位。 (/2 部分是在计算 int64 的 min/max 大小时不考虑该位的原因)【参考方案6】:

来自数学库: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)

【讨论】:

【参考方案7】:

使用math package中定义的常量:

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
)

【讨论】:

【参考方案8】:

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

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 
  

【讨论】:

【参考方案9】:

Go 1.17(2021 年第四季度)可能会有所帮助,commit e8eb1d8,如 Go101 所述:

在 Go 1.17 之前,我们可以使用以下技巧来定义 MaxInt

const MaxInt = int(^uint(0) >> 1)

从 Go 1.17 开始,我们可以直接使用 math.MaxInt 代替

修复了Silentd00m 报告的issue 28538,并通过CL 247058 审核。

既然我们有 int8int64 min maxuint8uint64 max 常量,我们可能也应该有一些用于字长类型的常量。

Tests 正在说明这是如何工作的:

    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)
    

【讨论】:

【参考方案10】:

Go-1.7 在math 包中定义了MaxUintMaxIntMinInt

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.7 的发布说明:https://golang.org/doc/go1.17#math

数学包现在定义了另外三个常量:MaxUintMaxIntMinInt。 对于 32 位系统,它们的值分别为 2^32 - 12^31 - 1-2^31。 对于 64 位系统,它们的值分别为 2^64 - 12^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

【讨论】:

【参考方案11】:
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

【讨论】:

【参考方案12】:

我一直记得的方式,是你拿位(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
   

【讨论】:

int 在 64 平台上是 int64【参考方案13】:

一个轻量级的package 包含它们(以及其他 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

【讨论】:

以上是关于Go 中 int 类型的最大值的主要内容,如果未能解决你的问题,请参考以下文章

golang 在Go中获取各种类型的最大最大值

一文了解 Go 标准库 math 和 rand 的常用函数

c# int型最大值

MySQL中数字类型的最大值 - int无法储存11位手机号码 - bigint, int, tinyint

MySQL中数字类型的最大值 - int无法储存11位手机号码 - bigint, int, tinyint

int类型最大值