为什么将 0.1f 更改为 0 会使性能降低 10 倍?

2023-12-01

为什么这段代码,

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0.1f; // <--
        y[i] = y[i] - 0.1f; // <--
    }
}

运行速度比以下位快 10 倍以上(除非另有说明,否则相同)?

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0; // <--
        y[i] = y[i] - 0; // <--
    }
}

使用 Visual Studio 2010 SP1 编译时。 优化级别为-02 with sse2已启用。 我还没有用其他编译器进行测试。


欢迎来到非规范化浮点!它们会对性能造成严重破坏!

非正规(或次正规)数字是一种从浮点表示中获取一些非常接近于零的额外值的黑客方法。对非规范化浮点的运算可以是慢几十到几百倍比标准化浮点数。这是因为许多处理器无法直接处理它们,必须使用微代码捕获和解析它们。

如果您在 10,000 次迭代后打印出数字,您将看到它们已收敛到不同的值,具体取决于是否0 or 0.1用来。

这是在 x64 上编译的测试代码:

int main() {

    double start = omp_get_wtime();

    const float x[16]={1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4,2.5,2.6};
    const float z[16]={1.123,1.234,1.345,156.467,1.578,1.689,1.790,1.812,1.923,2.034,2.145,2.256,2.367,2.478,2.589,2.690};
    float y[16];
    for(int i=0;i<16;i++)
    {
        y[i]=x[i];
    }
    for(int j=0;j<9000000;j++)
    {
        for(int i=0;i<16;i++)
        {
            y[i]*=x[i];
            y[i]/=z[i];
#ifdef FLOATING
            y[i]=y[i]+0.1f;
            y[i]=y[i]-0.1f;
#else
            y[i]=y[i]+0;
            y[i]=y[i]-0;
#endif

            if (j > 10000)
                cout << y[i] << "  ";
        }
        if (j > 10000)
            cout << endl;
    }

    double end = omp_get_wtime();
    cout << end - start << endl;

    system("pause");
    return 0;
}

Output:

#define FLOATING
1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007
1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007

//#define FLOATING
6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.46842e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044
6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.45208e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044

请注意,在第二次运行中,数字非常接近于零。

非规范化数字通常很少见,因此大多数处理器不会尝试有效地处理它们。


为了证明这与非规范化数字有关,如果我们将非正规值刷新为零将其添加到代码的开头:

_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);

然后是版本0不再慢 10 倍,实际上变得更快。 (这要求在启用 SSE 的情况下编译代码。)

这意味着我们不使用这些奇怪的低精度几乎为零的值,而是四舍五入到零。

时序:Core i7 920 @ 3.5 GHz:

//  Don't flush denormals to zero.
0.1f: 0.564067
0   : 26.7669

//  Flush denormals to zero.
0.1f: 0.587117
0   : 0.341406

最后,这实际上与它是整数还是浮点数无关。这0 or 0.1f被转换/存储到两个循环之外的寄存器中。所以这对性能没有影响。

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

