c++ - 关于优化的数学函数、范围和区间

标签 c++ c math optimization

我正在努力思考为游戏和渲染引擎编写数学函数的人如何以有效的方式使用优化的数学函数;让我进一步解释一下。

这些领域非常需要快速三角函数,有时您可以优化 sin , cos或其他函数,通过以仅对给定间隔有效的不同形式重写它们,通常这意味着您的近似值 f(x)仅用于第一象限,意思是 0 <= x <= pi/2 .

现在输入您的 f(x)仍然是关于所有 4 个象限,但真正的公式只覆盖了那个区间的 1/4,直接的解决方案是通过分析输入来检测象限,看看它属于哪个范围,然后相应地调整公式的结果如果输入来自不是第一象限的象限。

这在理论上是好的,但这也带来了一些非常糟糕的问题,特别是考虑到您这样做是为了从 CPU 中窃取几个周期(您还获得了一致的实现,它不像平台那样依赖于平台)硬编码 fsin in Intel x86 asm 仅适用于 x86 并具有一定的错误范围,所有这些在其他具有其他 asm 指令的平台上可能有所不同),因此您应该保持并发和高性能级别的工作。

我无法用象限解决方案解决“开关盒”的原因是:

  • 它只是防止可能的优化,即内存,考虑到你通常想把 switch-case在实际计算 f(x) 的相同函数中,也许可以通过实现 f(x) 的公式来改善这种情况。在所述函数之外,但这将导致为任何给定数学库维护的函数数量加倍
  • 通过并发执行增加更多分支的可能性
  • 一般来说,不会导致更好、干净、干燥的代码,条件语句通常是错误的潜在来源,我真的不喜欢 switch-case 和类似的东西。

  • 假设我可以实现我的跨平台 f(x)在 C 或 C++ 中,该领域的程序员通常如何解决将输入、象限通过实际实现转换和映射到结果的问题?

    最佳答案

    注意:在下面的答案中,我非常笼统地谈论代码。

    Assuming that I can implement my cross-platform f(x) in C or C++, how the programmers in this field usually address the problem of translating and mapping the inputs, the quadrants to the result via the actual implementation ?



    对此的一般答案是:以最明显和最简单的方式实现您的目的。

    我不完全确定我遵循了您的大部分论点/问题,但我有一种感觉,您正在寻找实际上不存在的问题。您真的需要重新实现三角函数吗?不要落入 NIH(不是在这里发明的)的陷阱。

    the straightforward solution is to detect the quadrant



    是的!我喜欢简单的代码。代码一目了然,它的作用一目了然。现在,有时,只是有时,你必须做一些疯狂的事情来让它做你想做的事:为了性能,或者避免你无法控制的错误。但是第一个版本应该是解决您的问题的最明显和最简单的代码。从那里你进行测试、分析和基准测试,如果(仅当)你发现性能或其他问题,那么你就会进入疯狂的事情。

    This is good in theory but this also presents a couple of really bad problems,



    我会说这在大多数情况下在理论上和实践中都是好的,我绝对没有看到任何“坏”问题。最多在特定的极端情况或设计要求中的小问题。

    关于你的一些具体评论的一些事情:
  • f(x) 的近似值仅适用于第一象限:是的,这有多种原因。一个简单的原因是大多数三角函数都有恒等式,因此您可以轻松地使用这些恒等式来减少输入参数的范围。这很重要,因为许多数值技术仅适用于特定范围的输入,或者对于小输入更准确/性能更高。接下来,对于非常大的输入,您无论如何都必须调整范围以使大多数数值技术工作或至少在相当长的时间内工作并具有足够的准确性。例如,查看 cos() 的泰勒展开式并查看对于大输入和小输入需要多长时间才能充分收敛。
  • 它只是阻止可能的优化:很有可能你的 C++ 编译器现在比你更擅长优化。有时不是,但一般过程是让编译器进行优化,并且仅在您测量并证明您需要它的地方进行手动优化。如今,通过查看代码来判断哪些代码更快是非常不直观的(您可以阅读关于性能问题的所有问题以及一些根本原因的疯狂程度)。
  • 即内存:我从未见过 double 的备忘功能功能。想想在 0 和 1 之间有多少个 double 值。现在在降低精度的情况下,您可以利用它,但这很容易实现为针对该确切情况量身定制的自定义函数。仔细想想,我不太确定如何为 double 实现记忆化。实际上意味着任何东西并且不会在过程中失去准确性或性能的功能。
  • 通过并发执行增加更多分支的可能性:我不确定我是否会以并发方式实现三角函数,但我认为它完全有可能获得一些性能优势。但同样,编译器通常比你更擅长优化,所以让它完成它的工作,然后进行基准测试/分析,看看你是否真的需要做得更好。
  • 不会导致更好、干净、干燥的代码:我不确定你在这里到底是什么意思,或者什么是“干代码”。是的,有时您可能会因过多或过于复杂的 if/switch 块而陷入麻烦,但我看不到此处适用于 4 个象限的简单检查……这是一个非常基本且简单的案例。
  • 因此,对于任何平台,对于相同的 x 值,我都会得到相同的 y:我的猜测是为 double 的所有 53 位获取“精确”值。跨多个平台和系统是不可能的。如果您只有 52 位正确,结果是什么?这将是进行一些测试并看看你得到什么的好地方。

  • 我在 C 语言中使用三角函数已有 20 多年,99% 的时间我只使用提供的任何内置函数。在极少数情况下,我需要通过测试或基准测试证明的更高的性能(或准确性),只有这样我才真正针对该特定情况推出自己的自定义实现。我不会重写 <math.h> 的整个色域功能,希望有一天我可能需要它们。

    我建议尝试以尽可能多的方式对其中的一些函数进行编码,并进行一些准确性和基准测试。这将为您提供一些实用知识,并为您提供一些关于您是否真的需要重新实现这些功能的硬数据。至少这应该会给你一些实现这些类型功能的实践经验,并且有机会在这个过程中回答你的很多问题。

    关于c++ - 关于优化的数学函数、范围和区间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26444676/

    相关文章:

    c++ - 对 `JNI_CreateJavaVM' 窗口的 undefined reference

    c++ - 在二叉搜索树中插入新元素

    C++ : int*/float* to char*, 为什么使用 reinterpret_cast 得到不同的结果?

    c - 在微 Controller 上以二进制形式写入文件

    javascript - 如何用JS制作一个计算模块(数学)?

    c++ - 用于投影的 D3DX vector 数学函数?

    c++ - std :map and std:set 的线程安全

    c - 查找任何范围的序列

    c - 为什么puts()最后会打印一个额外的字符?

    java - 将 int 分成整数