为什么这两个代码变体会产生不同的浮点结果?

2024-02-07

给出这个示例 C++ 代码片段:

void floatSurprise()
{
    // these come from some sort of calculation
    int a = 18680, b = 3323524, c = 121;
    float m = float(a) / c;

    // variant 1: calculate result from single expression
    float r1 = b - (2.0f * m * a) + (m * m * c);
    cout << "r1 = " << r1 << endl;

    // variant 2: break up the expression into intermediate parts, 
    /// then calculate 
    float
        r2_p1 = 2.0f * m * a,
        r2_p2 = m * m * c,
        r2 = b - r2_p1 + r2_p2;

    cout << "r2 = " << r2 << endl;
}

输出是:

开发者1 = 439703
开发2 = 439702

在调试器中查看时,这些值实际上分别是 439702.50 和 439702.25,这本身就很有趣 - 不知道为什么 iostream 默认情况下打印没有小数部分的浮点数。EDIT:原因是 cout 的默认精度设置太低,至少需要 cout

但我更感兴趣的是为什么我会得到不同的结果。我想这与舍入和整数与所需浮点输出类型的一些微妙相互作用有关,但我无法指出它。哪个值是正确的?

我很惊讶用这么简单的一段代码很容易搬起石头砸自己的脚。任何见解将不胜感激!编译器是VC++2010。

EDIT2:我使用电子表格进行了更多调查,为中间变量生成“正确”值,并发现(通过跟踪)它们确实被修剪,导致最终结果的精度损失。我还发现了单个表达式的问题,因为我实际上使用了一个方便的函数来计算平方而不是m * m there:

template<typename T> inline T sqr(const T &arg) { return arg*arg; }

尽管我很好地询问,编译器显然没有内联它,而是单独计算值,在将值返回到表达式之前修剪结果,再次扭曲结果。哎哟。


你应该阅读我很长很长的答案,了解为什么 C# 中会发生同样的事情:

(.1f+.2f==.3f) != (.1f+.2f).Equals(.3f) 为什么? https://stackoverflow.com/questions/15117037/1f-2f-3f-1f-2f-equals-3f-why/15117741#15117741

总结:首先,使用 float 只能获得大约小数点后七位的精度。如果您在整个计算过程中使用精确的算术对其进行计算,则正确答案约为 439702.51239669...因此,无论哪种情况,考虑到浮点数的限制,您都非常接近正确答案。

但这并不能解释为什么看似完全相同的计算却得到不同的结果。答案是:编译器有很大的自由度来进行数学计算更准确,显然您遇到了两种情况,优化器采用逻辑上相同的表达式,但不会将它们优化为相同的代码。

不管怎样,请仔细阅读我关于 C# 的回答;其中的所有内容也适用于 C++。

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

