为什么编译器决定2.3是double而不是decimal?

时间:2011-12-07 16:36:30

标签: c# .net compiler-construction types

为什么编译器决定2.3是双精度的,所以这段代码不能编译:

decimal x;
x = 2.3; // Compilation error - can not convert double to decimal.
x = (decimal) 2.3 // O.k.

为什么编译器不这样想:
他想得到一个小数,他给我一个可以是十进制的值,所以它是十进制的!

为什么这不会出现编译错误:

short x;
x = 23; // O.K.

谁说23不是int?

4 个答案:

答案 0 :(得分:21)

这里有很多问题。让我们把它们分解成小问题。

  

为什么文字2.3的类型是double而不是decimal?

历史原因。 C#被设计为“类C语法”系列语言的成员,因此其表面外观和基本习语对于使用类C语言的程序员来说是熟悉的。在几乎所有这些语言中,浮点文字被视为二进制而不是十进制浮点数,因为这就是C最初的做法。

如果我从零开始设计一种新语言,我可能会使含糊不清的文字变得非法;每个浮点文字都必须是非单一的,单个或十进制的,依此类推。

  

为什么在double和decimal之间隐式转换是非法的?

因为这样做可能是一个错误,有两种方式。

首先,双精度和小数具有不同的范围和不同数量的“表示错误” - 也就是说,您希望表示的精确数学量实际表示的数量有多么不同。将双精度转换为十进制或反之亦然是一件危险的事情,你应该确定你正确地做到了;让你拼出演员会引起注意你可能会失去精确度或幅度的事实。

其次,双打和小数的用法非常不同。双打通常用于科学计算,其中1.000000000001和0.99999999999之间的差异远小于实验误差。产生小的表示错误是无关紧要的。小数通常用于精确的财务计算,需要对便士完全准确。偶然混合两者似乎很危险。

有时你必须这样做;例如,更容易找出“指数”问题,如抵押摊还或复合利息双倍应计。在这些情况下,我们再次说明你要从双精度转换为十进制,以便清楚地表明这是程序中的一个点,如果你没有正确的话可能会发生精度或幅度损失。

  

为什么将双字面值转换为十进制字面值是非法的?为什么不假装它是十进制字面值?

C#不是“为你隐瞒错误”的一种语言。它是“告诉你你的错误,所以你可以解决它们”这种语言。如果你想说“2.3m”并忘记了“m”,那么编译器应该告诉你它。

  

那么为什么将整数文字(或任何整数常量)转换为short,byte等是合法的呢?

因为可以检查整数常量以查看它是否在编译时处于正确的范围内。从范围内整数到较小整数类型的转换始终是精确的;与双/十进制转换不同,它永远不会丢失精度或幅度。此外,整数常量算术总是在“已检查”的上下文中完成,除非您使用未经检查的块覆盖它,因此甚至没有溢出的危险。

整数/短算术不太可能像双/十进制算术那样跨越“域”边界。双算术很可能是科学的,十进制算术可能是经济的。但整数和短算术并不明确地与不同的业务领域相关联。

使其合法意味着您不必编写丑陋的不必要的代码来将常量强制转换为正确的类型。

因此没有充分的理由将其定为非法,并且有充分的理由使其合法化。

答案 1 :(得分:11)

这里有一些事情发生:

  • 在您的第一个示例中,您试图隐式地将double字面值转换为float。那不行。
  • 所谓的工作线实际上是在尝试执行doubledecimal的显式转换(这是允许的,但通常不是一个好主意),然后是{{1}的隐式转换} decimal(不允许)。如果要将float声明为x,那么唯一需要的转换是从decimaldouble - 这通常不是一个好主意。
  • 整数文字的工作转换是由于“隐式常量表达式转换”,如C#4规范第6.1.9节所述:

      

    decimal类型的常量表达式可以转换为intsbytebyteshortushortuint,前提是常量表达式的值在目标类型的范围内。

    ulong有类似内容,但long不是

基本上,当你编写浮点常量时,最好用后缀明确指定类型:

double

答案 2 :(得分:2)

2.3 double。这是语言规则;其中包含小数点的任何数字文字都是double,除非它具有F后缀(float)或M后缀(decimal):

x = 2.3F; // fine

编译器也有用地告诉我这个:

  

double类型的文字不能隐式转换为'float'类型;使用'F'后缀来创建此类型的文字

答案 3 :(得分:1)

因为Floatingpint数字在计算和Valuerange中总是有点困难,所以它们在Immediate符号中始终是最大可能的类型。 (在你的情况下:双倍)。

非浮点在下面有一些相同的处理方式,因此可以毫无问题地进行转换。如果您的值超出变量的Value-Range,则可能会导致错误(例如,字节为257)。