草庐IT

c++ - 这个 GCC 优化不正确吗?

coder 2023-05-03 原文

我有一个仿函数,它接受一个值,将其转换为 double,获取日志并将值转换回原始类型。对于这个问题,原始和输出类型是 float 。这是原始的 C++ 代码:

return static_cast< TOutput >( std::log( static_cast< double >( A ) ) )

当我在 Debug模式下编译时,一切都按预期进行,GCC 调用底层 log 函数:

  51:/myfile.h ****     return static_cast< TOutput >( std::log( static_cast< double >( A ) ) );
 219133                 .loc 112 51 0
 219134 0010 488B45F0     movq  -16(%rbp), %rax # A, tmp64
 219135 0014 F30F1000     movss (%rax), %xmm0 # *A_1(D), D.237346
 219136 0018 0F14C0       unpcklps  %xmm0, %xmm0  # D.237346, D.237346
 219137 001b 0F5AC0       cvtps2pd  %xmm0, %xmm0  # D.237346, D.237347
 219138 001e E8000000     call  log #
 219138      00
 219139 0023 660F14C0     unpcklpd  %xmm0, %xmm0  # D.237347
 219140 0027 660F5AC0     cvtpd2ps  %xmm0, %xmm0  # D.237347, D.237346
 219141 002b F30F1145     movss %xmm0, -20(%rbp)  # D.237346, %sfp
 219141      EC
 219142 0030 8B45EC       movl  -20(%rbp), %eax # %sfp, <retval>

但是,当我打开优化 (-O2 -ggdb3 -DNDEBUG) 时,它会调用 logf (???) 函数:

  51:/myfile.h ****     return static_cast< TOutput >( std::log( static_cast< double >( A ) ) );
 145171                 .loc 64 51 0
 145172 01a0 F30F1004     movss (%rdx,%rax,4), %xmm0  # MEM[(const float &)_84], MEM[(const float &)_84]
 145172      82         
 145173 01a5 E8000000     call  logf  #

它给出了不同的输出。这是正常的吗?我做错什么了吗?在我看来,GCC 对我的代码采取了一种非常自由的解释,如果没有 -ffast-math 选项,我不会期望这种解释。

最佳答案

将 double log应用到float的转换转换为单精度应用的float是一种边界优化>log,但可以说是可以接受的。

假设 logf 被正确四舍五入,并且 double log 也被正确四舍五入或至少忠实地四舍五入,这两个计算几乎不会有差异。由于double-rounding,它们可能不同(对于一些罕见的输入) (其中“double”表示“两次”,不指类型)。与最终类型的有效数字相比,在中间类型的有效数字中有额外的数字,双舍入在统计上的重要性较低(从数学的角度来看,这个统计论点有点垃圾,但它“在实践中有效”的函数没有被设计成反例)。出于教学原因,人们(或维基百科)用一个或两个额外的精度来解释它,但是当你有 53 - 24 = 29 个额外的二进制数字时,它可能会发生在 229.

我对优化感到惊讶,如果我自己编写代码以详尽搜索 log 的双舍入问题,我会对此感到不安,但考虑到 C++ 标准没有从 std::log 要求任何级别的准确性,可以认为它“不是错误”。


如果我们讨论的不是 log,而是基本操作之一(例如 *),那么对于编译器来说,转换是不正确的声称在引入可见更改时提供 IEEE 754 语义。对于基本操作,精度由 IEEE 754 间接规定,规范没有变化的余地。

碰巧对于基本操作,当 floatOP(flx,fly) 替换 (float)doubleOP((double)flx, (double)fly )(这个 thesis 在第 6 章中演示了这一点),但是当类型是 doublelong double 时可能会有明显的差异。这个确切的错误是recently fixed斯蒂芬·佳能在 Clang 中。

关于c++ - 这个 GCC 优化不正确吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26584903/

有关c++ - 这个 GCC 优化不正确吗?的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  3. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  4. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  5. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  6. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  7. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  8. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  9. ruby - 如何在 RVM 下将 Bundler 安装到 @global gemset,这是正确的方法吗 - 2

    我在OSX上(如果重要的话)。如果我使用RVM安装Ruby,它会默认将Bundler安装到@globalgemset假设我想要一个不同版本的bundler。我假设我需要做的就是执行geminstallbundler--version但是,这会将bundler安装到默认gemset并且RVM不会为其设置路径。因此,如果我键入bundler,它仍会启动一个与Ruby一起安装到@global中的bundler两个问题:如何将bundler安装到@globalgemset。将bundler安装到@globalgemset中的模式是否正确,或者我遗漏了什么 最佳答案

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