Jef*_*eff 1 time integer go unsigned-integer
我有一个包含负数的int64变量,我希望从包含一个正数的uint64变量中减去它:
var endTime uint64
now := time.Now().Unix()
endTime = uint64(now)
var interval int64
interval = -3600
endTime = endTime + uint64(interval)
Run Code Online (Sandbox Code Playgroud)
上面的代码似乎有效,但是我想知道是否可以依靠它。对于Go语言的新手,我感到很惊讶,在将负数强制转换为uint64后仍保持负数-我计划减去(正数后)正值(强制转换后)以获得所需的值。
将带符号的数字转换为无符号的数字不会保持负数,而是保持负数,因为有效范围的无符号类型不包含负数。如果您打印uint(interval),则肯定会看到一个正数。
您所经历的是确定性的,您可以依靠它(但这并不意味着您应该这样做)。这是Go(和大多数其他编程语言)使用2的完成表示形式存储带符号整数类型的结果。
这意味着在负数的情况下,使用n位将值-x(其中x为正)存储为正值的二进制表示形式2^n - x。这样做的好处是可以按位相加数字,并且无论它们是负数还是正数,结果都是正确的。
因此,当您拥有带负号的负数时,它基本上存储在内存中,就像您要从中减去其绝对值一样0。这意味着,如果将负的有符号值转换为无符号值,然后将其添加到无符号值,则结果将是正确的,因为会以一种有用的方式发生溢出。
转换类型的值int64,以uint64不改变存储器布局,只有类型。所以有8个字节int64,转换后的uint64将具有相同的8个字节。并且如上所述,存储在这8个字节中的表示是与value的位模式相同的位模式0 - abs(x)。因此,转换的结果将是在无符号世界中abs(x)从中减去所得到的数字0。是的,这不会是负数(因为类型是无符号的),而是一个“大”数字,从uint64类型的最大值开始递减。但是,如果将一个y大于abs(x)这个“大”数字的数字相加,则会发生溢出,并且结果将类似于y - abs(x)。
请看这个简单的示例,演示发生了什么(在Go Playground上尝试一下):
a := uint8(100)
b := int8(-10)
fmt.Println(uint8(b)) // Prints 226 which is: 0 - 10 = 256 - 10
a = a + uint8(b)
fmt.Println(a) // Prints 90 which is: 100 + 226 = 326 = 90
// after overflow: 326 - 256 = 90
Run Code Online (Sandbox Code Playgroud)
如上所述,您不应依赖于此,因为这可能会引起混乱。如果打算使用负数,请使用带符号的类型。
而且,如果您使用的代码库已经使用了uint64值,那么请使用值进行减法运算而不是加法运算uint64:
interval := uint64(3600)
endTime -= interval
Run Code Online (Sandbox Code Playgroud)
另请注意,如果您有time.Time值,则应利用其Time.Add()方法:
func (t Time) Add(d Duration) Time
Run Code Online (Sandbox Code Playgroud)
您可以指定time.Duration要添加的时间,如果要返回到时间,则可以为负,如下所示:
t := time.Now()
t = t.Add(-3600 * time.Second)
Run Code Online (Sandbox Code Playgroud)
time.Duration 更具表现力:我们看到上面指定的值明确使用秒。
| 归档时间: |
|
| 查看次数: |
1134 次 |
| 最近记录: |