我在编译器资源管理器中摆弄了一下,发现传递给std::min的参数的顺序改变了发出的程序集。
下面是Godbolt编译器资源管理器的示例
double std_min_xy(double x, double y) {
return std::min(x, y);
}
double std_min_yx(double x, double y) {
return std::min(y, x);
}
对其进行编译(例如,在clang 9.0.0上使用-O3),以便:
std_min_xy(double, double): # @std_min_xy(double, double)
minsd xmm1, xmm0
movapd xmm0, xmm1
ret
std_min_yx(double, double): # @std_min_yx(double, double)
minsd xmm0, xmm1
ret
我的问题是:为什么编译器不切换参数本身的顺序,这样movapd
就不是必需的了?它肯定知道minsd的参数顺序不会改变答案?是不是有什么副作用我不明白?
minsd a,b
对于某些特殊的FP值是不可交换的,std::min
也是不可交换的,除非您使用-ffast-math
。
MINSD a,b
完全实现了(a
包括严格的IEEE-754语义中暗示有符号零和NaN的所有内容。(即,它将源操作数
b
保留在无序的
1或相等)。正如Artyer所指出的,
-0.0
和
+0.0
比较相等(即
-0.<0.
是假的),但它们是不同的。
std::min
是根据(a
比较表达式(cppreference)定义的,使用
(a
std::fmin
不同,
std::fmin
保证从任一操作数进行NaN传播。(
fmin
最初来自C数学库,而不是C++模板。)
看看在x86上给出无分支FP最小值和最大值的指令是什么?有关minss/minsd/maxss/maxsd(以及相应的内部规则,除了某些GCC版本外,它们遵循相同的非交换规则)的更多详细信息
脚注1:记住
nan
对于任何
b
和任何比较谓词都是false。例如,
nan==b
是false,
nan>b
也是false。即使
nan==nan
也是false。当一对中的一个或多个是NaN时,它们是“无序”WRT。彼此。
使用
-ffast-math
(告诉编译器不假设NAN,以及其他假设和近似值),编译器将两个函数都优化为一个minsd
。https://godbolt.org/z/a7ok91
对于GCC,请参见https://GCC.gnu.org/wiki/floatingpointmath
clang支持类似的选项,包括-ffast-math
作为一个总括选项。
这些选项中的一些几乎每个人都应该启用,但奇怪的遗留代码库除外,例如
-fno-math-errno
。(有关推荐的数学优化的更多信息,请参阅本问答)。而且gcc-Fno-traping-math
是一个好主意,因为尽管默认为打开状态,但它仍然不能完全工作(某些优化仍然可以更改取消屏蔽异常时将引发的FP异常的数量,包括有时甚至从1变为0或0变为非零,IIRC)。gcc-ftrapping-math
还会阻止一些即使是WRT也是100%安全的优化。异常语义,所以它很糟糕。在不使用fenv.h
的代码中,您永远不会知道其中的区别。
但是,将
std::min
视为可交换的,只能通过不假设NAN的选项或类似的东西来实现,因此对于那些关心NAN发生了什么的代码来说,绝对不能被称为“安全的”。例如,-ffinite-math-only
不假设nan(也不假设无穷大)
clang-funsafe-math-optimizations-ffinite-math-only
将执行您所要的优化。(unsafe-math-optimizations意味着一系列更具体的选项,包括不关心带符号的零语义)。
本章将介绍Rust编译器的参数。 Rust编译器程序的名字是rustc,使用它的方法很简单: $ rustc [OPTIONS] INPUT 其中,[OPTIONS]表示编译参数,而INPUT则表示输入文件。而编译参数有以下可选: -h, --help - 输出帮助信息到标准输出; --cfg SPEC - 传入自定义的条件编译参数,使用方法如 fn main() { if cfg!(he
我想使用部分模板专门化,以便将数组(在编译时创建)“分解”为由其值组成的参数包(以便与我在代码中定义的其他结构接口)。以下内容(我的第一次尝试)不编译 因为模板参数不得涉及模板参数。正如我所理解的,在部分模板专门化中提供非类型参数是不可能的,如果它们不是非常依赖于模板参数的话。因此,我试图通过在类型中包含值来解决这个问题: 我使用并通过,因为我使用非类型模板参数,所以需要c++2a。 在我的实际代
问题内容: 之后,我用来获取输入参数。 但是,使用pyinstaller编译程序后,exe程序将无法接受我的输入。 它将仅使用我为程序设置的默认值。如何编译它并让exe文件接受我的输入? 我希望我不需要为此编写GUI。抱歉回复晚了。这是代码: 如果我使用“ python this_script.py”运行它,它将等待我输入等待的秒数。但是用pyinstaller编译后,我双击了exe文件。我没有地
根据C编程语言-第4节,第6.2.5节: 有三种浮点类型:浮点(单精度)、双精度(双精度)和长双精度(扩展精度) 参考:http://en.wikipedia.org/wiki/Single-precision_floating-point_format 真有效位包括二进制点右侧的23个分数位和值为1的隐式前导位(二进制点左侧),除非指数存储为全零。因此,内存格式中只有23个有效位的分数位,但总精
在Stroustrup的新书《C编程语言-第四版》第10.5.1节中,他说,在执行算术运算之前,整数提升用于从较短的整数类型中创建整数,类似地,浮点提升用于从浮点中创建双精度。 我用以下代码确认了第一个索赔: 这将输出带有vc的“int”和带有gcc的“i”。 但是,用浮点而不是短路进行测试,输出仍然是“浮点”或“f”: 根据Stroustrup的说法,浮点提升规则没有例外,所以我希望输出“dou
现在,我有下面的代码,它只是测试标准库中的< code>std::set_difference: 当我用Clang/GCC编译它时,我得到了输出: 更新我想实际使用的源代码案例(假设是我将要做的一些操作。因此,这些操作将按的顺序发生): 好吧,这看起来不错,它实际上对应于标准::set_difference,检查链接:但是当我选择MSVC时,我得到了不同的输出(检查链接:https://godbo