【问题标题】:Why is the division result between two integers truncated?为什么两个整数之间的除法结果会被截断?
【发布时间】:2012-04-08 03:20:01
【问题描述】:

所有有经验的 C# 程序员(我认为这来自 C)都习惯于对除法中的整数进行强制转换以获得十进制/双精度/浮点结果而不是 int(实际结果被截断)。

我想知道为什么要这样实现?如果两个数字都是整数,是否有充分的理由截断结果?

【问题讨论】:

  • 整数数学就是这样工作的。
  • 我会说向后兼容和逻辑(int/int=int 而不是int/int=double)。任何使用过任何其他编程语言的人都会预料到这种行为。有没有其他语言以其他方式做到这一点?
  • @jgauffin Pascal 和 Basic 对 double 和 int 除法有不同的运算符,其中结果的类型取决于运算符,而不是参数。
  • @jgauffin yes - Pascal(或至少 Delphi)将整数除法的结果实现为浮点数。当我切换到 C 语言时,结果是一个四舍五入的整数,这让我很恼火。毕竟,在学校,如果你说 3 除以 2 = 1,你的数学老师就不会被打动!
  • @jgauffin,Python 3 给出了int / int = double。 Python 2 以另一种方式工作,但现在如果您需要整数结果,他们添加了第二个运算符 //

标签: c# algorithm int double


【解决方案1】:

C# 可以追溯到 C,所以回答“为什么在 C# 中是这样的?”是“为什么在 C 中是这样的?”的组合。和“没有充分的理由改变吗?”

C 的方法是在高级语言和低级操作之间建立相当密切的对应关系。处理器通常将整数除法实现为返回商和余数,两者与操作数的类型相同。

(所以我的问题是,“为什么类 C 语言中的整数除法不返回 两个整数”,而不是“为什么它不返回浮点值?”)

解决方案是为除法和余数提供单独的操作,每个操作都返回一个整数。在 C 的上下文中,每个操作的结果都是整数并不奇怪。这通常比浮点运算更准确。考虑您对7 / 3 的评论中的示例。该值不能用有限的二进制数表示也不能用有限的十进制数表示。换句话说,在今天的计算机上,我们无法准确表示 7 / 3除非我们使用整数!这个分数的最准确表示是“商 2,余数 1”。

那么,没有充分的理由改变吗?我想不出任何理由,而且我可以想出几个改变的好理由。其他答案都没有提到 Visual Basic(至少到版本 6)有两个整数除法运算符:/ 将整数转换为双精度,并返回双精度,而 \ 执行普通整数运算。

在努力使用浮点除法实现二进制搜索算法后,我了解了\ 运算符。这真的很痛苦,整数除法就像呼吸新鲜空气一样进来。没有它,在程序的初稿中会有很多特殊处理来覆盖边缘情况和一个错误。

从那次经验中,我得出结论,用不同的运算符来划分整数是令人困惑的。

另一种选择是只有一个整数运算,它总是返回一个双精度,并要求程序员截断它。这意味着每次需要整数除法时都必须执行两次 int->double 转换、截断和 double->int 转换。有多少程序员会错误地舍入或取整而不是截断结果?这是一个更复杂的系统,至少同样容易出现程序员错误,而且速度较慢。

最后,除了二分查找之外,还有许多采用整数运算的标准算法。一个例子是将对象集合划分为大小相似的子集合。另一个是在一维数组中的索引和二维矩阵中的坐标之间进行转换。

据我所知,“int / int 产生 int”的替代方案无法在语言可用性方面的成本效益分析中幸存下来,因此没有理由改变从 C 继承的行为。

总结:

  • 整数除法在许多标准算法中经常有用。
  • 当需要对整数进行浮点除法时,可以使用简单、简短且清晰的强制转换显式调用它:(double)a / b 而不是a / b
  • 其他替代方案会增加程序员的复杂性和处理器的更多时钟周期。

【讨论】:

  • 天啊!很好的回答!感谢您所提供的所有信息!我还有一个问题:如果 CPU 将除法返回为两个整数,那么每次进行除法时,我都会“浪费” CPU 时间?
  • 顺便说一句:“为什么类 C 语言中的整数除法不返回两个整数”。有趣的是,x86 处理器在执行整数除法指令时确实计算商和余数。不幸的是,类 C 语言语法不允许在一个语句中本地返回这两个部分。
  • @adelphus 这就是我在写“处理器通常将整数除法实现为返回商和余数,两者都与操作数的类型相同”时想要传达的意思。
  • @Diego 是的!然而,浪费的时间非常少。在对性能有可衡量影响的应用程序中,如果您无法找到能够利用机器指令的商余数结果的编译器,您可以用机器代码编写一些东西。
  • 那将是math.h 中的div 函数。
【解决方案2】:

如果两个数字都是整数,是否有充分的理由截断结果?

当然;我可以很容易地想到十几个这样的场景。例如:您有一个大图像,以及一个在两个维度上都小 10 倍的图像的缩略图版本。当用户单击大图像中的一个点时,您希望识别缩小图像中的相应像素。显然,您需要将 x 和 y 坐标都除以 10。为什么要获得 十进制 的结果?相应的坐标将是缩略图位图中的整数坐标。