为什么将 0.1f 更改为 0 会使性能降低 10 倍? 的相关文章

  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 在 nHibernate 关系中使用实体的 Lite 版本?

    在某些情况下 出于性能原因 创建一个实体的轻量级版本 指向同一个表 但映射的列较少 这是一个好主意吗 例如 如果我有一个包含 50 列的联系人表 并且在一些相关实体中 我可能对 FirstName 和 LastName 属性感兴趣 那么创建
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐

  • JVM是否保证缓存非易失性变量?

    JVM是否保证缓存非易失性变量 程序员是否可以依赖 JVM 始终在本地为每个线程缓存非易失性变量 或者 JVM 可能会也可能不会这样做 因此程序员不应该依赖 JVM 来做到这一点 感谢您提前的答复 不 JVM 不保证非易失性字段的 缓存 J
  • Gremlin - 随机选择一项

    将我视为 用户 1 查询的目的是获取我关注的人 发布 的帖子 并对每个帖子进行检查 是否已被我喜欢过 我关注的其他人是否喜欢它 如果是随机选择其中一位用户返回 样本数据 g addV user property id 1 as 1 addV
  • OpenCV 从标准输入加载图像/视频

    我正在尝试使用以下代码从 stdin 读取 jpg 图像 int c count 0 vector
  • 在 Xcode 7 中构建 Parse 时出现链接错误

    我正在尝试将 Parse com SDK 添加到我的 Xcode 7 项目中 我已经遵循了入门指南 并且之前已经在 Xcode 6 中成功做到了 然而 这次当我尝试构建时 我收到了此错误消息 ld framework not found B
  • 列表视图列标题不显示 VB.Net

    我没有在 listView 中获取列标题 仅显示一项 0 不显示子项 这是我的代码 告诉我其中有什么问题 先感谢您 Dim PTCode As Integer CInt ChildPatnameTag ClearSQl CheckState
  • 部署项目中的安装目录

    我正在开发一个应用程序 我将在部署项目 将创建一个安装程序 的帮助下部署它 在安装程序的一个步骤中 用户将允许更改应用程序的安装文件夹 我需要知道这个文件夹是什么 因为那里保存了一些我需要从另一个 DLL 文件中使用的文件 如何以编程方式获
  • AutoCompleteTextView 未从 Google Places API 获取建议

    这是我从 Google Places API 获取地点建议的代码 但它显示一些错误 例如 无法连接到 Google Places API 我已经给出了在这段代码的底部得到的正确错误 我只需要一个 AutoCompleteTextView 来
  • 是否可以在 java (log4j) 中记录方法调用?

    是否可以在 log4j Java 中记录任何方法调用 Thanks 不 如果不编辑调用站点或方法本身就不行 我认为您所追求的是面向方面的编程 看一下AspectJ例如
  • 使用 Nodejs 实时抓取聊天记录

    我想做的是建立一个scrapingNodeJs 上的应用程序 它可以实时监控聊天并将某些消息存储在任何数据库中 我想做的是以下内容 我想从聊天平台流中捕获数据 从而捕获一些有用的信息来帮助那些正在做流媒体服务的人 但我不知道如何开始使用 N
  • Python unicode 解码错误 SUD

    好的 我有 coding utf 8 在我的脚本的顶部 它可以从数据库中提取数据 其中包含有趣的字符 并将该数据存储到变量中 但是我遇到其他问题 请参阅我提取数据 组织它 然后将其转储到变量中 如下所示 title product 1 Wh
  • 通过 Web 应用程序启动 Spark 应用程序的最佳实践?

    我想通过 Web 应用程序向用户公开我的 Spark 应用程序 基本上 用户可以决定他想要运行哪个操作并输入一些变量 这些变量需要传递到 Spark 应用程序 例如 用户输入几个字段 然后单击一个按钮 该按钮执行以下 运行火花应用1带参数
  • `eli5.show_weights` 显示的标准差与 `feature_importances_std_` 中的值不一致

    The PermutationImportance对象有一些很好的属性 例如feature importances and feature importances std 为了以 HTML 样式可视化此属性 我使用了eli5 show we
  • THREE.js 动态添加点到 Points 几何体不渲染

    我正在使用 Three js r83 我试图动态地将点添加到几何体中 但场景永远不会更新 这有效 var tmaterial new THREE PointsMaterial color 0xff0000 size 5 opacity 1
  • 设计问题:std::map的线程安全

    我正在使用 std map 来实现我的本地哈希表 该哈希表将同时被多个线程访问 我做了一些研究 发现 std map 不是线程安全的 所以我将使用互斥体在地图上进行插入和删除操作 我计划有单独的互斥锁 每个映射条目都有一个互斥锁 以便可以独
  • C++ 数组:为什么 delete[] 不起作用? [复制]

    这个问题在这里已经有答案了 当我运行以下代码时 include
  • 确定 2 个列表是否具有相同的元素,无论顺序如何? [复制]

    这个问题在这里已经有答案了 抱歉这个简单的问题 但我很难找到答案 当我比较两个列表时 我想知道它们是否 相等 因为它们具有相同的内容 但顺序不同 Ex x a b y b a I want x y评估为True 您可以简单地检查包含 x 和
  • 通过查询参数选择 Jersey 方法

    我需要实现一个使用第一个查询参数来识别操作的网络服务 即客户端调用将类似于 http localhost 8080 ws operation info or http localhost 8080 ws operation create n
  • RDS数据库的本地副本

    在过去一个小时左右的时间里 我一直在进行一些研究 并且听到了一些有关 Amazon RDS 数据库复制的相互矛盾的信息 我的数据库相当大 有 15 个表 总大小为 4 GB 那么 基本上 我是否可以创建远程 RDS InnoDB 的本地副本
  • 常驻后端 Google App Engine“/_ah/background”(Python)

    有人可以帮我理解谷歌应用程序引擎 Python 中的 ah background 是什么吗 我有一个正在运行的常驻后端 并且我看到向该端点发出的请求 它们似乎是由我的代码之外的某些东西生成的 它们似乎也由我的 ah start 处理程序处理
  • 为什么将 0.1f 更改为 0 会使性能降低 10 倍?

    为什么这段代码 const float x 16 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 const float z 16 1 123 1 234 1