C#对于非数字double.NaN的神奇现象,无穷大的处理以及整数除以0

某次执行小数除以0时,发现居然不抛出异常。执行如下代码片段:

            try
            {
                Console.WriteLine(Math.Sqrt(-4));
                int num = 0;
                Console.WriteLine(10.5F / num);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"浮点运算出现异常:{ex.Message}");
            }
            Console.ReadLine();

原本以为会抛出异常,尝试运行下,出现戏剧的一幕,

一般来说,字符串为中文时,转换为double类型的转换结果都为false

【double.TryParse("中文",out result)】

但运行如下代码:

Console.WriteLine(double.TryParse("非数字",out double result));

 运行结果:

查看微软对小数点的逻辑时,小数除以0用不抛出异常。

 但某个小数与double.NaN 比较,结果一定为false

即使非数字与double.NaN比较,仍然为false

某个数字除以0的处理

类别 除以0的结果 中文描述 比较与运算处理
负数 double.NegativeInfinity 负无穷大 可以进行比较,运算结果为负无穷或者非数字
0 double.NaN 非数字 比较永远为false,运算结果永远为NaN(非数字)
正数 double.PositiveInfinity 正无穷大 可以进行比较,运算结果为正无穷或者非数字

微软定义:

当未定义算术运算时,Double.NaN 表示非数字结果。 测试一个值与 Double.NaN 之间的相等关系的任何表达式始终返回 false。 测试一个值与 Double.NaN 之间的不等关系的任何表达式始终返回 true。

如何解决冲突。若要修复与此规则的冲突并准确确定某个值是否表示 Double.NaN,请使用 Single.IsNan 或 Double.IsNan 来测试值。

但整数不能尝试除以0,否则将抛出异常 DivideByZeroException。

尝试将整数或 System.Decimal 值除以零时引发的异常。

