C++ 中正弦、余弦和平方根的最快实现(不需要太精确)

2024-01-09

我在过去一个小时内搜索了这个问题,但只有泰勒级数或一些示例代码要么太慢要么根本无法编译。好吧,我在谷歌上找到的大多数答案都是“谷歌一下,已经有人问过了”,但遗憾的是it's not...

我在低端 Pentium 4 上分析我的游戏,发现大约 85% 的执行时间浪费在计算正弦、余弦和平方根(来自 Visual Studio 中的标准 C++ 库),这似乎严重依赖于 CPU(在我的 I7 上,相同的函数只执行了 5% 的时间,而且游戏是哇啊啊啊啊啊啊快点)。我无法优化这三个函数,也无法一次性计算正弦和余弦(相互依赖),但我的模拟不需要太准确的结果,因此我可以接受更快的近似。

那么,问题是:在 C++ 中计算 float 的正弦、余弦和平方根的最快方法是什么?

EDIT查找表更加痛苦,因为在现代 CPU 上产生的缓存缺失比泰勒级数的成本要高得多。现在的 CPU 速度太快了,而缓存则不然。

我犯了一个错误,我认为我需要计算泰勒级数的几个阶乘,我现在看到它们可以作为常量实现。

所以更新的问题:平方根是否也有快速优化?

EDIT2

