C 中的“double”运算和优化

2024-02-12

我最近分析了一段用 VS2005 编译的旧代码,因为“调试”(无优化)和“发布”(/O2 /Oi /Ot 选项)编译中的数值行为不同。 (简化的)代码如下所示:

void f(double x1, double y1, double x2, double y2)
{
double a1, a2, d;

a1 = atan2(y1,x1);
a2 = atan2(y2,x2);
d = a1 - a2;
if (d == 0.0) { // NOTE: I know that == on reals is "evil"!
   printf("EQUAL!\n");
}

功能f如果使用相同的值对调用(例如f(1,2,1,2)),但这并不总是发生在“发布”中。事实上,编译器已经优化了代码,就好像它是这样的d = a1-atan2(y2,x2)并完全删除了对中间变量的赋值a2。此外,它还利用了第二个事实:atan2()的结果已经在 FPU 堆栈上,因此重新加载a1在 FPU 上并减去这些值。问题是 FPU 以扩展精度(80 位)工作,而a1是“唯一”双精度(64位),所以保存第一个atan2()内存中的结果实际上已经失去了精度。最终,d包含扩展精度和双精度之间的“转换错误”。

我完全知道这个身份(==应避免使用 float/double 运算符)。我的问题不是关于如何检查双打之间的接近度。我的问题是如何考虑对局部变量的“契约”赋值。从我的“天真的”观点来看,赋值应该强制编译器将值转换为变量类型(在我的例子中为双精度)表示的精度。如果变量是“浮动”怎么办?如果它们是“int”(奇怪但合法)怎么办?

那么,简而言之,C 标准对这些情况有何规定?


从我的“天真的”观点来看,赋值应该强制编译器将值转换为变量类型(在我的例子中为双精度)表示的精度。

是的,C99标准就是这么说的。见下文。

那么,简而言之,C 标准对这些情况有何规定?

在某些情况下,C99 标准允许以比类型隐含的精度更高的精度来计算浮点运算:FLT_EVAL_METHOD and FP_CONTRACT in the standard http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf,这是与超额精度相关的两个构造。但我不知道有任何词语可以解释为允许编译器任意将浮点值的精度从计算精度降低到类型精度。根据对标准的严格解释,这应该仅以确定性方式发生在特定位置,例如作业和演员表。

最好的就是读书约瑟夫·S·迈尔斯的分析 https://gcc.gnu.org/ml/gcc-patches/2008-11/msg00105.html相关部分的FLT_EVAL_METHOD:

C99 允许以超范围和精度跟踪进行评估 一定的规则。 5.2.4.2.2 第 8 段概述了这些内容:

除了赋值和转换(这会删除所有额外的范围和 精度),具有浮点操作数的运算值和 值受通常的算术转换和浮动 常量被评估为其范围和精度可能的格式 大于类型所需的值。评价的运用 格式的特点是实现定义的值 FLT_EVAL_METHOD:

Joseph S. Myers 继续描述了在他的帖子附带的补丁之前 GCC 的情况。这种情况和你的编译器(以及无数其他编译器)中的情况一样糟糕:

使用 x87 浮点时,GCC 将 FLT_EVAL_METHOD 定义为 2。它是 然而,实现不符合 C99 的要求 FLT_EVAL_METHOD == 2,因为它是由后端实现的 假装处理器支持 SFmode 上的操作并且 DF模式:

  • 有时,根据优化,值可能会溢出到 SFmode 或 DFmode 下的内存,因此会不可预测地丢失多余的精度 以及 C99 指定丢失以外的地方。
  • 赋值通常不会丢失过多的精度,尽管-ffloat-store可能会使其更有可能发生。

C++标准继承了以下定义math.h来自 C99,以及math.h是定义的标题FLT_EVAL_METHOD。出于这个原因,您可能期望 C++ 编译器也会效仿,但他们似乎并没有认真对待这个问题。即使G++仍然不支持-fexcess-precision=standard,尽管它使用与 GCC 相同的后端(自 Joseph S. Myers 的帖子和随附补丁以来,GCC 一直支持此选项)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 中的“double”运算和优化 的相关文章

随机推荐

  • 在 React 和 Redux 中处理本地状态

    是否可以将本地状态存储在state与 redux 一起使用 React 时的对象 通过操作将所有内容存储在状态树中很快就会变得乏味 感觉某些状态仅与应用程序的呈现 显示相关 而不与逻辑相关 我所说的演示是指动画 闪烁 面板的展开 收缩状态
  • NetBeans 12.0:“类没有 main 方法”(但有)

    NetBeans 12 0 Jdk 15 我无法启动我的程序 单击绿色运行按钮不会执行任何操作 并且在 MainFrame 上右键单击 运行文件会出现错误 类没有主方法 但正如您在下面的 GIF 中看到的 它确实有一个 main Strin
  • Android 中如何将一个值从一个 Activity 传递到另一个 Activity? [复制]

    这个问题在这里已经有答案了 我创建了一个带有 AutuCompleteTextView ACTV 和按钮的活动 我在 ACTV 中输入一些文本 然后按下按钮 按下按钮后 我希望该活动转到另一个活动 在第二个活动中 我只想将在第一个活动的 A
  • 无限大小的整数?

    在Python中 我可以编写一个程序来计算无限大小的整数 就在前几天 我做了百万分之一斐波那契数 它太大了 无法放入控制台 如果可以在 Python 中做到这一点 据我了解 Python 是用 C 编写的 那么如何在 C 中做到同样的事情呢
  • 我们如何跟踪 Javascript 错误?现有的工具真的有用吗?

    今天我发现需要跟踪和检索 Javascript 错误堆栈跟踪来解决这些问题 今天 我们能够捕获所有其余调用 其想法是 一旦出现错误 就会自动发布该错误的堆栈跟踪以及其余保存的服务的响应 以便我们可以以几乎相同的方式检测 重现和解决问题环境
  • 使用 XHR 流时通过 SockJs 确定 STOMP 的用户

    客户端不支持WebSockets 因此SockJs使用XHR Streaming和defineUser 虽然在使用WebSockets时被调用 但根本不会被调用 还有其他方法来设置本金吗 这就是我所拥有的 class CustomHands
  • 从系列/列中查找第一个元素(例如“True”)的索引

    如何查找系列或列中元素的索引 例如 True 例如 我有一个列 我想在其中识别事件发生的第一个实例 所以我把它写成 Variable df Force lt event 然后 这将创建一系列布尔数据 其中为 False 直到第一个实例变为
  • RAML:嵌套模式

    1 编写 RAML 时 我可以在模式定义中使用嵌套吗 例如 schemas DNSResponse type object properties AnswerSection type array items I want a re usea
  • Rails ActiveRecord::多参数分配错误

    我的模型中有以下代码 attr accessor expiry date validates presence of expiry date on gt create message gt can t be blank 我认为以下几点 但是
  • WebClient.UploadString 方法的最大数据长度

    我的 asp net mvc 应用程序中有以下代码 string URI http send url com smsapi sender php string queryParameters a long query string stri
  • scipy curve_fit多系列数据

    我试图建立一个曲线拟合 考虑基于相同 x 值和相同 指数 定律的多个 y 系列 该系列中的 y 值略有不同 因为它们是实验性的 但仍然很接近 x 相同 我尝试构建两个数组 一个包含 x 另一个包含两个不同系列的 y def f x a b
  • ContentResolver.bulkInsert(..) 的意义是什么?

    My goal 我想批量 以事务方式 将多条记录插入到sqlite中 我的问题 我找到了方法android content ContentResolver 批量插入 http android git kernel org p platfor
  • PHP 中的位操作和 MySQL 检索

    我正在尝试稍微优化我的 mysql 表 以获得一个更易于管理的表 我想将用户权限存储在一个位字段中 例如 用户权限可以是 0110 我的用户权限数量越来越多 因此长度可能会长一点 该示例可能对应于以下内容 0 用户不能在网站上发布新闻 1
  • Groovy 中的爬虫(JSoup VS Crawler4j)

    我希望在 Groovy 中开发一个网络爬虫 使用 Grails 框架和 MongoDB 数据库 它能够爬取网站 创建网站 URL 及其资源类型 内容 响应时间和涉及的重定向数量的列表 我正在争论 JSoup 与 Crawler4j 我已经阅
  • HTML5 日期输入 6 位数年份

    我有一个标准
  • 设置 QMessageBox 的父级

    我不明白设置父级有什么好处QMessageBox 例如在以下代码中 void mainWindow showMessage QString msg QMesageBox information this title msg this is
  • 如何创建批处理文件来在Cmder中执行命令?

    我想创建一个启动 Cmder 的批处理文件 然后在 Cmder 中执行一些命令 我知道如何使用批处理文件启动 Cmder 但不知道如何使用批处理文件在 Cmder 中编写 执行命令 我尝试这个 echo off cd C Program F
  • 将 html 内联图像从浏览器复制/粘贴到文字处理器

    我正在尝试使用 html 内联图像 背景 尝试创建我自己的 CMS 它不会将图像保留为单独的文件 我可以将此类图像从浏览器 Firefox IE 复制 粘贴到 Photoshop 或 MS Paint 等图像处理程序 但不能复制到 MS W
  • 使用 svn+ssh 协议通过 2 跳访问 Subversion 存储库

    我的 Ubuntu Subversion 服务器无法直接访问互联网 192 168 1 2 我的公共 Ubuntu 机器通过 DMZ 暴露在 192 168 1 1 我已经设置了从 192 168 1 1 3906 到 192 168 1
  • C 中的“double”运算和优化

    我最近分析了一段用 VS2005 编译的旧代码 因为 调试 无优化 和 发布 O2 Oi Ot 选项 编译中的数值行为不同 简化的 代码如下所示 void f double x1 double y1 double x2 double y2