快捷搜索:  汽车  科技

零基础数据类型转换(2.2.1C8.0教程)

零基础数据类型转换(2.2.1C8.0教程)图2. 单精度、双精度浮点类型C# 还支持浮点数。有两种类型:float和double,它们是标准IEEE 754格式的32位和64位数字,如图2.中的CLR名称所示,它们对应于通常称为单精度和双精度的数字。浮点值的工作方式与整数不同,因此此表与整数类型表略有不同。浮点数存储一个值和一个指数(在概念上类似于科学表示法,但使用的是二进制而不是十进制)。精度列(第四列)显示值部分有多少位可用,范围(第五列)表示为最小的非零值和最大值。(可以是正的,也可以是负的。)C#支持整数和浮点运算。有带符号的和无符号的整数类型,它们有不同的大小,如图1.所示。最常用的整数类型是int,主要是因为它足够大,可以表示范围广泛的正负整数值,同时也不会因为太大而无法在所有支持 .NET 的 CPU 上有效工作。是效率最高的整数类型之一。图1. 基本数据类型图1.中的第二列显示了CLR中的类型名称。不同的语言有不同

.NET 在它的类库中定义了数千种类型,你也可以自己定义编写,所以 C# 可以处理无限数量的数据类型。但是,编译器对少数类型进行特殊处理,预制了大量的方法,简化我们的使用。例如下面代码:

// 示例 1

string strUserName = "Frank" " " "Gao";

示例1.很方便的进行了字符串连接操作。但它之所以有效,是因为c#编译器知道字符串类型,并为它们提供了特殊的服务( C#规范中有一部分为 操作符 定义了唯一的字符串处理)。C# 不仅为字符串提供了各种特殊服务,还为某些数值数据类型、布尔值、称为元组的类型家族以及称为动态和对象的两种特定类型提供了特殊服务。它们中的大多数不仅对 C# 很特殊,而且对运行时也很特殊——几乎所有的数字类型(除了BigInteger外)都在中间语言(IL)中得到了直接支持,而 bool 、string 和 object 类型在 Runtime 阶段执行效率也非常高。

  1. 整数类型
  2. 浮点类型
  3. 特殊的decimal类型
  4. 默认数字类型
  5. 类型后缀
  6. 分组计数表示
  7. 科学计数法
  8. 十六进制、二进制
整数类型

C#支持整数和浮点运算。有带符号的和无符号的整数类型,它们有不同的大小,如图1.所示。最常用的整数类型是int,主要是因为它足够大,可以表示范围广泛的正负整数值,同时也不会因为太大而无法在所有支持 .NET 的 CPU 上有效工作。是效率最高的整数类型之一。

零基础数据类型转换(2.2.1C8.0教程)(1)

图1. 基本数据类型

图1.中的第二列显示了CLR中的类型名称。不同的语言有不同的命名约定,C# 使用来自其 C语言 词根的名称来命名数值类型(图1.第一列),但是这些不符合 .NET 对其数据类型的命名约定。就运行时而言,第二列中的名称是真正的名称——有各种各样的 API 可以在运行时报告关于类型的信息,它们报告是这些 CLR 的名称(图1.第二列),而不是C#的类型名称(图1.第一列)。两列名称在 C# 源代码中是同义词或称为别名,所以如果你想使用运行时名称,你可以自由使用,但是 C# 类型名称在风格上更类似 C语言。由于编译器处理这些类型的方式不同于其他类型,因此在这里特别强调一下这种情况。

浮点类型

C# 还支持浮点数。有两种类型:float和double,它们是标准IEEE 754格式的32位和64位数字,如图2.中的CLR名称所示,它们对应于通常称为单精度和双精度的数字。浮点值的工作方式与整数不同,因此此表与整数类型表略有不同。浮点数存储一个值和一个指数(在概念上类似于科学表示法,但使用的是二进制而不是十进制)。精度列(第四列)显示值部分有多少位可用,范围(第五列)表示为最小的非零值和最大值。(可以是正的,也可以是负的。)

零基础数据类型转换(2.2.1C8.0教程)(2)

图2. 单精度、双精度浮点类型

特殊的decimal类型

C# 识别第三种数字表示形式,称为 decimal(在CLR中称为 System.Decimal)。这是一个128位的值,因此它可以提供比其他类型更高的精度,但它不仅仅是 double 的更大版本。它是为需要可预测处理小数部分的计算而设计的,这是 float 和 double 都不能提供的。如果您编写的代码将一个 float 类型的变量初始化为0,然后在一行中向它添加了9次0.1(如图3.所示),那么您可能期望得到0.9,但实际上您将得到大约0.9000001。这是因为IEEE 754用二进制存储数字,二进制不能表示所有的小数部分。

零基础数据类型转换(2.2.1C8.0教程)(3)

图3. 意外的结果

十进制整数转换成二进制的方法 “除2倒取余”。所以每一个十进制整数都能对应出准确的二进制数。

十进制小数转换成二进制的方法 “乘2正取整”。所以十进制小数不一定能够对应出准确的二进制数,有可能会一直乘下去。就像没法用十进制精确表示 1/3 一样。