我使用平方根来计算距离,而不是归一化 - 无法使用快速反平方根算法(如评论中指出的:http://en.wikipedia.org/wiki/Fast_inverse_square_root http://en.wikipedia.org/wiki/Fast_inverse_square_root

EDIT3

我也无法对平方距离进行操作,我需要精确的距离进行计算


这是 C++ 中保证最快的正弦函数:

double FastSin(double x)
{
    return 0;
}

哦,您想要比 |1.0| 更高的精度吗?好吧,这是一个同样快的正弦函数:

double FastSin(double x)
{
    return x;
}

这个答案,当 x 接近于零时。对于较小的 x,sin(x) 约等于 x https://en.wikipedia.org/wiki/Small-angle_approximation,因为 x 是 sin(x) 泰勒展开式的第一项。

什么,对你来说还不够准确?继续阅读吧。

20 世纪 70 年代的工程师在这一领域取得了一些奇妙的发现,但新程序员根本不知道这些方法的存在,因为它们没有作为标准计算机科学课程的一部分进行教授。

你需要首先了解这一点没有“完美”的实施这些功能适用于所有应用程序。因此,对“哪一个最快”之类的问题的肤浅回答肯定是错误的。

问这个问题的人大多不明白这个问题的重要性性能和准确性之间的权衡。特别是,在执行其他操作之前,您必须对计算的准确性做出一些选择。您可以容忍结果中有多少误差? 10^-4? 10^-16?

除非您可以用任何方法量化错误,否则不要使用它。请参阅我下面的所有随机答案,这些答案发布了一堆随机的未注释的源代码,没有清楚地记录所使用的算法及其exact输入范围内的最大误差? “我猜这个错误大约是一种咕哝声。”这完全是丛林联盟。如果您不知道如何计算PRECISE最大误差,至FULL精度,在你的近似函数中,跨越ENTIRE输入的范围...那么您不知道如何编写近似函数!

没有人单独使用泰勒级数来近似软件中的超越数。除了某些高度具体的案例 https://math.stackexchange.com/questions/1344627/how-to-use-chebyshev-polynomials-to-approximate-sinx-and-cosx-within-t,泰勒级数一般缓慢接近目标跨越常见的输入范围。 https://math.stackexchange.com/questions/1344627/how-to-use-chebyshev-polynomials-to-approximate-sinx-and-cosx-within-the-int

您的祖父母用来有效计算超越数的算法统称为CORDIC https://en.wikipedia.org/wiki/CORDIC并且足够简单,可以在硬件中实现。这里有一个C 中记录良好的 CORDIC 实现 https://people.sc.fsu.edu/%7Ejburkardt/cpp_src/cordic/cordic.html。 CORDIC 实现通常需要一个非常小的查找表,但大多数实现甚至不需要可用的硬件乘法器。大多数 CORDIC 实现都可以让您在性能和准确性之间进行权衡,包括我链接的那个。

多年来,原始 CORDIC 算法已经有了很多渐进式改进。例如,去年日本的一些研究人员发表了一篇article http://www.jiii.org/uploadfile/2015/0911/20150911044421219.pdf改进的 CORDIC 具有更好的旋转角度,从而减少了所需的操作。

如果你有硬件乘法器(你几乎肯定有),或者如果你买不起像 CORDIC 需要的查找表,你总是可以使用切比雪夫多项式 https://www.embeddedrelated.com/showarticle/152.php做同样的事情。切比雪夫多项式需要乘法,但这在现代硬件上很少成为问题。我们喜欢切比雪夫多项式,因为对于给定的近似值,它们具有高度可预测的最大误差 https://math.stackexchange.com/questions/1344627/how-to-use-chebyshev-polynomials-to-approximate-sinx-and-cosx-within-t。在输入范围内,切比雪夫多项式最后一项的最大值限制了结果中的误差。并且随着项数变多,这个误差会变小。这是一个例子 https://web.archive.org/web/20200628195036/http://mooooo.ooo/chebyshev-sine-approximation/切比雪夫多项式在大范围内给出正弦近似,忽略正弦函数的自然对称性,只是通过向其投入更多系数来解决近似问题。这是将正弦函数估计到 5 个 ULP 以内的示例 https://web.archive.org/web/20200628195036/http://mooooo.ooo/chebyshev-sine-approximation/。不知道什么是ULP?你应该。 https://en.wikipedia.org/wiki/Unit_in_the_last_place

我们也喜欢切比雪夫多项式,因为近似误差在输出范围内均匀分布。如果您正在编写音频插件或进行数字信号处理,切比雪夫多项式可以“免费”为您提供廉价且可预测的抖动效果。

如果您想在特定范围内找到自己的切比雪夫多项式系数,许多数学库将查找这些系数的过程称为“切比雪夫拟合 https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.polynomial.chebyshev.Chebyshev.fit.html“ 或类似的东西。

平方根,无论当时还是现在,通常都是用以下公式的一些变体来计算:牛顿-拉夫森算法 https://www.youtube.com/watch?v=2158QbsunA8,通常具有固定的迭代次数。通常,当有人制作出一个“惊人的新” https://stackoverflow.com/questions/1349542/john-carmacks-unusual-fast-inverse-square-root-quake-iii求平方根的算法,它只是伪装的牛顿拉夫森算法。

Newton-Raphson、CORDIC 和 Chebyshev 多项式可让您以速度换取准确性,因此答案可以像您想要的那样不精确。

最后,当您完成所有精美的基准测试和微优化后,请确保您的“快速”版本实际上比库版本更快。这是 fsin() 的典型库实现 http://www.netlib.org/fdlibm/k_sin.c限制在从 -pi/4 到 pi/4 的域上。而且速度并没有那么慢。

最后要提醒您的是:您几乎肯定会使用 IEEE-754 数学来执行估计,并且每当您使用一堆乘法执行 IEEE-754 数学时,几十年前做出的一些晦涩的工程决策就会再次出现。你,以舍入误差的形式。这些错误一开始很小,但它们会变得越来越大,越来越大!在你生命中的某个时刻,请阅读“每个计算机科学家都应该了解浮点数” https://www.itu.dk/%7Esestoft/bachelor/IEEE754_article.pdf并有适当程度的恐惧。请记住,如果您开始编写自己的超越函数,则需要对浮点舍入造成的实际误差进行基准测试和测量,而不仅仅是最大理论误差。这不是一个理论上的问题;而是一个问题。在不止一个项目中,“快速数学”编译设置让我很恼火。

TL:博士;去谷歌“正弦近似”或“余弦近似”或“平方根近似”或“近似理论 https://en.wikipedia.org/wiki/Approximation_theory."

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

C++ 中正弦、余弦和平方根的最快实现(不需要太精确) 的相关文章

  • 我们可以在 C# 中定义枚举的隐式转换吗?

    是否可以在 C 中定义枚举的隐式转换 可以实现这一目标的东西吗 public enum MyEnum one 1 two 2 MyEnum number MyEnum one long i number 如果没有 为什么不呢 有一个解决方案
  • 求 a 范围内的 pow(a^b)modN

    对于给定的b and N以及一系列a say 0 n 我需要找到ans 0 n 1 where ans i 没有a s为此pow a b modN i 我在这里搜索的是可能的重复pow a b modN对于一系列a 以减少计算时间 例子 i
  • 在子目录中构建共享库

    我正在尝试构建一个使用一些 C 代码的 R 包 我有一个编译为可执行文件的 C 库 可以从命令行调用 有一个与之关联的 Makefile 我正在尝试获取信息here http cran r project org doc manuals R
  • 运行时两个注册之间的简单注入器基于动态上下文的注入

    我有一个使用 Simple Injector 进行命令处理程序注册的中介应用程序 并且注入和处理程序均已设置并完美运行 class DoWashingCommandHandler IRequestHandler
  • 在异步方法中使用时 HttpClient 标头被清空

    我正在使用 NET Framework 4 6 1 我的 Web api 中有一个控制器 其中有静态 HttpClient 来处理所有 http 请求 在 IIS 上托管我的应用程序后 大约每月一次 我的应用程序的所有传入请求都会出现以下异
  • VS2010中VSHost.exe不断启动

    我正在 VS2010 中使用一个包含大量项目的解决方案 但它不断变得无响应 我注意到的一件事可能是一条线索 尽管我尚未开始任何调试 但 MyApplicationName vshost exe 不断出现在进程列表中 也许每当构建发生时它就会
  • 如何在 C++ 中从模板基类的构造函数调用模板超类的构造函数?

    我正在使用 sublimetext3 用 c 进行编程 我的程序有一个名为 Array 的超类和一个名为 IntArray 的子类 这两个类都是模板类 目前 我在编译该程序时遇到问题 它不断在我的 IntArray cpp 文件中给出错误
  • 如何将 QSerialPort 模块添加到 CMake 中?

    我想将 QSerialPort 模块添加到 CMake 中 根据我的理解 我需要将QT 串口添加到 pro中 我只想使用 CMake 所以我尝试编译简单的 CMake 文件 但有错误 QtCore 正在工作 qDebug 可以毫无问题地显示
  • 使用私有构造函数的 C# 单元测试类?

    好吧 我刚刚收到一个作业 我必须对具有私有构造函数的类执行单元测试 现在 当所有方法也都是非静态时 我该如何在不初始化类的情况下进行单元测试 有什么方法可以对具有私有构造函数的类进行单元测试 无需反射 如果您无法将类公开 您仍然可以通过以下
  • 解析通过asp:FileUpload上传的XML文件

    我有一个场景 用户将上传 XML 文件 我想将该文件添加到数据库中的表中 不过 困难的部分是我需要解析文件 然后将一些信息添加到一些不同的表中 显示如何获取 XML 文件的每个示例都使用 URI 来获取文件 但是如何直接从数据库获取文件 或
  • 第三方引用的 dll 未被复制来构建

    我有一个第三方 net dll 被我的 dll 类库项目 A 引用和使用 我的控制台应用程序项目 B 引用项目 A 我的问题是第三方 dll 没有被复制到控制台应用程序项目 B 的构建中 这里有什么问题呢 我的 dll 类库中引用的第三方
  • UWP - 绑定枚举差异

    我遇到了一个非常有趣的问题 假设 UWP 应用中有以下 XAML 页面内容
  • Excel 2007 中的数值 - 底层 xml 文件中的表示与存储

    这个问题与 NET和OpenXml有关 我已经阅读了以下文章 它有很好的解释 但没有回答我的问题 Excel 2007 中数值的可视化与底层 xml 文件不一致 https stackoverflow com questions 58594
  • OpenMP 循环数组访问中的错误共享

    我想利用 OpenMP 来并行执行我的任务 我需要将数组的所有元素减去相同的数量并将结果写入另一个向量中 两个数组都是动态分配的malloc第一个填充了文件中的值 每个元素都有类型uint64 t pragma omp parallel f
  • 链接错误:xxx 已在 *****.LIB 中定义:: 究竟出了什么问题?

    Problem 我正在尝试使用一个名为DCMTK http dicom offis de dcmtk它使用了一些其他外部库 zlib libtiff libpng libxml2 libiconv 我已经从同一网站下载了这些外部库 LIB
  • 合并大文件的最佳方法是什么?

    我必须合并数千个大文件 每个大约 200MB 我想知道合并这些文件的最佳方法是什么 行将有条件地复制到合并文件中 可以使用 File AppendAllLines 或使用 Stream CopyTo 吗 使用 File AppendAllL
  • Javascript - HTML Canvas 上的 Gecko 边框半径自适应(CSS border-radius)

    我试图弄清楚如何将 border radius css 属性的行为重现到 HTML 画布中 所以我已经在 J avascript 中做了一些事情 以便使用特定的半径 对于每个角 来计算给定形状的正确边界 如果需要的话 这是上一个问题 Gec
  • 将 R 值传递给采用 L 值的函数时出现过载歧义

    我有 2 个重载函数 一个采用 L 值 另一个采用 R 值 目的是让该函数可以像这样调用 Obj obj foo obj OR foo Obj 所以 我写了2个重载函数 template
  • 在不打开文件的情况下操作/复制 .CSV 数据?

    我正在尝试优化一些代码 这些代码使用存储在 CSV 文件中的一些测试数据进行一些分析并将其数据复制到 Excel 工作表中 此代码通常一次运行数百个测试 每个测试大约需要 4 5 秒 因此有时可能需要几个小时才能完成 我查阅了一些优化技术
  • 有关 Endian 性和 .Net 的详细信息?

    我有几个关于字节顺序的问题 这些问题足够相关 我保证将它们作为一个问题提出 1 字节顺序是由 Net还是由硬件决定的 2 如果是由硬件决定的 我怎样才能在C 中找出硬件的字节序 3 字节序是否影响二进制交互 例如 OR AND OR 或移位

随机推荐

  • 如何像我们做扩展一样在VSCODE上发布LSP语言服务器

    已经通过官方网站 发布扩展的整个过程都有很好的记录 vscode 发布扩展 https code visualstudio com docs extensions publish extension 我的疑问是在 vscode 中发布语言服
  • scrapy - 每个 starurl 单独的输出文件

    我有一个运行良好的 scrapy 蜘蛛 coding utf 8 import scrapy class AllCategoriesSpider scrapy Spider name vieles allowed domains examp
  • angular-ui-router 1.0.x:event.preventDefault 和 event.defaultPrevented 替代方案

    我刚刚更换了 stateChangeStart with transitions onStart rootScope on stateChangeStart function e e preventDefault other code go
  • 当我按下按钮时,方法没有被调用

    我正在使用反应导航 并在右侧添加了一个按钮 用于使用默认导航选项从我的应用程序注销 如下所示 const otherApp createStackNavigator Welcome screen WelcomeScreen defaultN
  • 发送自己的 API 的 Cookie 或标头以防止 Google Cloud Identity Aware Proxy (IAP) 302?

    我已经在开发环境上设置了 Cloud IAP 与 Kubernetes 一起启动并使用 Let s Encrypt 一切正常 这个应用程序的设置非常基本 1 An API在项目中具有许多 REST 端点和持久数据存储A 2 A SPA利用所
  • Oracle数据库通过命令提示符导入.sql文件

    我想通过命令提示符在 Oracle 中导入 sql 文件 所以请告诉我在oracle中导入 sql文件的命令 在 MYSQL 中我像这样使用它 mysql u root p h localhost softpoint lt D Nisarg
  • Bootstrap 为列添加边距

    这可能很简单 但我的思绪却纠结于如何解决这个问题 花了一个小时左右搜索这个 但仍然不起作用 我的 HTML 代码 div class section container light bg div class container div cl
  • .NET Core 中的 AES-256-CBC (C#)

    我正在搜索 C 代码来重现以下 openssl 命令 openssl enc d aes 256 cbc in my encrypted file csv enc out my decrypted file csv pass file ke
  • 为什么我的 git 没有从 1.7.1 更新到 1.9.4

    我在REDHAT 6上 我想更新我的git 我尝试了多种方法 第一种方法 yum 更新 git 我得到 没有标记为更新的软件包 第二种方法 wget http git core googlecode com files git 1 8 3
  • 如何在android中关闭AlertDialog

    我创建了包含 4 个按钮的 AlertDialog OptionDialog new AlertDialog Builder this OptionDialog setTitle Options LayoutInflater li Layo
  • 数据库安全的日期/时间字符串?

    哪种格式的日期 时间字符串被认为是跨平台 跨数据库 通用安全的 这会吗YYYY MMM DD HH MM SS在 MySQL SQLite 2 3 MsSQL 和其他常见数据库中使用是否被认为是安全的 怎么样2010 Jul 12 12 0
  • 通用哈希函数系列只是为了防止敌人攻击吗?

    如果我的目的只是拥有一个好的哈希函数 将数据均匀地分布到所有存储桶中 那么我不需要想出一系列哈希函数 我只需使用一个好的哈希函数即可 对吗 拥有一系列哈希函数的目的只是让敌人更难构建病态数据集 因为当我们随机选择哈希函数时 他 她不知道使用
  • 创建梯度并返回方法

    抱歉 关于 iPhone 和 Quartz 编程的新手问题 刚刚开始从 C 到 Objective C 的转换 所以 我有这样一个类方法 CGGradientRef CreateGradient UIColor startColor end
  • 在映射内缩进 YAML 序列

    以下内容应该有效吗 parent child child 所以我们拥有的是映射内的一系列值 具体问题是第二行和第三行的缩进是否有效 Ruby YAML dump 生成了此代码 但是 Yaml 解析器here http www codepro
  • TFS 2010 中 witadmin 操作的日志在哪里?

    从 Visual Studio 2010 命令行运行 witadmin 命令时 此操作记录在 TFS 2010 中的何处 一个示例命令是 C gt witadmin exportwitd collection http server 808
  • 如何在 Dart 中返回不可变列表?

    所以在其他语言中有ArrayList or MutableList它允许修改 添加 删除 删除 列表项 现在为了避免修改这些列表 只需返回MutableList or ArrayList as a List 我想做同样的事情Dart 但在D
  • 如何在 Objective C 中使用 strlen 查找字符串长度

    我有一个字符串存储在字符串变量中 我想查找 str 变量中可用的字符串长度 我尝试过 strlen str 它不工作 如果您的字符串是 C 字符串 那么您可以使用strlen str 如果它是一个NSString str 那么你可以使用NS
  • 使用默认值而不是异常来提升 numeric_cast<> ?

    每当升压时numeric cast lt gt 转换失败 会抛出异常 boost 中是否有类似的模板可以让我指定默认值 或者在这种情况下捕获异常是我唯一能做的事情 我不太担心所有额外异常处理的性能 但我宁愿使用标准模板也不愿编写无用的包装函
  • 找不到 PROTOBUF 编译器

    我正在尝试使用 Caffe 进行 CMake 但我的系统找不到 protobuf 编译器 我之前安装过protobuf2 7 0 现在我切换回2 6 1 如何配置我的 CMake 来识别 protobuf2 6 1 编译器 我已经做好了 s
  • C++ 中正弦、余弦和平方根的最快实现(不需要太精确)

    我在过去一个小时内搜索了这个问题 但只有泰勒级数或一些示例代码要么太慢要么根本无法编译 好吧 我在谷歌上找到的大多数答案都是 谷歌一下 已经有人问过了 但遗憾的是it s not 我在低端 Pentium 4 上分析我的游戏 发现大约 85