为什么C#中的整数除法返回整数而不是浮点数?

Why does integer division in C# return an integer and not a float?

有人知道为什么C中的整数除法返回整数而不是浮点数吗?它背后的想法是什么?(这仅仅是C/C++的遗产吗?)

C中:

1
2
3
4
float x = 13 / 4;  
//imagine I used have an overridden == operator here to use epsilon compare
if (x == 3.0)
   print 'Hello world';

此代码的结果将是:

1
'Hello world'

严格地说,没有整数除法(按定义除法是一种产生有理数的运算,整数是其中很小的一个子集。)


虽然新程序员在实际使用浮点除法时犯了这样的错误,但实际上整数除法是一种非常常见的操作。如果你假设人们很少使用它,而且每次你做除法的时候,你总是需要记住将其转换为浮点,那么你就错了。

首先,整数除法要快得多,所以如果你只需要一个整数结果,你就需要使用更有效的算法。

其次,有许多算法使用整数除法,如果除法的结果总是一个浮点数,则每次都会强制对结果取整。我头上的一个例子是改变一个数字的基数。计算每个数字涉及到一个数字与余数的整数除,而不是数字的浮点除。

由于这些(以及其他相关的)原因,整数除法产生整数。如果你想得到两个整数的浮点除法,你只需要记住将一个数转换成一个double/float/decimal


见C规范。有三种类型的除法运算符

  • 整数除法
  • 浮点除法
  • 小数除法

在您的例子中,我们使用整数除法,并应用以下规则:

The division rounds the result towards zero, and the absolute value of
the result is the largest possible integer that is less than the
absolute value of the quotient of the two operands. The result is zero
or positive when the two operands have the same sign and zero or
negative when the two operands have opposite signs.

我认为C使用这种整数除法(某些语言返回浮点结果)的原因是硬件-整数除法更快更简单。


每个数据类型都能够重载每个运算符。如果分子和分母都是整数,则整数类型将执行除法运算,并返回整数类型。如果要进行浮点除法,则必须先将一个或多个数字强制转换为浮点类型,然后再对其进行除法。例如:

1
2
3
int x = 13;
int y = 4;
float x = (float)y / (float)z;

或者,如果您使用的是文字:

1
float x = 13f / 4f;

记住,浮点数并不精确。如果您关心精度,请使用类似于decimal类型的类型。


由于您不使用任何后缀,因此文字134被解释为整数:

Manual:

If the literal has no suffix, it has the first of these types in which its value can be represented: int, uint, long, ulong.

因此,由于您将13声明为整数,因此将执行整数除法:

Manual:

For an operation of the form x / y, binary operator overload resolution is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

The predefined division operators are listed below. The operators all compute the quotient of x and y.

Integer division:

1
2
3
4
int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);

所以四舍五入发生在:

The division rounds the result towards zero, and the absolute value of the result is the largest possible integer that is less than the absolute value of the quotient of the two operands. The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs.

如果您执行以下操作:

1
int x = 13f / 4f;

您将收到一个编译器错误,因为浮点除法(13f/运算符)会产生一个浮点,而该浮点不能隐式转换为int。

如果希望除法是浮点除法,则必须将结果设为浮点:

1
float x = 13 / 4;

请注意,您仍然要分割整数,这将隐式地强制转换为float:结果将是3.0。使用f后缀(13f4f将操作数显式声明为float。


这只是一个基本的操作。记住当你学会了分裂。一开始我们解决了9/6 = 1 with remainder 3

1
2
9 / 6 == 1  //true
9 % 6 == 3 // true

/-运算符与%-运算符组合用于检索这些值。


可能有用:

1
2
3
4
5
6
7
8
9
10
11
double a = 5.0/2.0;  
Console.WriteLine (a);      // 2.5

double b = 5/2;  
Console.WriteLine (b);      // 2

int c = 5/2;  
Console.WriteLine (c);      // 2

double d = 5f/2f;  
Console.WriteLine (d);      // 2.5


结果将始终是分子和分母范围较大的类型。异常为byte和short,它们产生int(int32)。

1
2
3
4
5
6
7
8
9
10
11
var a = (byte)5 / (byte)2;  // 2 (Int32)
var b = (short)5 / (byte)2; // 2 (Int32)
var c = 5 / 2;              // 2 (Int32)
var d = 5 / 2U;             // 2 (UInt32)
var e = 5L / 2U;            // 2 (Int64)
var f = 5L / 2UL;           // 2 (UInt64)
var g = 5F / 2UL;           // 2.5 (Single/float)
var h = 5F / 2D;            // 2.5 (Double)
var i = 5.0 / 2F;           // 2.5 (Double)
var j = 5M / 2;             // 2.5 (Decimal)
var k = 5M / 2F;            // Not allowed

浮点类型和小数类型之间没有隐式转换,因此不允许在它们之间进行除法。您必须显式地强制转换并决定需要哪种类型(与浮点类型相比,十进制具有更高的精度和更小的范围)。