为什么这两个代码变体会产生不同的浮点结果? 的相关文章

  • 实体框架中的重复键异常?

    我试图捕获当我将具有给定用户名的现有用户插入数据库时 引发的异常 正如标题所说 我正在使用 EF 当我尝试将用户插入数据库时 引发的唯一异常是 UpdateException 如何提取此异常以识别其是否是重复异常或其他异常 catch Up
  • 此插件导致 Outlook 启动缓慢

    我正在使用 C NET 4 5 开发 Outlook Addin 项目 但部署后 有时 Outlook 会禁用我的插件 并显示此消息 这个插件导致 Outlook 启动缓慢 我不知道我的插件出了什么问题 这只有很少的代码 并且ThisAdd
  • 浏览器收集哪些值作为回发数据?

    当页面被发送回服务器时 浏览器收集每个控件的当前值并将其粘贴到一个字符串中 然后 该回发数据通过 HTTP POST 发送回服务器 Q1 除了控件的 Text 属性和 SelectedIndexchanged 因此除了用户输入数据 之外 控
  • 如何检查 .NET 4.0 中的泛型参数是否是动态的

    我有课ObjectMapper
  • 当我尝试使用 AVX 功能时,Clang 生成错误

    我使用的是 Windows 10 使用 Clang 版本 5 最近安装 当我编译以下内容时 define AVX define AVX2 include
  • 将占位符文本添加到文本框

    我正在寻找一种将占位符文本添加到文本框的方法 就像在 html5 中使用文本框一样 IE 如果文本框没有文本 则会添加文本Enter some text here 当用户单击它时 占位符文本消失并允许用户输入自己的文本 如果文本框失去焦点并
  • 从 ef core 的子集合中删除一些项目

    我有一个父表和子表 其中父表与子表具有一对多关系 我想删除一些子项 并且希望父项的子集合反映该更改 如果我使用删除选定的子项RemoveRange 那么子集合不会更新 如果我使用Remove从子集合中删除子集合然后 显然 它不如使用效率高R
  • 为什么在 .net 中使用 Invoke on Controls? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么 NET不允许跨线程操作 https stackoverflow com questions 2896504 why net does not allow cross thread operat
  • 如何使用 C# 代码使用超链接的 onClick 事件?

    我正在尝试为页面中的超链接添加条件 而不是仅仅使用特定的链接 例如 a href help Tutorial html Tutorial a 我想为不同的用户显示不同的页面 例如 如果用户以管理员身份登录 他们将看到与普通用户不同的链接 我
  • 从存储过程返回 int 值并在 ASP.NET 代码中检查它以验证登录表单

    当我多次尝试但没有得到有效结果时 使此代码运行的真实顺序是什么 SQL存储过程的代码 set ANSI NULLS ON set QUOTED IDENTIFIER ON GO ALTER PROC dbo login proc usern
  • 打破条件变量死锁

    我遇到这样的情况 线程 1 正在等待条件变量 A 该变量应该由线程 2 唤醒 现在线程 2 正在等待条件变量 B 该变量应该由线程 1 唤醒 在我使用的场景中条件变量 我无法避免这样的死锁情况 我检测到循环 死锁 并终止死锁参与者的线程之一
  • fscanf 和 EOF 中的否定扫描集

    我的文件中有一个以逗号分隔的字符串列表 姓名 1 姓名 2 姓名 3 我想跳过所有逗号来阅读这些名字 我写了以下循环 while true if fscanf file my string 1 break 然而 它总是比预期多执行一次 给定
  • 停止 TcpListener 的正确方法

    我目前正在使用 TcpListener 来处理传入连接 每个连接都有一个线程用于处理通信 然后关闭该单个连接 代码如下 TcpListener listener new TcpListener IPAddress Any Port Syst
  • 使 C# 编译器相信执行将在成员返回后停止

    我认为目前这是不可能的 或者这是否是一个好主意 但这是我刚才正在考虑的事情 我使用 MSTest 对我的 C 项目进行单元测试 在我的一项测试中 我执行以下操作 MyClass instance try instance getValue
  • 检索 Autofac 容器以解析服务

    在 C WindowForms 应用程序中 我启动一个 OWIN WebApp 它创建另一个类 Erp 的单例实例 public partial class Engine Form const string url http 8080 49
  • 如何在Linux上构建GLFW3项目?

    我已经使用 cmake 和 make 编译了 glfw3 和包含的示例 没有出现任何问题 开始编写我的第一个项目 作为 opengl 和 glfw 的新手 并且对 C 和 CMake 没有经验 我正在努力理解示例构建文件 甚至要链接哪些库和
  • 为什么从绑定返回的对象会忽略额外的参数?

    假设我有一个带有两个参数的函数 void f int x int y 我想绑定其中之一 我可以用std bind如下 auto partiallyBoundF std bind f 10 1 partiallyBoundF仅需要一个参数 但
  • 编译器什么时候内联函数?

    在 C 中 函数仅在显式声明时才内联inline 或在头文件中定义 或者编译器是否允许内联函数 因为他们认为合适 The inline关键字实际上只是告诉链接器 或告诉编译器告诉链接器 同一函数的多个相同定义不是错误 如果您想在标头中定义函
  • 计算两个日期之间的工作日数?

    在C 中 如何计算business 或工作日 两个日期之间的天数 我以前曾经遇到过这样的任务 并且我已经找到了解决方案 当可以避免的时候 我会避免列举其间的所有日子 这里就是这种情况 正如我在上面的一个答案中看到的那样 我什至没有提到创建一
  • XmlDocument Save 使文件保持打开状态

    我有一个简单的 C 函数 可以创建一个基本的 XML 文件并保存 private void CreateXMlFile string Filename string Name string Company XmlDocument doc n