浮点数值类型(C# 引用)

浮点数值类型表示实数。 所有浮点型数值类型均为值类型。 它们还是简单类型,可以使用文本进行初始化。 所有浮点数值类型都支持算术比较相等运算符。

浮点类型的特征

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
decimal ±1.0 x 10-28 至 ±7.9228 x 1028 28-29 位 16 个字节 System.Decimal

在上表中,最左侧列中的每个 C# 类型关键字都是相应 .NET 类型的别名。 它们是可互换的。 

每个浮点类型的默认值都为零,0。 每个浮点类型都有 MinValue 和 MaxValue 常量,提供该类型的最小值和最大有限值。 float and double 类型还提供可表示非数字和无穷大值的常量。 例如,double 类型提供以下常量:Double.NaNDouble.NegativeInfinity 和 Double.PositiveInfinity

当所需的精度由小数点右侧的位数决定时,decimal 类型是合适的。 此类数字通常用于财务应用程序、货币金额(例如 $1.00)、利率(例如 2.625%)等。 精确到只有一个小数的偶数用 decimal 类型处理会更准确:例如,0.1 可以由 decimal 实例精确表示,而没有精确表示 0.1 的 double 或 float 实例。 由于数值类型存在这种差异,因此当你对十进制数据使用 double 或 float 时,算术计算可能会出现意外的舍入错误。 当优化性能比确保准确度更重要时,可以使用 double 代替 decimal。 然而,除了大多数计算密集型应用程序之外,所有应用程序都不会注意到性能上的任何差异。 避免使用 decimal 的另一个可能原因是为了最大限度地降低存储需求。 例如,ML.NET 使用 float,因为对于非常大的数据集,4 个字节与 16 个字节之间的差异合乎情理。 有关详细信息,请参阅 System.Decimal

真实文本

真实文本的类型由其后缀确定,如下所示:

  • 不带后缀的文本或带有 d 或 D 后缀的文本的类型为 double
  • 带有 f 或 F 后缀的文本的类型为 float
  • 带有 m 或 M 后缀的文本的类型为 decimal

测试程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MagicFloatDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.SetWindowSize(120, 50);
            Console.WriteLine("任何浮点数与double.NaN比较(大于、小于、等于)永远返回false。对【非数字】的任何运算(加减乘除等)都将返回NaN");
            Console.WriteLine("【非数字NaN】必须是0除以0,非零除以0将返回无穷大");
            Console.WriteLine("非零数除以0的结果:" + double.IsNaN(-8.00 / 0));
            Console.WriteLine($"测试NaN的比较和运算结果:{double.NaN == double.NaN}");
            Console.WriteLine($"测试NaN的比较和运算结果:{double.PositiveInfinity > double.NaN}");
            Console.WriteLine("判断一个浮点数是否是【非数字】只能用 double.IsNaN(d)方法");
            Console.WriteLine($"对非数字运算测试:{double.NaN + 5},结果是否是【非数字】:{double.IsNaN(double.NaN + 5)}");
            Console.WriteLine("但正无穷【PositiveInfinity】和负无穷【NegativeInfinity】可以与其他浮点数比较");
            Console.WriteLine($"两个负无穷比较:{double.NegativeInfinity == double.NegativeInfinity}");
            Console.WriteLine($"正负无穷比较:{double.PositiveInfinity > double.NegativeInfinity}");
            Console.WriteLine($"无穷与普通浮点数比较:{ double.PositiveInfinity > 55}");
            Console.WriteLine($"无穷与普通浮点数比较:{double.NegativeInfinity > -888}");
            Console.WriteLine($"判断一个结果是否为无穷大:{double.IsNegativeInfinity(-8.56 / 0)}");
            Console.WriteLine($"正无穷与负无穷相加结果为NaN:{double.PositiveInfinity + double.NegativeInfinity}");
            Console.WriteLine($"两个无穷相加:{double.PositiveInfinity + double.PositiveInfinity}");
            Console.WriteLine($"正无穷减去正无穷:{double.PositiveInfinity - double.PositiveInfinity}");
            Console.WriteLine($"正无穷普通运算:{double.PositiveInfinity - 3000.5}");
            Console.WriteLine($"负无穷减去负无穷:{double.NegativeInfinity - double.NegativeInfinity}");
            Console.WriteLine($"正无穷普通运算:{double.NegativeInfinity + 5E12D}");
            Console.WriteLine("----测试字符串转化为浮点数----");
            JudgeParse("非数字");
            JudgeParse("负无穷大");
            JudgeParse("正无穷大");
            JudgeParse("无穷大");
            JudgeParse("非数字123");
            JudgeParse("");
            JudgeParse("12345.6789");
            JudgeParse("1.5E3");
            JudgeParse("NaN");
            JudgeParse("NegativeInfinity");
            JudgeParse("Infinity");
            JudgeParse("-123.45678E+3");
            JudgeParse("\x39\u003645.E-2");
            JudgeParse("-55");
            JudgeParse(".643");
            JudgeParse(".");
            JudgeParse("895.");
            double d = Math.Sqrt(-1);
            //非数字比较 永久为false 【d == double.NaN】
            Console.WriteLine($"获取负数的平方根将不产生异常,按非数字处理:{d}.当前值与非数字比较结果:【{d == double.NaN}】,是否不为数字【{double.IsNaN(d)}】");
            Console.WriteLine($"反正弦结果:【{Math.Asin(2)}】");

            Console.WriteLine();
            Console.WriteLine("整数int和十进制数decimal不能尝试除以0,否则将抛出异常。而浮点数可以除以0,返回NaN");
            int x = 0;
            try
            {
                Console.WriteLine(8888.66M / x);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"【{ex.GetType()}】{ex.Message}");
            }
            try
            {
                Console.WriteLine(8848 / x);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"【{ex.GetType()}】{ex.Message}");
            }
            Console.WriteLine("----打印特殊值【非数字、无穷大】对应的字节数组----");
            Console.WriteLine("Float非数字对应的字节数组:" + string.Join(",", BitConverter.GetBytes(float.NaN)));
            Console.WriteLine("Float负无穷对应的字节数组:" + string.Join(",", BitConverter.GetBytes(float.NegativeInfinity)));
            Console.WriteLine("Float正无穷对应的字节数组:" + string.Join(",", BitConverter.GetBytes(float.PositiveInfinity)));
            Console.WriteLine("Double非数字对应的字节数组:" + string.Join(",", BitConverter.GetBytes(double.NaN)));
            Console.WriteLine("Double负无穷对应的字节数组:" + string.Join(",", BitConverter.GetBytes(double.NegativeInfinity)));
            Console.WriteLine("Double正无穷对应的字节数组:" + string.Join(",", BitConverter.GetBytes(double.PositiveInfinity)));
            Console.ReadLine();
        }

        /// <summary>
        /// 判断转换某一个字符串为双精度浮点数是否成功,以及返回结果
        /// </summary>
        /// <param name="str"></param>
        static void JudgeParse(string str)
        {
            double result;
            bool parseResult = double.TryParse(str, out result);
            Console.WriteLine($"操作是否成功【{parseResult}】,转换结果【{result}】,源字符串【{str}】");
        }
    }
}

运行结果:

猜你喜欢

转载自blog.csdn.net/ylq1045/article/details/120361741