整数与浮点除法 -> 谁负责提供结果?
Posted
技术标签:
【中文标题】整数与浮点除法 -> 谁负责提供结果?【英文标题】:Integer vs floating division -> Who is responsible for providing the result? 【发布时间】:2010-08-15 16:05:22 【问题描述】:我已经用 C++ 编程了一段时间,但突然有了疑问,想向 *** 社区澄清一下。
当一个整数除以另一个整数时,我们都知道结果是一个整数,同样,一个浮点数除以一个浮点数也是一个浮点数。
但是谁负责提供这个结果呢?是编译器还是DIV指令?
【问题讨论】:
你是在划分常量还是变量? 【参考方案1】:这取决于您的架构是否具有 DIV
指令。如果您的体系结构同时具有整数和浮点除法指令,编译器将针对代码指定的情况发出正确的指令。语言标准规定了类型提升的规则,以及在每种可能的情况下应该使用整数除法还是浮点除法。
如果您只有一个整数除法指令,或者只有一个浮点除法指令,编译器将内联一些代码或生成对数学支持库的调用来处理除法。除法指令是出了名的慢,所以大多数编译器会尽可能地优化它们(例如,用移位指令替换,或预先计算编译时常量除法的结果)。
【讨论】:
【参考方案2】:编译器将在编译时根据所使用的变量类型决定需要哪种形式的除法 - 最终会涉及到一种或另一种形式的 DIV(或 FDIV)指令。
【讨论】:
除非变量是编译时常量,在这种情况下编译器会“承担责任”并且不会产生任何指令。 @Potatoswatter:不完全正确;编译器必须评估积分常量表达式并且可以评估其他常量表达式。 IE。float x = 1.0/3.0
可能由编译器评估,也可能导致 FDIV - 编译器的选择。【参考方案3】:
硬件除法指令几乎从不包括整数和浮点数之间的转换。如果你得到了除法指令(它们有时会被忽略,因为除法电路又大又复杂),它们实际上肯定是“将 int 除以 int,产生 int”和“将 float 除以 float,产生 float” .而且通常输入和输出的大小也是一样的。
编译器负责在这些原语之上构建源代码中编写的任何操作。例如,在 C 语言中,如果将浮点数除以 int,编译器将发出 int-to-float 转换,然后是浮点数。
(确实存在古怪的例外情况。我不知道,但我不会把它放在 VAX 之外,因为它有“将浮点数除以 int”类型的指令。Itanium 并没有真正的除法指令,但它的“除法助手”仅用于浮点,您必须在浮点除法之上伪造整数除法!)
【讨论】:
嘿。至于“古怪的例外”,正如您所说的那样,您可能刚刚使用了一个来写这个答案。 将浮点数除以 int 的 x86(或更准确地说是 x87)指令称为 FIDIV。 这并不是 x86 的古怪让 VAX 蒙羞的唯一一点:)。 哈!嗯,应该是 x87。他们没有用正常的方式做任何事情。【参考方案4】:你的问题真的没有意义。 DIV 指令本身不会做任何事情。不管你对它大声喊叫,即使你试图贿赂它,它也不会对任何事情负责
当您使用编程语言 [X] 进行编程时,[X] 编译器的唯一责任是制作一个执行您在源代码中描述的程序。
如果请求除法,编译器将决定如何进行除法。这可能通过为DIV
指令生成操作码来实现,如果您的目标 CPU 有一个。它可能是通过在编译时预先计算除法,然后将结果直接插入程序中(假设两个操作数在编译时已知),或者它可能通过生成一起模拟的指令序列来完成 一个部门。
但它总是取决于编译器。除非根据 C++ 标准进行解释,否则您的 C++ 程序不会有任何 效果。如果您将其解释为纯文本文件,则它不会执行任何操作。如果您的编译器将其解释为 Java 程序,它将阻塞并拒绝它。
而且 DIV 指令对 C++ 标准一无所知。另一方面,C++ 编译器编写的唯一目的是理解 C++ 标准,并根据它转换代码。
编译器始终负责。
【讨论】:
【参考方案5】:C++ 标准中最重要的规则之一是“好像”规则:
本国际标准中的语义描述定义了一个参数化的非确定性抽象机器。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模仿抽象机器的结构。相反,需要符合要求的实现来模拟(仅)抽象机的可观察行为,如下所述。
这与您的问题有关,这意味着只要完成,划分哪个组件并不重要。它可以由DIV
机器代码执行,如果没有针对相关处理器的适当指令,它可以由更复杂的代码执行。
它还可以:
-
如果合适并且可能更快,请使用位移位操作替换该操作。
如果在编译时可计算,则将操作替换为文字,或者在例如在处理 x / y 时,可以在编译时显示 y 始终为 1。
如果可以在编译时显示它始终是整数除以零,则将操作替换为异常抛出。
【讨论】:
如果它可以在编译时推断出商总是为零,它会拒绝编译吗?或者一个完全符合的 C 程序包含像 x=1/(x-x 这样的指令是否合法? );如果这样的指令从未真正执行过? @supercat:这是完全合法的。 执行除以零会导致未定义的行为。 @supercat 如果你想制作一个总是出错的程序,那是你的事!毕竟,在没有错误的情况下教人们关于错误是很困难的(尽管在某些语言中,您必须执行if(true == false)
之类的操作来欺骗编译器让您编译)。编译器产生非标准化警告肯定是合理且有用的。
... 重要的是,如果一个可靠的语言专家说“它会这样表现”,那么它必须按照专家所说的从外部看。它如何做取决于编译器。那些“未定义”的位是专家会说“我不知道它会做什么”的地方(实际上他可能会抱怨糟糕的代码,你知道专家是什么样的),但定义仅适用于“外部"意见。这对于允许优化很重要,事实上,很多 STL 都依赖于这一点,而不是在性能方面真的很糟糕。
编译器也可以用x * 0.4
替换x/2.5
。这实际上很常见,因为乘法通常比除法更快。【参考方案6】:
实际
C99 标准定义“当整数被除时,/ 运算符的结果 是任何小数部分的代数商 丢弃。”并在脚注中补充说“这通常被称为'向零截断'。”
历史
从历史上看,语言规范负责。
Pascal defines its operators 这样使用/
进行除法总是返回real
(即使您使用它来除2 个整数),如果您想将整数除以得到整数结果,则使用@改为 987654324@ 运算符。 (Visual Basic 也有类似的区别,它使用\
运算符进行整数除法,返回整数结果。)
在 C 中,如果您想要浮点结果,则决定应该通过将整数操作数之一转换为 float
来进行相同的区分。以您在许多 C 派生语言中描述的方式处理整数与浮点类型已成为惯例。我怀疑这个约定可能起源于 Fortran。
【讨论】:
以上是关于整数与浮点除法 -> 谁负责提供结果?的主要内容,如果未能解决你的问题,请参考以下文章