随机推荐

  • Span 不能是嵌套局部变量。为什么这是一个限制?

    以下内容无法编译 既然这不是匿名方法 lambda 表达式或查询表达式 为什么这是一个限制 将文本作为 ref ReadOnlySpan 传递效果很好 void TestNestedSpan var text Some text AsRea
  • Colorbox 使灯箱在滚动时固定

    我使用 jquery colorbox 当页面内容较大并且打开colorbox时 然后颜色框随着页面内容滚动 我希望即使背景内容滚动也需要修复颜色框 请帮我解决这个问题 也许所有这些答案都来自 colorbox 的早期版本 但 fixed
  • Java 颠倒文本 - 错误还是功能?

    在使用 Java 字体类和 Swing 时 我将字体大小设置为负值 我发现这会使文本被颠倒绘制 这是一个错误还是一个功能 谁能解释为什么会发生这种行为 试试看 import java awt Font import java awt Gra
  • 在 aspx 中包含 C# 文件代码

    我想在我的位置执行以下代码C 页 我知道这里还有更多类似的问题 但我找不到可以帮助我的东西 但是我在第一行收到服务器错误 The server block is not well formed 代码是 WebIntegrationRestS
  • “好”数字的算法

    如果数字 x 的任意两个连续数字之和在 k 和 2k 之间 则给定数字 x 是 好 我需要找到一种算法 对于给定的数字 k 和给定的数字 n 找出存在多少个 好 n 位数字 我在 PHP 中为此实现了一个实现 但复杂性太大 我正在搜索所有这
  • 对指针调用 free 两次

    我在讲座中被教导 召唤free 两次使用指针真的非常非常糟糕 我知道这是一个很好的做法 将指针设置为NULL 在释放它之后 然而 我仍然没有听到任何关于为什么会这样的解释 据我了解 方法malloc 有效 从技术上讲 它应该跟踪它已分配并供
  • WebException:服务器违反了协议。 Section=ResponseStatusLine(调用 Marketo SOAP API)

    我正在尝试调用 Marketo SOAP Web 服务 通过 ASP NET C 我成功添加了 Web 服务引用并尝试使用以下代码行调用它 SuccessGetLead lead service getLead paramsgetlead
  • 使用显示时没有底部填充:网格和滚动

    我有一个容器div有一些填充 display grid and overflow auto放 当一个孩子div的高度比父级的高度大 并且出现一个滚动条 它会滚动 以便没有底部填充 这里有一个Fiddler https jsfiddle ne
  • 绘图中的对数色阶

    我正在尝试使用一些异常值来可视化数据Plotly and Python3 异常值导致色阶图例看起来很糟糕 只有很少的高数据点 但图例看起来很糟糕 2k 和 10k 之间的空间太大 所以问题是 如何改变右侧 颜色图例 的外观 见下图 以便它主
  • 仍然可以在节点 run_list 中指定确切的食谱版本吗?

    我的笔记中有这样的内容 run list recipe email protected cdn cgi l email protection 可以明确指定在节点 run list 中使用的说明书版本 但我无法让它工作 也找不到任何文档来说明
  • TryFrom<&[T]> 和 TryFrom> 有什么区别?

    似乎有两种方法可以尝试将向量转换为数组 或者通过切片 fn a 或直接 fn b use std array TryFromSliceError use std convert TryInto type Input Vec
  • 如何将图像从 Laravel 控制器发送到 API Rest [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我需要从存储中获取图像Laravel并将其从控制器发送到外部 API REST 我正在使用 guzzlehttp multipart 但 A
  • 在 JPA 中使用泛型 @OneToMany

    我有一个班级 分支 我想在这里将其用作 Dictionary 和 Link 类 Entity public class Branch
  • 捕获异常时可以使用gdb进行回溯吗?

    我刚刚开始使用 C 异常并希望得到正确的解决方案 我的想法是在捕获异常时生成某种回溯信息 最初我有类似的想法C 中异常的调用堆栈 https stackoverflow com questions 3222890 call stack fo
  • 如果没有找到任何元素,我可以防止 Cypress cy.get 失败吗?

    我正在使用赛普拉斯cy get抓取元素 但如果没有 我的测试就会失败 我不想让它失败 我希望它继续下去 测试只是列出存在的项目 如果有 const listItemTitle data cy component list item titl
  • 在Python中,是否有一种优雅的方法可以以自定义格式打印列表而无需显式循环?

    我知道你能做到 print str myList to get 1 2 3 你可以做 i 0 for entry in myList print str i entry i 1 to get 0 1 1 2 2 3 但是有没有一种与第一种类
  • canvas.toDataURL() 不是函数 - 错误 node-webGL 包装器

    目前我正在尝试将基于浏览器的客户端体积渲染代码转换为服务器端纯基于 JavaScript 的渲染 我在服务器端使用node webgl 我的主要目标是将服务器的画布内容发送到客户端 然后将该图像数据显示在客户端上 但在此之前我需要检查渲染是
  • mysql 5.7 日志慢查询错误

    我试图在 mysql 5 7 上启用慢查询日志记录并收到此错误 2016 04 27T14 55 51 934612Z 0 错误 未知变量 log slow queries var log mysql query log 2016 04 2
  • 谷歌地图删除所有标记,然后创建新的

    我正在创建一个地图 默认情况下加载地址并显示标记并在搜索框中放置地址 效果很好 但我需要添加单击事件 该事件将首先删除所有标记 然后放置标记 到目前为止 我正在开发满足我需要的所有脚本 但是 当用户单击地图时 搜索框会获取地点地址 但旧标记
  • 为什么这两个代码变体会产生不同的浮点结果?

    给出这个示例 C 代码片段 void floatSurprise these come from some sort of calculation int a 18680 b 3323524 c 121 float m float a c