Golang中Int32转换为int16丢失精度的具体过程
1.类型转换代码
Int32转换为int16会丢失精度,这是总所周知的,但是具体如何丢失精度的,请看下面的代码:
var tmp1 int32 = 123424021
var tmp2 int16
var tmp3 uint16
tmp2 = int16(tmp1)
tmp3 = uint16(tmp1)
fmt.Printf("0x%x,%b,%d\n",tmp1,tmp1,tmp1);
fmt.Printf("0x%x,%b,%d\n",tmp2,tmp2,tmp2);
fmt.Printf("0x%x,%b,%d\n",tmp3,tmp3,tmp3);
fmt.Printf("====================================\n")
var t1 int32 = 123456789
var t2 int16
var t3 uint16
t2 = int16(t1)
t3 = uint16(t1)
fmt.Printf("0x%x,%b,%d\n",t1,t1,t1);
fmt.Printf("0x%x,%b,%d\n",t2,t2,t2);
fmt.Printf("0x%x,%b,%d\n",t3,t3,t3);
运行的结果是:
2.原理分析
首先,我们分别把123424021
和123456789
转换为二进制形式:
123424021
的二进制形式111010110110100110100010101
123456789
的二进制形式111010110111100110100010101
其实在二进制形式下,上面的两个数字只有一个位是不同的,见上面粗体部分。
当从int32转换为int16时,Golang会截取后面的16位数字,两个数字的截取情况如下:
123424021
截取0100110100010101
123456789
截取1100110100010101
在带符号的二进制数中,最高位为0表示该数字为正数,最高位为1表示该数字为负数,因此:
0100110100010101
是一个正数,1100110100010101
是一个负数。
但是在无符号的二进制数中,我们可以把1100110100010101
看作一个正数来处理,此时1100110100010101
转换为十进制就是52501。
3.二进制正负数的转换运算
二进制的负数采用补码的方式来实现,运算规则是将正数取反后再加1,例子:
假如我们要表示-100
,首先,100
的二进制形式是01100100
,我们对其近期取反操作10011011
,然后再进行加一操作后,得到的结果就是10011100
,这个就是-100
的二进制形式。
结合上面的例子,1100110100010101
是一个负数,将100110100010101
其按照上面的规则进行逆运算,得到的结果是011001011101011
,就是上面截图中的-011001011101011
,转换为十进制就是-13035
。