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


131

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

在C#中:

float x = 13 / 4;   
//== operator is overridden here to use epsilon compare
if (x == 3.0)
   print 'Hello world';

该代码的结果将是:

'Hello world'

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


46
因为那是integer师而不是floating point
亨特·麦克米伦

它确实必须(在VB.Net中)以自然的数学方式以不同的方式实现,其中除法运算的所有结果都是一个无理数。
BanditoBunny 2012年

3
我认为您的意思是有理数。参见维基百科:将两个整数相除可能会导致余数。为了完成余数的除法,将数字系统扩展为包括分数或有理数,因为它们通常被称为。
crashmstr 2012年

6
这就是为什么我不喜欢使用语言“复制语法”的原因。我来自VB,认为“ C#是.NET”而不是“ C#就像C”。我猜是我的错误,但是在这种情况下,我更喜欢VB方式。如果他们在使用未初始化的简单类型时遇到了产生编译器错误的麻烦(您甚至在C语言中都没有得到警告),那么在将整数除法分配给浮点数时为什么不警告您?
darda 2013年

Answers:


96

虽然新程序员在实际上打算使用浮点除法时经常犯执行整数除法的错误,但实际上,整数除法是一种非常常见的操作。如果您假设人们很少使用它,并且每次进行除法操作时,您总是需要记住将其转换为浮点数,那您就错了。

首先,整数除法要快得多,因此,如果您只需要整数结果,则可以使用更高效的算法。

其次,有许多使用整数除法的算法,如果除法的结果始终是浮点数,则每次都将被迫舍入结果。我脑海中的一个例子是改变数字的底数。计算每个数字涉及数字与整数的除法运算,而不是数字的浮点除法。

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


5
在VB.Net中,.Net架构师做出了另一个决定:/-始终是浮点除法\ \-整数除法,因此除非您考虑C ++的传统,否则它是不一致的。
BanditoBunny 2012年

4
您可以在编译时确定/运算符将执行整数还是浮点除法(除非您使用的是动态运算)。如果由于在一行上执行了太多操作而使难以弄清楚,那么我建议您将该行分成几行,以便更容易确定操作数是整数还是浮点类型。您的代码的未来读者可能会喜欢它。
Servy 2012年

5
我个人认为我总是不得不思考我要划分的变量是有问题的,我认为这是浪费我的注意力。
BanditoBunny 2012年

8
@pelesl因为这样做将是一个巨大的突破性变化,为此它将破坏天文数字的程序,我可以完全自信地说,它永远不会在C#中发生。那是从第一天开始就需要用某种语言完成的事情,或者根本不需要。
Servy 2013年

2
@Servy:在C,C ++和C#中有很多类似的东西。就个人而言,我认为如果存在用于整数除法的其他运算符,C#将是一种更好的语言,并且为避免合法代码产生惊人的行为,该int/int运算符完全是非法的([诊断指定代码必须强制转换操作数或使用其他操作员,具体取决于所需的行为]。如果还有一些其他好的令牌序列可用于整数除法,则有可能不赞成/为此目的使用它,但是我不知道这是实用的。
supercat

77

请参阅C#规范。三种除法运算符

  • 整数除法
  • 浮点除法
  • 十进制除法

在您的情况下,我们使用整数除法,并应用以下规则:

除法将结果舍入为零,并且结果的绝对值是最大可能的整数,该整数小于两个操作数的商的绝对值。当两个操作数具有相同的符号时,结果为零或正;而当两个操作数具有相反的符号时,结果为零或负。

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


哪些语言返回浮动结果?@SergeyBerezovskiy
Ilaria

40

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

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

或者,如果您使用文字:

float x = 13f / 4f;

请记住,浮点数并不精确。如果您在乎精度,请改用小数类型。


1
+1表示仅需浮点数即可进行浮点除法。
Xynariz

显然,您关于精度的陈述是正确的,它适用于学习,并且不使理解变得复杂。由于我们需要在工作中尽可能地保持精确,因此我仍然想对精度进行澄清:根据IEE 754-1985,您可以获得准确的结果(即使事实并非如此)。如果之前已经精确地给出了计算值,并且结果是-简而言之-为2的幂,那么您可以获得精确的结果,即使在这些特殊情况下依靠该精度不是最佳实践。
L. Monty '18

精度上的增加:结果接近1或-1时,获得精确结果的可能性大大提高。由于可以无限精确地表示无限数量和有限数量的结果,因此该可支配性仍然保持为0可能会有点令人困惑。:)
L. Monty '18

1
@ L.Monty感谢您提出来。自编写此答案以来,我已经学到了更多有关浮点的知识,并且您所提出的观点是公平的。从技术上讲,我仍然会说我的“浮点数不精确”的说法是可以接受的,因为从某种意义上说某些东西有时可能是准确的,但这并不意味着它总体上是精确的。就像他们说的那样,时钟一天破两次是正确的,但是我永远不会称它为精密仪器。实际上,我感到惊讶,而这是困扰你比我的建议是,小数类型的部分准确的。
史蒂文·多格特

由于浮点数的所有相同原因,小数是不精确的;只是浮点数以2为底,小数点以10为底。例如,十进制类型不能精确地保留1/3的精确值。
史蒂文·多格

11

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

手册

如果文字没有后缀,它具有第一这些类型的,其中它的值可以表示的:intuintlongulong

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

手册

对于x / y形式的操作,将应用二进制运算符重载解析来选择特定的运算符实现。操作数将转换为所选运算符的参数类型,结果的类型为运算符的返回类型。

预定义的除法运算符在下面列出。运算符都计算x和y的商。

整数除法:

int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);

因此四舍五入发生:

除法将结果舍入为零,并且结果的绝对值是最大可能的整数,该整数小于两个操作数的商的绝对值。当两个操作数具有相同的符号时,结果为零或正;而当两个操作数具有相反的符号时,结果为零或负。

如果您执行以下操作:

int x = 13f / 4f;

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

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

float x = 13 / 4;

请注意,您仍将除以整数,该整数将隐式转换为float:结果将为3.0。使用f后缀(13f4f)将操作数显式声明为float 。


+1用来解释您可以将答案作为浮点数,但仍然进行整数除法。另外,我见过的另一种强制浮点除法的常用方法是将除法的第一项乘以1.0
Xynariz

8

它只是一个基本操作

记住当你学会分裂时。一开始我们解决了9/6 = 1 with remainder 3

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

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


6

可能有用:

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

请尝试为您的答案添加一些解释
NetStarter 2016年

最后一个表达式将产生2.5,而不是2
Lasse V. Karlsen

是的,拼写错误。谢谢。
eozten

4

结果将始终是具有更大范围的分子和分母的类型。byte和short例外,它们产生int(Int32)。

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.