C# 需要为性能使用浮点,但需要双精度计算

C# 需要为性能使用浮点,但需要双精度计算,c#,optimization,performance,floating-point,C#,Optimization,Performance,Floating Point,MonoGame是微软XNA的开源版本。它是构建跨平台游戏的框架 它有许多数学类型,如向量和四元数 我对他们使用双人和浮动的方式有点困惑 到目前为止,我收集了以下信息: 浮动可能比双倍更有效 双精度比浮点精度高 以下是一种让我困惑的方法: /// <summary> /// Transforms a single Vector2, or the vector normal (x, y, 0, 0), by a specified Quaternion rotation. ///

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;
}
//
///通过指定的四元数旋转变换单个向量2或向量法线(x、y、0、0)。
/// 
///要旋转的向量。要应用的四元数旋转。
公共静态矢量2变换(矢量2值,四元数旋转)
{
float num1=旋转.X+旋转.X;
float num2=旋转.Y+旋转.Y;
float num3=旋转.Z+旋转.Z;
浮动num4=旋转。W*num3;
浮点num5=旋转.X*num1;
浮动num6=旋转.X*num2;
浮动num7=旋转。Y*num2;
浮动num8=旋转。Z*num3;
float num9=(float)((double)value.X*(1.0-(double)num7-(double)num8)+(double)value.Y*((double)num6-(double)num4));
浮点num10=(浮点)((双精度)值.X*((双精度)num6+(双精度)num4)+(双精度)值.Y*(1.0-(双精度)num5-(双精度)num8));
向量2向量2;
向量2.X=num9;
向量2.Y=num10;
返回向量2;
}

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

这里的关键点是,一系列计算都是在
double
中进行的,而没有将中间结果四舍五入到
float
。考虑到
float
输入,这可能会导致最终的
float
结果更接近于无限精确算法产生的结果

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

将存储每个值的字节数减半可能会在性能上产生很大的差异。它有效地将每个缓存的大小和每个数据传输路径的带宽增加了一倍

浮动可能比双倍更有效

这曾经是真的。你必须回到几十年前,那时图形算法最初被设计出来,必须在硬件上运行,而硬件在加速浮点运算方面不是很好。要么是因为它根本没有,而且必须在软件中进行模拟,从而自动提高单精度。或者是因为它运行在专门构建的图形终端上,这种终端有一个定制的图形处理器,无法处理比单精度浮点更好的任何东西。直到16年前,第一款奔腾(Pentium)问世,FPU才被保证能在板上运行。对于程序员来说,奔腾的软件运行在一台有FPU的机器上,这需要几年的时间

当然,所有已知的图形算法都设计为使用单一精度。让它们重新编写为使用双精度需要极大的勇气。因为这将不可避免地引入错误,这样的算法不会像单精度算法那样运行。浮点数学不是精确的数学。只要结果不同就足以生成bug报告,单精度版本将被作为规范标准,因为这是每个人都在使用的。程序员除了推荐“不要使用它”之外,完全没有办法让用户满意


所以图形代码不使用它。

可能相关:。。。一句话:在大多数情况下并没有真正的性能差异。为什么你认为double比float慢?在大多数现代硬件中,这几乎是一样的。但在某些情况下,混合浮点数和倍点数会导致额外的循环在两个浮点数之间转换types@LưuVĩnhPhúc“最现代的硬件”是否包括所有主流ARM和x86衍生产品(所有主流机器人、iPhone、XBox 360/XBox One、PS4等)?我不知道。@nhgrif:对中间值使用更高的精度可以减少结果的误差。例如,(float)double_value*10000和(float)(double_value*10000)可能不同。使用double进行的行计算越多,精度越高。我明白,我的主要问题是为什么不在整个行中使用两个float(例如,内联num1..num8作为num9和num10的双表达式)? 我个人会对方法中的所有内容使用double,并且在返回结果之前只强制转换为float。为什么不这样做呢?我可能会按照你描述的方式来做,但使用double的决定可能是基于对特定计算的分析。这取决于典型的输入数字,而不仅仅是计算。如果你不想仅仅依靠他们的智慧,你可以收集大量的函数输入。使用当前代码、所有浮点、所有双精度和任何库类型,对每组输入执行计算,这些库类型允许您执行精确的加法、减法和乘法。各种浮点组合与无限精确计算的结果最接近的浮点有多近?不知道这有什么关系。编写自己的图形原语的程序员倾向于处理永远无法完成的项目。SIMD呢?它不是更有效地处理浮动吗?请参阅此答案中的评论:(C#将很快获得Microsoft的官方SIMD支持)。您是否意识到您忘记提及缓存和RAM访问速度?此外,大多数GPU进行单精度计算比双精度计算快得多。