C++ 如何控制C math是否使用SSE2?

C++ 如何控制C math是否使用SSE2?,c++,visual-c++,floating-point,sse,deterministic,C++,Visual C++,Floating Point,Sse,Deterministic,我在fp:strict模式下使用MSVC组装了C库的超越数学函数。它们似乎都遵循相同的模式,下面是sin的情况 首先是一个名为“disp_pentium4.inc”的文件中的调度例程。它检查变量\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuse2\umathfcns是否已设置;如果是,则调用\uuu sinu pentium4,否则调用\uuuu sinu\u default \uuu sin_pentium4(在“sin_pentium4.asm”中)首先将参数从x87 fp

我在fp:strict模式下使用MSVC组装了C库的超越数学函数。它们似乎都遵循相同的模式,下面是
sin
的情况

首先是一个名为“disp_pentium4.inc”的文件中的调度例程。它检查变量
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuse2\umathfcns
是否已设置;如果是,则调用
\uuu sinu pentium4
,否则调用
\uuuu sinu\u default

\uuu sin_pentium4
(在“sin_pentium4.asm”中)首先将参数从x87 fpu传输到xmm0寄存器,使用SSE2指令执行计算,并将结果加载回fpu

\uu sin\u default
(在“sin.asm”中)将变量保留在x87堆栈上,只需调用
fsin

因此,在这两种情况下,操作数都被推送到x87堆栈上,并返回到x87堆栈上,使其对调用者透明,但如果定义了
\uuuuuuuuuuuuu use\u sse2\u mathfcns
,则操作实际上是在sse2而不是x87中执行的

这种行为对我来说非常有趣,因为x87超越函数因其行为稍有不同而臭名昭著,这取决于实现,而给定的SSE2代码应该总是给出可重复的结果


是否有一种方法可以确定在编译或运行时将使用SSE2代码路径?我不擅长编写程序集,因此如果这涉及到编写任何程序集,请提供一个代码示例。

简单的回答是,您无法在代码中确定库将做什么,除非您还涉及库实现的特定细节。这将使代码完全不可移植-即使是同一编译器的两个不同版本也可能会更改库的内部结构

当然,如果可移植性不是问题,那么使用
extern\uuuuuu\uSSE2\uMathfcns并检查它是否为真显然会起作用

我希望,如果处理器有SSE2,并且您使用的是足够现代的库,那么它将尽可能使用SSE2。但肯定地说,这是另一回事


如果这对您的代码至关重要,那么实现您自己的超越函数并使用它们——这是保证相同结果的唯一方法。或者,使用一些合适的内联汇编程序(或超越)代码计算选定的
sin
cos
等值,并将这些值与库提供的
sin()
cos()
函数进行比较

为什么不使用自己的库而不是C运行时?这将为跨计算机的一致性提供更有力的保证(假定C运行时是作为DLL提供的,并且可能会随时间发生轻微变化)


我推荐你。如果您已经将SSE2作为目标,并且只要您不打算更改FPU的舍入模式,您就处于使用它的理想状态,并且不会找到更准确的实现方式。

我通过仔细的数学调查找到了答案。这由名为
\u set\u SSE2\u enable的方法控制。这是一个公共符号,记录如下:

启用或禁用第二代数据流单指令多数据扩展指令集(SSE2)的使用 CRT数学例程中的指令。(此功能在上不可用。) x64体系结构,因为默认情况下已启用SSE2。)

这将导致上述uuuuuu use sse2 mathfcns标志设置为提供的值,从而有效启用或禁用pentium4 sse2例程的使用

文档中提到这只会影响某些超越函数,但从反汇编的角度看,这似乎会影响其中的每一个函数

编辑:单步进入每个函数会显示它们在SSE2中都可用,但以下功能除外:

  • fmod
  • 信义
  • 科什
  • sqrt

Sqrt是最大的冒犯者,但是在SSE2中使用内部函数实现它是微不足道的。对于其他人来说,除了使用第三方库之外,没有简单的解决方案,但我可能没有。

这些文件位于哪个目录?“\f:\dd\vctools\crt\u bld\SELF\u X86\crt\prebuild\tran\i386\”-这正是我在disassembly中看到的,我自己没有这些文件。不,不可能,这是一个体面的问题。。。我有一种尴尬的冲动,想要投票。如果这是基于一个名为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuse2\uMathfcns
的变量,你不能测试同一个变量吗?(您可能需要声明它,我不知道它有多私有)
extern int\uuuuuu use\u sse2\u mathfcns
给我一个链接器错误。我不知道这是在哪里定义的,它只是disassembly中的一个名称。进入sin()会跳转到
cmp dword ptr[\uuuuuuuuuuuuuuu sse2\u mathfcns(518BEEB8h)],0
。。。我在C头文件中也没有看到这方面的任何痕迹。它可能是该单元中的一个私有变量。您能找到它所在的DLL并查看它是否已导出吗?msvcr110.DLL(调试中的msvcr110d.DLL)。用Dependency Walker打开它,我看不到有问题的符号。在这种情况下,我最初关于“你不能真正做到这一点”的陈述适用。我实际上需要设置FPU的精度和舍入模式:53位并舍入到最接近的值。但是,如果CRlibm例程是在SSE2中实现的,则这不应该与它们有任何关联。@Dr_Asik历史浮点堆栈指令的模拟模式并不完美:当设置为53位有效位时,指数保持其完整扩展范围。特别是,避免双舍入非规范化非常困难。尽管如此,CRlibm设计为即使在以x87为目标时也能工作,只要将其设置为您所指的仿真模式:+1(CRlibm)。除了保证完美的精度外,它通常比GNU LibM和Cephes C更快。如果您想用精度换取性能,请看一下FDLibM。@PascalCuoq您是说将x87设置为53位精度不足以保证再现性吗