• C# 中的基本数值类型


    在之前的文章中(地址:https://www.vinanysoft.com/c-sharp-basics/introducing/),以 HelloWorld 程序为基础,介绍 C# 语言、它的结构、基本语法以及如何编写最简单的程序有了初步理解。

    接下来介绍基本的 C# 类型,继续巩固 C# 的基础知识。本系列文章到目前为止只用过少量的内置数据类型,而且只是一笔带过。在 C# 中有大量的类型,而且可以通过合并类型来创建新类型。

    但 C# 有几种类型非常简单,是其他所有类型的基础,它们称为预定义类型(predefined type)或基元类型( primitive type)。

    C# 提供了 16 种预定义类型,如下图所示。其中包括 13 种简单类型和 3 种非简单类型。

    所有预定义类型的名称都由全小写的字母组成。预定义的简单类型包括以下 3 种。

    • 11 种数值类型。
      • 不同长度的有符号和无符号整数类型。
      • 用于科学计算的二进制浮点类型 floatdouble
      • 一种用于金融计算的十进制高精度浮点类型 decimal。与 floatdouble 不同,decimal 类型可以准确地表示分数。decimal 类型常用于货币的计算。
    • 一种 Unicode 字符类型 char
    • 一种布尔类型 boolbool 类型表示布尔值并且必须为 truefalse

    非简单类型如下:

    • object,它是所有其他类型的基类。
    • string,它是一个 Unicode 字符数组。
    • dynamic,使用动态语言编写的程序集时使用。

    所有预定义类型都直接映射到底层的 .NET 类型。C# 的类型名称就是 .NET 类型的别名,所以使用 .NET 的类型名称也能很好地符合 C# 语法,不过并不鼓励这样做。在 C# 程序中,应该尽量使用 C# 类型名称而不是 .NET类型名称。

    整数类型

    C# 有八种整数类型,可选择最恰当的一种来存储数据以避免浪费资源。下表列出了 C# 支持的整型类型:

    C# 类型/关键字 范围 大小 .NET 类型
    sbyte -128 到 127 8 位带符号整数 System.SByte
    byte 0 到 255 无符号的 8 位整数 System.Byte
    short -32,768 到 32,767 有符号 16 位整数 System.Int16
    ushort 0 到 65,535 无符号 16 位整数 System.UInt16
    int -2,147,483,648 到 2,147,483,647 带符号的 32 位整数 System.Int32
    uint 0 到 4,294,967,295 无符号的 32 位整数 System.UInt32
    long -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 64 位带符号整数 System.Int64
    ulong 0 到 18,446,744,073,709,551,615 无符号 64 位整数 System.UInt64

    C# 所有基元类型都有短名称(最左列)和完整名称(最右列)。完整名称对应 BCL(基类库)中的类型名称。

    由于基元数据类型是其他类型的基础,所以 C# 为基元数据类型的完整名称提供了短名称(或称为缩写)。其实从编译器的角度看,两种名称完全一样,最终都生成相同的代码。事实上,检查最终生成的 CIL 代码,根本看不出源代码具体使用的名称。

    例如,以下声明声明了相同类型的变量:

    int a = 123;
    System.Int32 b = 123;
    

    C# 支持完整 BCL 名称和关键字,造成开发人员犯难在什么时候用什么。不要时而用这个,时而用那个,最好坚持用一种。

    C# 开发人员一般用 C# 关键字。例如,用 int 而不是 System.Int32,用 string 而不是 System.String(甚至不要用 String 这种简化形式)。

    浮点类型(floatdouble

    C# 支持以下预定义浮点类型:

    C# 类型/关键字 大致范围 精度 大小 .NET 类型
    float ±1.5 x 10−45 至 ±3.4 x 1038 大约 6-9 位数字 4 个字节 System.Single
    double ±5.0 × 10−324 到 ±1.7 × 10308 大约 15-17 位数字 8 个字节 System.Double

    在上表中,最左侧列中的每个 C# 类型关键字都是相应 .NET 类型的别名。 它们是可互换的。 例如,以下声明声明了相同类型的变量:

    double a = 12.3;
    System.Double b = 12.3;
    

    decimal 类型

    C# 类型/关键字 大致范围 精度 大小 .NET 类型
    decimal ±1.0 x 10-28 至 ±7.9228 x 1028 28-29 位 16 个字节 System.Decimal

    floatdouble 相比,decimal 类型具有更高的精度和更小的范围,因此它适合于财务和货币计算。

    浮点数舍入误差

    floatdouble 在内部都是基于 2 来表示数值的。因此只有基于 2 表示的数值才能够精确表示。事实上,这意味着大多数有小数部分的字面量(它们都基于 10)将无法精确表示。例如:

    float f1 = 1F;
    float f2 = 0.9F;
    
    Console.WriteLine(f1 - f2);
    
    double d1 = 1D;
    double d2 = 0.9D;
    
    Console.WriteLine(d1 - d2);
    
    decimal decimal1 = 1M;
    decimal decimal2 = 0.9M;
    
    Console.WriteLine(decimal1 - decimal2);
    

    输出

    0.100000024
    0.09999999999999998
    0.1
    

    这就是为什么 floatdouble 不适合金融计算。相反,decimal 基于 10,它能够精确表示基于 10 的数值(也包括它的因数,基于 2 和基于 5 的数值)。因为实数的字面量都是基于 10 的,所以 decimal 能够精确表示像 0.1 这样的数。然而,floatdoubledecimal 都不能精确表示那些基于 10 的循环小数:

    decimal m = 1M / 6M;
    Console.WriteLine(m);
    
    decimal m2 = m + m + m + m + m + m;
    Console.WriteLine(m2);
    Console.WriteLine();
    
    
    double d = 1d / 6d;
    Console.WriteLine(d);
    
    double d2 = d + d + d + d + d + d;
    Console.WriteLine(d2);
    

    输出

    0.1666666666666666666666666667
    1.0000000000000000000000000002
    
    0.16666666666666666
    0.9999999999999999
    

    字面量

    字面量(literal value)表示源代码中的固定值。

    Console.WriteLine(123);
    Console.WriteLine(456.789);
    

    默认情况下,输入带小数点的字面量,编译器自动把它解释成 double 类型。 如果输入的是整数值(没有小数点)通常默认为 int, 如果值太大,以至于无法用 int 来存储。编译器会把它解释成 long

    static void Main(string[] args)
    {
        var expectIsInt = 123;
        var expectIsLong = 9223372036854775807;
        var expectIsDouble = 3.14;
    
        Console.WriteLine($"expectIsInt 的类型是:{expectIsInt.GetType().Name};" +
                            $"expectIsLong 的类型是:{expectIsLong.GetType().Name};" +
                            $"expectIsDouble 的类型是:{expectIsDouble.GetType().Name}");
    }
    

    输出

    expectIsInt 的类型是:Int32;expectIsLong 的类型是:Int64;expectIsDouble 的类型是:Double
    

    由于带小数点的值默认为 double 类型,所以下面输出的结果中,超过可容纳的精度部分会被丢弃。

    static void Main(string[] args)
    {
        Console.WriteLine(5.141231231234567898765);
    }
    

    输出

    5.141231231234568
    

    要显示具有完整精度的数字,必须将字面量显式声明为 decimal 类型,通过追加一个 M(或者 m)来实现。

    static void Main(string[] args)
    {
        Console.WriteLine(5.141231231234567898765M);
    }
    

    输出

    5.141231231234567898765
    

    还可以使用 FD 作为后缀,将字面量分别显式声明为 float 或者 double。 对于整数数据类型,整数字面量的类型是像下面这样确定的:

    • 如果整数字面量没有后缀,则其类型为以下类型中可表示其值的第一个类型:intuintlongulong

    • 如果整数字面量以 Uu 为后缀,则其类型为以下类型中可表示其值的第一个类型:uintulong

    • 如果整数字面量以 Ll 为后缀,则其类型为以下类型中可表示其值的第一个类型:longulong

      备注:可以使用小写字母 l 作为后缀。 但是,这会生成一个编译器警告,因为字母 l 可能与数字 1 混淆。 为清楚起见,请使用 L

    • 如果整数字面量的后缀为 ULUluLulLULulUlu,则其类型为 ulong

    字面量的后缀不区分大小写。但一般推荐大写,避免出现小写字母 l 和数字 1 不好区分的情况。

    从 C# 7.0 开始提供支持将 _ 用作数字分隔符,可以将数字分隔符用于所有类型的数字文本。

    double d = 3D;
    d = 4d;
    d = 3.934_001;
    
    float f = 3_000.5F;
    f = 5.4f;
    
    decimal myMoney = 3_000.5m;
    myMoney = 400.75M;
    

    C# 支持使用科学记数法,指数记数法要求使用 eE 中缀,在中缀字母后面添加正整数或者负整数,并在字面量最后添加恰当的数据类型后缀。

    double d = 0.42e2;
    Console.WriteLine(d);  // output 42;
    
    float f = 134.45E-2f;
    Console.WriteLine(f);  // output: 1.3445
    
    decimal m = 1.5E6m;
    Console.WriteLine(m);  // output: 1500000
    

    使用 0x0X 前缀表示十六进制计数法,在 C# 7.0 和更高版本中使用 0b0B 前缀表示二进制计数法。

    var hexLiteral = 0x2A;
    var binaryLiteral = 0b_0010_1010;
    

    总结

    C# 语言的基元类型包括八种整数类型、两种用于科学计算的二进制浮点类型、一种用于金融计算的十进制浮点类型。浮点型存在舍入误差,使用的时候要注意。

  • 相关阅读:
    mysql sleep
    mysql 与grafana数据展示时的时间处理
    DevSecOps调研
    django 启动mysql加载错误信息
    kubebuilder operator
    mysql 修改密码
    mysql 实例管理工具
    一文详解JackSon配置信息
    表达式计算(双栈实现)
    【转!】metersphere win源码部署
  • 原文地址:https://www.cnblogs.com/vin-c/p/12043961.html
Copyright © 2020-2023  润新知