• C# 5.0 in a Nutshell 读书笔记(一) 野峰


    数值型(Numeric)数据的类型转换,对任何程序语言来说,都是基本功能,C# 也不例外。

    C# 的类型转换有两种基本形式:隐式(implicit)和显式(explicit),如下例:

    int x = 345;
    long y = x;
    short z = (short)x;

    其中,y = x,即将整型 x 转换为 长整型 y,称为 隐式类型转换,即由编译器自动完成类型转换。因为编译器知道,整型数转换为长整型数,不会有任何精度损失。z = (short)x,即将整型 x 转换为 短整型 z,称为 显式类型转换,即需要程序员明确指出转换的目的类型。因为编译器知道,整型转换为短整型,可能会产生精度损失,所以不能隐式转换。

    再看下例:

    double d = 12.5;
    int n = (int)d;

    因为 双精度浮点数转换为整型数时,也可能产生精度损失,所以这里也需要显式转换。而且,转换后的结果,n = 12,即直接去掉了浮点数的小数部分。这种转换方式,很多时候是无法满足要求的,因为我们需要 四舍五入 地转换。而 C# 语言的显式类型转换机制无法实现这一点。为此,.NET Framework 提供了 Convert 类,用于实现类型转换。

    int m = Convert.ToInt32(d);

    转换的结果,m = 12!为什么?Convert.ToInt32(double value) 方法的文档是这么说的:

    value, rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.

    双精度浮点数 value 舍入到最近的 32 位有符号整数。若 value 正好处于两个整数中间,则返回偶数,即,4.5 转换的结果是 4,而 5.5 转换的结果是 6。

    看一下 Convert.ToInt32(double value) 方法的实现代码,就更清楚了:

        if (value >= 0.0)
        {
            if (value < 2147483647.5)
            {
                int num = (int) value;
                double num2 = value - num;
                if ((num2 > 0.5) || ((num2 == 0.5) && ((num & 1) != 0)))
                {
                    num++;
                }
                return num;
            }
        }
        else if (value >= -2147483648.5)
        {
            int num3 = (int) value;
            double num4 = value - num3;
            if ((num4 < -0.5) || ((num4 == -0.5) && ((num3 & 1) != 0)))
            {
                num3--;
            }
            return num3;
        }

    上面代码中的 num2 == 0.5 或 num4 == -0.5,即表示 value is halfway between two whole numbers,所以在 (num & 1) != 0,即 num 为奇数的时候,才执行 num++ 操作。

    这种硬生生的向偶数的舍入,似乎与我们固有的 四舍五入 的常识不符!看来,Convert.ToInt32() 也不是一个完美的解决方案。

    浮点数的舍入是一个大问题,因为存在舍入误差,在计算过程中就会产生累计误差,而且最后的累积误差有可能会很大!

    IEEE 754 标准定义了 5 种舍入规则,常用的前面两个称为 舍入到最近值(rounds to nearest):

    1. Round to nearest, ties to even(舍入到最近值,但绑定到偶数)
    2. Round to nearest, ties away from zero(舍入到最近值,但远离零)

    这样看来,Convrt.ToInt32() 实现了 IEEE 754 的第一种舍入规则,也是二进制浮点数的默认规则,并且对于十进制浮点数(decimal),也是推荐的默认规则。

    为使用户能够有第二种选择,.NET Framework 的 Math 类提供了 Round 方法:

    public static double Round(double value, MidpointRounding mode);

    其中,中点舍入模式(MidpointRounding)是一个枚举类型,可以是 ToEven,也可以选择 AwayFromZero。示例如下:

    Math.Round(3.5, MidpointRound.ToEven) => 4.0
    Math.Round(3.5, MidpointRound.AwayFromZero) => 4.0
    Math.Round(2.5, MidpointRounding.ToEven) => 2.0;
    Math.Round(2.5, MidpointRounding.AwayFromZero) => 3.0
    Math.Round(2.35, 1, MidpointRounding.ToEven) => 2.4
    Math.Round(2.35, 1, MidpointRouding.AwayFromZero) => 2.4

    总起来看,对于数值数据的类型转换,C# 在语言层面上提供了 隐式/显式 两种转换方式,如果语言层面上的转换方式不能满足要求,还可以使用 Convert 类型转换类进行类型转换,假如对 Convert 的舍入方式不满意,可以通过 Math.Round 方法,选择自己需要的舍入方式。

    .NET/C# 通过层层递进,把一个复杂、困难的问题,近乎完美地解决了。

     
  • 相关阅读:
    学习bn算法
    记录pytorch的几个问题
    Python: 你不知道的 super
    cmd里面怎么复制粘贴
    tensorflow的transpose
    应该做一个软件,直接把视频里面的英语,转换成字幕,然后翻译
    继续修改,爬虫贴吧,上次的每次只取一个图片.
    Deleting elements
    Map, filter and reduce
    List methods
  • 原文地址:https://www.cnblogs.com/prowyh/p/2796998.html
Copyright © 2020-2023  润新知