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 >= n
。
【问题讨论】:
看看从golang.org/doc/effective_go.html#printing提取的这个sn-pint(^uint(0) >> 1) // largest int
【参考方案1】:
https://groups.google.com/group/golang-nuts/msg/71c307e4d73024ce?pli=1
相关部分:
由于整数类型使用二进制补码算法,您可以推断
int
和uint
的最小/最大常量值。例如,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
,而不是uint32
。 len
和 cap
使用 int
而不是 int32
所以我想使用与所有架构上的大小相匹配的东西。 math/const.go
定义了一组 Max<type>
,但对于 uint
或 `int 都没有。
我会将其更改为 uint32 或 unit64 以确保它可跨架构移植。我虔诚地对待一切。我已经经历了多年在架构之间移植 C 的地狱,我可以说“明确”将在以后有很大帮助。
谢谢。我的代码检查了uint(len(...)) < 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
类型的大小与 uint32
或 uint64
相同,具体取决于您所在的平台。通常,只有在没有接近最大值的风险时才会使用这些未调整大小的版本,因为没有大小规范的版本可以使用“原生”类型,具体取决于平台,这往往更快。
请注意,它往往“更快”,因为使用非本机类型有时需要处理器执行额外的数学和边界检查,以模拟更大或更小的整数。考虑到这一点,请注意处理器(或编译器的优化代码)的性能几乎总是比添加您自己的边界检查代码更好,所以如果它有任何发挥作用的风险,它可能会使简单地使用固定大小的版本是有意义的,并让优化的仿真处理由此产生的任何后果。
话虽如此,但在某些情况下,了解您正在处理的内容仍然很有用。
包“math/bits”包含uint
的大小,以位为单位。要确定最大值,请将1
移动那么多位,减去 1。即:(1 << bits.UintSize) - 1
请注意,在计算 uint
的最大值时,您通常需要将其显式放入 uint
(或更大)变量中,否则编译器可能会失败,因为它会默认尝试分配该变量计算成一个有符号的int
(应该很明显,它不适合),所以:
const MaxUint uint = (1 << bits.UintSize) - 1
这是对您问题的直接答案,但您可能还对一些相关的计算感兴趣。
根据spec,uint
和int
的大小始终相同。
uint
32 位或 64 位
int
与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
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 审核。
既然我们有
int8
到int64
min
max
和uint8
到uint64
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 包中定义了MaxUint
、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.7 的发布说明:https://golang.org/doc/go1.17#math
提交:https://github.com/golang/go/commit/e8eb1d82 文档:https://pkg.go.dev/math#pkg-constants数学包现在定义了另外三个常量:
MaxUint
、MaxInt
和MinInt
。 对于 32 位系统,它们的值分别为2^32 - 1
、2^31 - 1
和-2^31
。 对于 64 位系统,它们的值分别为2^64 - 1
、2^63 - 1
和-2^63
。
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 类型的最大值的主要内容,如果未能解决你的问题,请参考以下文章
MySQL中数字类型的最大值 - int无法储存11位手机号码 - bigint, int, tinyint