【问题标题】:Need to use floats for performance yet want double-precision calculations需要使用浮点数来提高性能但需要双精度计算
【发布时间】:2014-06-29 11:48:04
【问题描述】:

MonoGame 是微软 XNA 的开源版本。它是一个构建跨平台游戏的框架。

它有许多数学类型,例如向量和四元数。

他们使用双打和浮点数的方式让我有点困惑。

到目前为止,我已经收集了以下信息:

  • 浮点数可能比双精度数更有效;
  • 双精度比浮点精度高。

这里有一种让我困惑的方法:

/// <summary>
/// Transforms a single Vector2, or the vector normal (x, y, 0, 0), by a specified Quaternion rotation.
/// </summary>
/// <param name="value">The vector to rotate.</param><param name="rotation">The Quaternion rotation to apply.</param>
public static Vector2 Transform(Vector2 value, Quaternion rotation)
{
  float num1 = rotation.X + rotation.X;
  float num2 = rotation.Y + rotation.Y;
  float num3 = rotation.Z + rotation.Z;
  float num4 = rotation.W * num3;
  float num5 = rotation.X * num1;
  float num6 = rotation.X * num2;
  float num7 = rotation.Y * num2;
  float num8 = rotation.Z * num3;
  float num9 = (float) ((double) value.X * (1.0 - (double) num7 - (double) num8) + (double) value.Y * ((double) num6 - (double) num4));
  float num10 = (float) ((double) value.X * ((double) num6 + (double) num4) + (double) value.Y * (1.0 - (double) num5 - (double) num8));
  Vector2 vector2;
  vector2.X = num9;
  vector2.Y = num10;
  return vector2;
}

为什么不在整个过程中使用双精度浮点数(例如,内联 num1..num8 作为 num9 和 num10 的双精度表达式)?

【问题讨论】:

  • 也许相关:stackoverflow.com/questions/158889/… ...底线:在大多数情况下,性能并没有真正的差异。
  • 为什么你认为双精度比浮点数慢?在大多数现代硬件中,它几乎是一样的。但在某些情况下,混合浮点数和双精度数会导致类型之间转换的额外循环
  • @LưuVĩnhPhúc “最现代的硬件”是否包括所有主流 ARM 和 x86 衍生产品(所有主流 Android、iPhone、XBox 360/Xbox One、PS4 等)?我不知道。
  • @nhgrif:对中间值使用更高的精度可以减少结果的误差。例如 (float)double_value * 10000 和 (float)(double_value * 10000) 可能不同。
  • 使用双精度完成的计算越多,精度就越高。

标签: c# optimization performance floating-point


【解决方案1】:

这里的重点是,一系列的计算都是在double中进行的,没有将中间结果四舍五入到float。在给定float 输入的情况下,这可能会导致最终的float 结果更接近无限精确算术得出的结果。

32 位和 64 位浮点运算的性能差异很小。存储32位和存储64位有很大的空间差异。

将存储每个值的字节数减半可能会对性能产生很大影响。它有效地使每个缓存的大小和每个数据传输路径的带宽加倍。

【讨论】:

  • 我明白,我的主要问题是为什么不使用浮点数的双精度 throughout(例如内联 num1..num8 作为 num9 和 num10 的双精度表达式)?我个人会对方法内的所有内容使用双精度,并且只在返回结果之前强制转换为浮点数。为什么不这样做呢?
  • 我可能会按照您描述的方式进行操作,但使用 double 的决定可能是基于对特定计算的分析。这取决于典型的输入数字,而不仅仅是计算。
  • 如果你不想仅仅依靠他们的智慧,你可以收集大量的函数输入。使用当前代码、所有浮点数、所有双精度数以及任何可让您进行完美精确加法、减法和乘法运算的库类型对每组输入进行计算。各种浮点组合与无限精确计算结果最接近的浮点数有多接近?
【解决方案2】:

浮点数可能比双精度数更有效

曾经是真的。你必须回到几十年前,大约在图形算法最初设计并且必须在不太擅长加速浮点数学的硬件上运行的时候。要么是因为它根本没有任何东西,而且必须在软件中进行仿真,从而使单精度自动更快。或者因为它运行在专门构建的图形终端上,这种终端具有自定义图形处理器,无法处理比单精度浮点数更好的东西。直到第一个 Pentium 才保证板载 FPU,对于一个程序员来说,要依靠他的软件运行在仅仅 16 年前的一台机器上运行 FPU。

当然,所有已知的图形算法都设计为使用单精度。让它们重写以使用双精度需要极大的勇气。因为这将不可避免地引入错误,所以这样的算法不会与单精度算法的行为方式相同。浮点数学不是精确的数学。结果不同的事实足以生成错误报告,单精度版本将被保留为规范标准,因为这是每个人都在使用的。除了建议“不要使用它”,程序员绝对不能做任何事情来让用户满意。

所以图形代码不使用它。

【讨论】:

  • 不知道它是如何相关的。编写自己的图形基元的程序员往往从事从未完成的项目。
  • SIMD 怎么样?它不是更有效地处理浮动吗?请在此答案中查看 cmets:stackoverflow.com/a/417591/486561(C# 将很快获得 Microsoft 的官方 SIMD 支持)。
  • 您是否意识到您忘记提及缓存和 RAM 访问速度?此外,大多数 GPU 执行单精度计算的速度比双精度计算快得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
  • 2017-06-26
  • 1970-01-01
相关资源
最近更新 更多