基本类型间的类型转换(数值型)

今天一打开博客,看到左上角的园龄5年,目光有些恍然,昔日作为学生上课的情景、已经慢慢变的模糊。是啊、毕业已经3年有余,时光不再来...

 

一、原码和补码

在步入正文说类型转换之前,先做一个小铺垫,了解一下原码和补码。

[注:由于同一个数字在用不同位数的原码或补码表示时、结果不同,所以如无特殊说明、该小节下出现的所有原码和补码均为8位]

 

原码(true form)是一种计算机中对数字的二进制定点表示方法。原码表示法在数值前面增加了一位符号位(即最高位为符号位):

正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。

1、原码优点:简单直观;例如,我们用8位二进制表示一个数,+11的原码为00001011,-11的原码就是10001011

2、原码缺点:原码不能直接参加运算,可能会出错。例如数学上,1+(-1)=0,而在二进制中 00000001+10000001=

10000010,换算成十进制为-2。显然出错了。

 

补码(two's complement) 在计算机系统中,数值一律用补码来表示和存储。补码是可以直接参与运算的。原码和补码表示方法均有

符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位表示方法不相。

1、知原码求补码

求正数的补码:正整数的补码与原码相同。

【例】+9的补码是00001001。

求负数的补码:求负整数的补码, 在原码的基础之上 符号位不变,数值位各位取反,最后整个数加1。

【例】求-5的补码。
-5的原码(10000101)→符号位不变(10000101)→数值位取反(11111010)→加1(11111011)
所以-5的补码是11111011。
【例】数0的补码表示是唯一的。
[+0]补=[+0]原=00000000
[-0]补=11111111+1=00000000


2、知补码求原码

已知一个数的补码,求原码的操作其实就是对该补码再求补码:
1)如果补码的符号位为“0”,表示是一个正数,其原码就是补码。
2)如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
【例】已知一个补码为11111001,则原码是10000111(-7)。
因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。
其余七位1111001取反后为0000110;
再加1,所以是10000111。

3、补码的运算

 补码:http://baike.baidu.com/view/377340.htm

 

二、整形间的类型转换

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("注:该demo中的所有例子均为整形间的无精度损失的类型转换,为了方便阅读打印的是字节而不是位");
            Console.WriteLine("1、补位式转化");

            Console.WriteLine("\r\n###32位有符号 转 64位无符号###");
            Console.WriteLine("\r\n例1");
            int i = int.MaxValue;
            ulong ul = (ulong)i;
            Print(BitConverter.GetBytes(i), i.ToString(), "转化前");
            Print(BitConverter.GetBytes(ul), ul.ToString(), "转化后");
            Console.WriteLine("\r\n例2");
            i = int.MinValue;
            ul = (ulong)i;
            Print(BitConverter.GetBytes(i), i.ToString(), "转化前");
            Print(BitConverter.GetBytes(ul), ul.ToString(), "转化后");

            Console.WriteLine("\r\n###32位有符号 转 64位有符号###");
            Console.WriteLine("\r\n例3");
            i = int.MinValue;
            long l = (long)i;
            Print(BitConverter.GetBytes(i), i.ToString(), "转化前");
            Print(BitConverter.GetBytes(l), l.ToString(), "转化后");


            Console.WriteLine("\r\n###32位无符号 转 64位有符号###");
            Console.WriteLine("\r\n例4");
            uint ui = uint.MaxValue;
            l = (long)ui;
            Print(BitConverter.GetBytes(ui), ui.ToString(), "转化前");
            Print(BitConverter.GetBytes(l), l.ToString(), "转化后");

            Console.WriteLine("2、截位式转化");

            Console.WriteLine("\r\n###64位有符号 转 32位有符号###");
            Console.WriteLine("\r\n例5");
            l = long.MaxValue;
            i = (int)l;
            Print(BitConverter.GetBytes(l), l.ToString(), "转化前");
            Print(BitConverter.GetBytes(i), i.ToString(), "转化后");

            Console.WriteLine("\r\n###64位无符号 转 32位有符号###");
            Console.WriteLine("\r\n例6");
            ul = ulong.MaxValue;
            i = (int)ul;
            Print(BitConverter.GetBytes(ul), ul.ToString(), "转化前");
            Print(BitConverter.GetBytes(i), i.ToString(), "转化后");


            Console.WriteLine("3、转换符号位式转化");

            Console.WriteLine("\r\n###32位无符号 转 32位有符号###");
            Console.WriteLine("\r\n例7");
            ui = uint.MaxValue;
            i = (int)ui;
            Print(BitConverter.GetBytes(ui), ui.ToString(), "转化前");
            Print(BitConverter.GetBytes(i), i.ToString(), "转化后");

            Console.WriteLine("\r\n###32位有符号 转 32位无符号###");
            Console.WriteLine("\r\n例8");
            i = int.MinValue;
            ui = (uint)i;
            Print(BitConverter.GetBytes(i), i.ToString(), "转化前");
            Print(BitConverter.GetBytes(ui), ui.ToString(), "转化后");


            Console.Read();
        }

        private static void Print(byte[] buffer, string result, string tag = "")
        {
            Console.WriteLine(tag);
            Console.WriteLine("数值:" + result);
            Console.Write("字节数组(补码):");
            foreach (byte b in buffer)
            {
                Console.Write(string.Format("{0},", b.ToString()));
            }
            Console.WriteLine("");
        }

    }

  

      

 根据上述的8个例子可以得出如下结果:

 1、补位式转化、即少位数据类型向多位数据类型转化 (例1、例2、例3、例4)

  所补位与操作数的数据类型有关,与目标数据类型无关。

  如果操作数是有符号的数据类型,所补位一律为操作数的符号位,如果操作数是无符号的数据类型,所补位一律为0。

 2、截位式转化、即多位数据类型向少位数据类型转化 (例5、例6)

  该转换方式就是简单的截取有效数位(即丢弃高位),和操作数的类型无关。

 3、转换符号位式转化、即相同位数有无符号数据类型间的转化(例7、例8)

   发生该类型转化时,只是最高位的意义发生了变化,进而可能导致结果改变。

 

三、整形与浮点型间的类型转换

有了上面的基础、再理解整形与浮点型的转换就容易多了。

由整形向浮点型转换的时候,如果整形数据的值过大或过小,就可能损失一些最低的有效位,造成精度损失(float的精度只有7位,double15~16位)。

 

四、参考资料:

原码:http://baike.baidu.com/view/60480.htm

补码:http://baike.baidu.com/view/377340.htm

 

最后祝园友们,中秋快乐(虽然晚了,但是诚意还在吧)。

 

posted @ 2014-09-09 19:01  把爱延续  阅读(962)  评论(0编辑  收藏  举报