至于为什么要牵扯进去二进制,以及转换方法,如果搞不明白,请跳过过程,记住结论即可。

这意味着 float 和 double 对于部分小数来说只能表示其近似值。但这并不总是很明显的,因为精度损失太小,在将浮点数转换为文本时,它们被四舍五入为十进制近似,这可以掩盖差异。但经过多次计算,误差往往会累积起来,最终产生令人惊讶的结果。

对于某些数学运算,这并不重要。例如在模拟或信号转换处理中,一些噪声和误差是正常可接受的。但会计师和金融监管机构往往不那么宽容——像这样的小差异可能会让它看起来像是金钱神奇地消失了或出现了。我们需要对涉及金钱的计算做到绝对准确,这使得浮点数对于这样的工作来说是一个糟糕的选择。这就是为什么 C# 提供了 decimal 类型,它提供了良好定义的十进制精度级别。

decimal 需要根据实际情况使用。主要原因是大多数整数类型可以由CPU本地处理(在64位进程中运行时,它们都可以得到完美支持)。同样,许多cpu可以直接使用float和double类型。但是,它们都没有对 decimal 的内在支持,这意味着即使是简单的操作,比如加法,也需要多个CPU指令。这意味着使用 decimal 进行的算术运算要比使用到目前为止所显示的其他数字类型慢得多。大家可以参考图4.查看两种类型变量计算相差时间,还是很明显的。

零基础数据类型转换(2.2.1C8.0教程)(4)

图4.橙色箭头代表 float 时间,红色箭头代表 decimal 时间

默认数字类型

在使用数字值时,C# 编译器会自动推断该值的类型。如数字 123 会自动推断为 int 类型,3000000000 推为 uint 5000000000 推为 long 1.23 推为 double 型。这是编译器里写死的,请不要对着干,例如下方语句:

float f=0.1; // 编译错误

编译时会提示:Literal of type double cannot be implicitly converted to type 'float'; use an 'F' suffix to create a literal of this type

类型后缀

如果你要打破此规定,可以通过添加后缀告诉编译器您需要特定的类型。123U是uint 123L是long,123UL是ulong。后缀字母是独立于大小写和顺序的,所以可以用123Lu、123UL或其他任何排列代替123UL,都表示无符号长整型。对于 double float decimal,分别使用D、F和M后缀。

分组计数表示

如果你处理的是非常大的数,很容易把0的数量弄错。这可能非常昂贵或危险,这取决于你的应用程序所使用的领域。C# 提供了一些解决方法,允许您在数字文本的任何地方添加 下划线,以便分解数字。这类似于大多数英语国家使用逗号将每3位编成一组的常见做法。例如,大多数以英语为母语的人不会写5000000000,而是会写500 000 000 000,这样就能立即看出这是50亿,而不是500亿或5亿。(世界上有几个国家用句号表示,他们会写成5.000.000.000)。在C#中,我们可以通过将数字写为5_000_000_000来便于计位,在编译器看来,会忽略 下划线_ ,等同于5000000000。

科学计数法

当然,你还可直接使用科学计数法来使用数字。如下图5.所示 0.618×10¹ = 0.618E1 。

零基础数据类型转换(2.2.1C8.0教程)(5)

图5. 科学计数法

十六进制、二进制

能够用十六进制编写整数值通常很有用,因为这些数字能更好地映射到运行时使用的二进制数值。当一个数字的不同位表示不同的东西时,这一点特别重要。例如,您可能需要处理源自Windows系统调用的数字错误代码——Windows偶尔出现异常很正常。这些代码一般使用第一位的位表示成功或失败,接下来的几个位表示错误的起源,剩下的位标识特定的错误。例如,COM错误代码E_ACCESSDENIED的值为−2 147 024 891。很难看到十进制的结构,但在十六进制中,它更容易:80070005。8表示这是一个错误(十六进制8 = 二进制1000),接下来的007表示这最初是一个普通的Win32错误,已经被翻译成一个COM错误。剩下的位表示Win32错误代码为5 (ERROR_ACCESS_DENIED)。C#允许您在类似的场景中使用十六进制编写整数值,其中十六进制表示更具可读性。您只需在数字前面加上0x,因此在本例中,您将写入0x80070005。

零基础数据类型转换(2.2.1C8.0教程)(6)

图6. 经典的蓝屏,注意错误代码0x开头

零基础数据类型转换(2.2.1C8.0教程)(7)

变量i 被赋值为十六进制数

您还可以使用0b前缀编写二进制文字。数字分隔符可以在十六进制和二进制中使用,就像它们可以在小数中使用一样,尽管在这些情况下更常见的是将数字按4分组,例如0b_0010_1010。显然,这使得数字中的任何二进制结构都比十六进制更明显,但是32位二进制长得不方便,这就是为什么我们经常使用十六进制来代替。

零基础数据类型转换(2.2.1C8.0教程)(8)

变量i 被赋值为二进制数

如果您不了解二进制、十六进制,不知道为何最后的输出结果为6.28,那么你还是先从更基础的知识开始学起吧。

本课小结

这节课作者也收获颇多,有很多都是根据 Microsoft 的官方文档查阅而来。尤其是关于精度的问题。又有了更深的理解。

猜您喜欢: