声明
本文内容来自微软 MVP solenovex 的视频教程——真会C#吗?-- C#全面教程,大致和第 6 课—— 基础 - 数值类型(入门+) 对应。
本文主要包括以下内容:
- 数值类型
数值类型
数值类型包括,整型和浮点型。如下图所示:
整数 Literal
整数类型的 Literal 可使用 10/16/2 进制符号,16 进制是在前面加上 0x 前缀,进制是在前面加上 0b 前缀,C# 7.0 开始可以在数值中使用下划线提高可读性。
int x = 127;
long y = 0x7F;
int million = 1_000_000;
var b = 0b1010_1011_1100_1101_1110_1111;
实数 Literal
可使用小数点,指数形式。
double d = 1.5;
double million = 1E06;
数值 Literal 的类型推断
默认情况下,编译器会推断一个数值 Literal 是 Double 还是整数类型,如果包含小数点,或以指数形式展现,那么就是 Double 类型
否则 Literal 的数值是 int,uint,long,ulong 里第一个能容纳该数值的类型。
Console.WriteLine ( 1.0.GetType()); // Double (double)
Console.WriteLine ( 1E06.GetType()); // Double (double)
Console.WriteLine ( 1.GetType()); // Int32 (int)
Console.WriteLine ( 0xF0000000.GetType()); // UInt32 (uint)
Console.WriteLine (0x100000000.GetType()); // Int64 (long)
数值的后缀
数值的后缀会显式定义 Literal 的类型,U、L 很少使用,因为 Uint,Long,Ulong 要么可以被推断出来,要么可以从 Int 隐式转换过来,F、M 是比较有用的,当指定 Float 或 Decimal 的 Literal 的时候,应该加上。
long i = 5; // Implicit lossless conversion from int literal to long
double x = 4.0;
float f = 4.5F;
decimal d = -1.23M; // Will not compile without the M suffix.
类型转换
整数类型
当目标类型可以容纳源类型时,整数转换是隐式的,否则就要显式转换。
int x = 12345; // int is a 32-bit integer
long y = x; // Implicit conversion to 64-bit integral type
short z = (short)x; // Explicit conversion to 16-bit integral type
浮点型
Float 可以隐式的转换为 Double,Double 必须显式的才能转换为 Float。
浮点型和整数类型转换
所有的整数类型都可以隐式的转换为所有的浮点类型,反过来必须进行显式转换。
int i = 1;
float f = i;
int i2 = (int)f;
Note:当前浮点型转为整型时,小数部分将会被截断。
把一个很大的整数隐式转换为浮点类型后,会保证量级不变,但是偶尔会丢失精度。因为浮点类型有更多的量级,而精度可能不足。
int i1 = 100000001;
float f = i1; // Magnitude preserved, precision lost
int i2 = (int)f; // 100000000
Decimal 转换
所有的整数类型可以被隐式的转换为 Decimal 类型,反过来则必须进行显式转换。
算术操作符
以下运算符对数值类型执行算术运算:
一元 ++(增量)、--(减量)、+(加) 和 -(减)运算符。
二元 *(乘)/(除)%(余数)+(加) 和 -(减) 运算符。
这些运算符支持所有整型和浮动数值类型。
++(增量)、--(减量)
增量运算符以两种形式进行支持:后缀增量运算符 x++ 和前缀增量运算符 ++x。
int x = 0, y = 0;
Console.WriteLine (x++); // Outputs 0; x is now 1
Console.WriteLine (++y); // Outputs 1; y is now 1
除法
整型会截断余数,除数变量为 0,会抛出 DivideByZeroException 运行时异常,除数 Literal 为 0 则编译错误。
int a = 2 / 3; // 0
int b = 0;
int c = 5 / b; // throws DivideByZeroException
Overflow 溢出
在运行时,整型的算术操作可能会引起溢出,默认情况下,不会抛出异常,结果类似于“环绕”行为。
默认开启算术的 Overflow 检查,可使用 unchenked 部分关闭检查。
int a = int.MinValue;
a--;
Console.WriteLine (a == int.MaxValue); // True
Overflow Checked 操作符
Checked 会告诉运行时,如果整型的表达式或语句超出了该类型的极限,就会抛出 OverflowException。
Checked 操作符对
++,--,+,-,*,/
起作用。Checked 可以用于表达式或语句。
Checked 对 Float,Double 不起作用,因为它们有无限的值。
常量表达式的 Overflow 检查,编译时算出来的表达式总会时行溢出检查,除非使用 unchenced 操作符。
int a = 1000000;
int b = 1000000;
int c = checked (a * b); // Checks just the expression.
checked // Checks all expressions
{ // in statement block.
c = a * b;
}
int x = int.MaxValue;
int y = unchecked (x + 1);
unchecked { int z = x + 1; }
// int x = int.MaxValue + 1; // Compile-time error
// int y = unchecked (int.MaxValue + 1); // No errors
按位操作符
C# 提供如下图所示按位操作符:
8/16 位整数类型
byte,sbyte,short,ushort,没有自己的操作符,C# 会按需对它们进行隐式转换到大一点的整数类型。
short x = 1, y = 1;
short z = x + y; // Compile-time error
short z = (short) (x + y); // OK
Float,Double 的特殊值
浮点表达式可以包含下列值集:
NaN,正无穷,负无穷,-0,MaxValue,MinValue,Epsilon。
Float/Double 除以 0
Console.WriteLine ( 1.0 / 0.0); // Infinity
Console.WriteLine (−1.0 / 0.0); // -Infinity
Console.WriteLine ( 1.0 / −0.0); // -Infinity
Console.WriteLine (−1.0 / −0.0); // Infinity
NaN
使用 == 操作符时,NaN 不等于任何一个值,包括 NaN 使用 object.Equals() 方法时,两个NaN是相等的,验证某个值是否为 NaN,float.IsNan(),double.IsNan()。
Console.WriteLine ( 0.0 / 0.0); // NaN
Console.WriteLine ((1.0 / 0.0) − (1.0 / 0.0)); // NaN
Console.WriteLine (0.0 / 0.0 == double.NaN); // False
Console.WriteLine (double.IsNaN (0.0 / 0.0)); // True
Console.WriteLine (object.Equals (0.0 / 0.0, double.NaN)); // True
Double vs. Decimal
Double 基于 2 计算,Decimal 基于 10 计算。Double 比 Decimal 的计算速度更快,大约 10 倍左右。Double 适用于科学计算,例如坐标值;Decimal 适用于财务计算,或者人造数据。
实数的舍入错误
Float 和 Double 是基于 2 来表示数值的,只有可用 2 表达的数值才是准确的,大多数带有小数部分的Literal都不会被精确的表达出来。
Decimal 是基于 10,可以精确的表达基于 10 的数据,包括基于 2,5 的数据。
循环数据,Double 和 Decimal 都不可以精确的表达循环数据。
float tenth = 0.1f; // Not quite 0.1
float one = 1f;
Console.WriteLine (one - tenth * 10f); // -1.490116E-08
decimal m = 1M / 6M; // 0.1666666666666666666666666667M
double d = 1.0 / 6.0; // 0.16666666666666666
decimal notQuiteWholeM = m+m+m+m+m+m; // 1.0000000000000000000000000002M
double notQuiteWholeD = d+d+d+d+d+d; // 0.99999999999999989
Console.WriteLine (notQuiteWholeM == 1M); // False
Console.WriteLine (notQuiteWholeD < 1.0); // True
参考
Integral types table (C# Reference)
Floating-point types table (C# Reference)
Value types (C# Reference)
Double Struct
Arithmetic operators (C# Reference)
Bitwise and shift operators (C# Reference)