为什么编译器决定2.3是double而不是decimal?
为什么编译器决定2.3是double,所以这段代码不能编译:
decimal x; x = 2.3; // Compilation error - can not convert double to decimal. x = (decimal) 2.3 // Ok
为什么编译器不这样想:
他想得到一个小数,他给我一个可以是小数的值,所以它是小数!
为什么这不会出现编译错误:
short x; x = 23; // OK
谁说23不是int?
这里有很多问题。 让我们把它们分解成小问题。
为什么文字2.3的类型是double而不是decimal?
历史原因。 C#被设计为“类C语法”系列语言的成员,因此其表面外观和基本习语对于使用类C语言的程序员来说是熟悉的。 在几乎所有这些语言中,浮点文字被视为二进制而不是十进制浮点数,因为这就是C最初的做法。
如果我从零开始设计一种新语言,我可能会使模糊的文字变得非法; 每个浮点字面值都必须是非单值,单值或小数,依此类推。
为什么在double和decimal之间隐式转换一般是非法的?
因为这样做可能是一个错误,有两种方式。
首先,双精度和小数具有不同的范围和不同数量的“表示错误” – 也就是说,您希望表示的精确数学量实际表示的数量有多么不同。 将双精度转换为十进制或反之亦然是一件危险的事情,你应该确保你正确地做到了; 让你拼出演员要求注意你可能会失去精确度或幅度。
其次,双打和小数的用法非常不同。 双打通常用于科学计算,其中1.000000000001和0.99999999999之间的差异远小于实验误差。 产生小的表示错误是无关紧要的。 小数通常用于精确的财务计算,需要对便士完全准确。 偶然混合两者似乎很危险。
有时你必须这样做; 例如,更容易找出“指数”问题,如抵押摊还或复合利息双倍应计。 在这些情况下,我们再次说明你要从双精度转换为十进制,以便明确表示这是程序中的一个点,如果你没有正确的话可能会发生精度或幅度损失。
为什么将双字面值转换为十进制字面值是非法的? 为什么不假装它是十进制字面值?
C#不是“为你隐瞒你的错误”的一种语言。 它是“告诉你你的错误,所以你可以解决它们”这种语言。 如果你想说“2.3m”并忘记了“m”那么编译器应该告诉你它。
那么为什么将整数文字(或任何整数常量)转换为short,byte等是合法的呢?
因为可以检查整数常量以查看它是否在编译时处于正确的范围内。 从范围内整数到较小整数类型的转换始终是精确的; 与双/十进制转换不同,它永远不会丢失精度或幅度。 此外,整数常量算术总是在“已检查”的上下文中完成,除非您使用未经检查的块覆盖它,因此甚至没有溢出的危险。
并且整数/短运算不太可能跨越像“双重/十进制算术”这样的“域”边界。 双重算术很可能是科学的,十进制算术可能是经济的。 但整数和短算术并不明确地与不同的业务领域相关联。
并使其合法意味着您不必编写丑陋的不必要的代码,将常量强制转换为正确的类型。
因此,没有充分的理由使其成为非法的,并且有充分理由使其合法化。
这里有一些事情:
- 在第一个示例中,您尝试隐式地将
double
字符转换为float
。 那不行。 - 所谓的工作线实际上是在尝试执行
double
到decimal
的显式转换(这是允许的,但通常不是一个好主意),然后是decimal
到float
的隐式转换(这是不允许的)。 如果x
意味着声明为decimal
,那么唯一需要的转换是从double
到decimal
– 这通常不是一个好主意。 -
整数文字的工作转换是由于“隐式常量表达式转换”,如C#4规范的6.1.9节所述:
如果constant-expression的值在目标类型的范围内,则
int
类型的常量表达式可以转换为sbyte
,byte
,short
,ushort
,uint
或ulong
类型。long
有类似的东西,但不是double
。
基本上,当您编写浮点常量时,最好使用后缀显式指定类型:
double d = 2.3d; float f = 2.3f; decimal m = 2.3m;
2.3 是 double
。 这是语言规则; 任何带小数点的数字文字都是double
,除非它有F
后缀( float
)或M
后缀( decimal
):
x = 2.3F; // fine
编译器也有用地告诉我这个:
double类型的文字不能隐式转换为’float’类型; 使用’F’后缀来创建此类型的文字
因为Floatingpint数字在计算和Valuerange中总是有点困难,所以它们在Immediate符号中始终是最大可能的类型。 (在你的情况下:双倍)。
非浮点在下面有一些相同的处理,因此可以毫无问题地进行转换。 如果您的值超出变量的Value-Range,则可能会导致错误(例如,字节为257)。