双数非常适合物理计算,小数非常适合金融计算,但我使用计算机进行的几乎所有数学工作都完全以整数形式进行。我不想仅仅因为我做了一些除法就不断地将双精度数或小数转换回整数。如果您要解决物理或财务问题,那么您为什么首先使用整数?什么都不使用,只使用双精度数或小数。使用整数解决有限数学问题。

【讨论】:

  • 我不认为如果除法不会截断的每个场景都是一个很好的理由.. 还有很多场景是您不想要的。而且我认为拥有两个整数并希望将它们相除而不是截断是错误的(或奇怪的),那么为什么(如果我知道它们是整数)我应该使用双精度或小数?
  • @Diego - 我认为关键是,在很多情况下您不想要分数结果。当然,在某些情况下您确实需要分数结果。因此,无论除法返回整数还是浮点值,都不会满足所有用例。
  • 是的,当然,但我的观点是:为什么要根据数量而不是通过方法来决定哪个更正确?我仍然认为 7 / 3 是 2.33... 而不是 2。
  • @Diego - 问题是你用人类数学术语思考,而计算机用语言规定的术语“思考”。您特别询问了 C#,语言设计者决定对来自 C/C++ 和 Java 的人使用整数除法,并且设计者试图适应这些语言的思维方式。至于为什么在以前的语言中做出决定的原因,您得到的许多答案基本上告诉您相同的答案。 [续]
  • @Diego - 首先,正如 Attila 和其他人所指出的那样,有影响决定的历史和性能原因。但是,我认为您忽略了在现实世界中,有很多时候分数答案没有意义。埃里克举了一个例子,但还有很多其他的例子。如果我有一个有 23 个孩子的教室,我想将他们分成 10 个小组进行某项活动,那么在什么意义上说每个小组应该有 2.3 个孩子“更正确”?
【解决方案3】:

计算整数比计算浮点值更快(通常)。此外,所有其他整数/整数运算(+-*)都返回一个整数。

编辑: 根据OP的要求,这里有一些补充:

OP 的问题是他们认为/ 是数学意义上的除法,而语言中的/ 运算符执行一些其他操作(这不是数学。除法)。按照这种逻辑,他们也应该质疑所有其他操作(+-*)的有效性,因为它们具有特殊的溢出规则,这与数学对应物所期望的不同。如果这对某人来说很麻烦,他们应该找到另一种语言,以便按照人们的预期执行操作。

关于支持整数值的性能差异声明:当我写答案时,我只有“民间”知识和“直觉”来支持这一声明(因此我的“通常”免责声明)。事实上,正如 Gabe 所指出的,有些平台并不适用。另一方面,我发现了这个link(第 12 点),它显示了英特尔平台上的混合性能(不过使用的语言是 Java)。

总结应该是,在经过衡量和发现为真之前,许多主张和直觉都是未经证实的。

【讨论】:

  • @Diego:我认为这是一个很好的理由。 通常对特定类型的所有操作都应该返回相同类型的结果。否则会非常混乱。 [编辑:Diego 删除了他的评论 - 我们建议将返回 int 的 int 划分不是一个好的理由]
  • +1。如果它返回除int 之外的任何内容,它就不再是整数数学!这就是它适用于所有类型的方式:uint 除法的结果是uintfloat 除法的结果是float,等等。在没有任何转换的情况下,应该如何计算完成,如floatdoubledecimal?编译器将不得不选择。如果您想要其中一个结果,请选择。
  • 整数之间的除法不一定比浮点数之间的除法快。
  • @Gabe - AFAIK 除非你有特殊的硬件,否则你可以放心地假设整数运算比相应的浮点运算快。
  • @MrLister 问题在于/ 经常被称为除法,而实际上并非如此。 3 除以 2 等于 1.5:每个人都知道这一点,但开发人员如此习惯于整数数学,以至于它没有记录 / 运算符与其他运算符的数学正确性不匹配。
【解决方案4】:

是的,如果最终结果需要是一个整数。这将取决于要求。

如果这些确实是您的要求,那么您不希望存储小数然后截断它。你会浪费内存和处理时间来完成一些已经内置的功能。

【讨论】:

  • 我想我不明白.. 为什么要更改除法的结果。如果您需要截断,请保存十进制结果,然后截断(或舍入或其他)。
  • 但是,为什么要浪费内存和处理。我会更新我的答案
【解决方案5】:

运算符旨在返回与其输入相同的类型。

编辑(评论回复): 为什么?我不设计语言,但我会假设大多数时候你会坚持使用你开始使用的数据类型,在剩下的例子中,你会使用什么标准来自动假设用户想要哪种类型?你会在需要时自动期待一个字符串吗? (诚​​心诚意)

【讨论】:

    【解决方案6】:

    如果你将一个 int 添加到一个 int,你期望得到一个 int。如果你从一个 int 中减去一个 int,你期望得到一个 int。如果您将一个 int 与一个 int 相乘,您期望得到一个 int。那么,如果将 int 除以 int,为什么不期望得到 int 结果呢?如果你期望一个 int,那么你将不得不截断。

    如果您不希望这样,那么您需要先将您的整数转换为其他内容。

    编辑:我还要注意,如果您真的想了解这是为什么,那么您应该开始研究二进制数学的工作原理以及它是如何在电子电路中实现的。当然没有必要详细了解它,但是快速了解它确实可以帮助您了解硬件的低级细节如何过滤到高级语言的细节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-01
      • 1970-01-01
      • 2014-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多