C# 中有一些关于定点数学的好资源吗?
我见过这样的事情(http://2ddev.72dpiarmy.com/viewtopic.php ?id=156)和这个(进行定点数学的最佳方法是什么?),以及一些关于小数是真正的定点还是实际上的浮点的讨论(更新:响应者已经确认它绝对是浮点) ,但我还没有看到一个可靠的 C# 库来计算余弦和正弦之类的东西。
我的需求很简单——我需要基本运算符,加上余弦、正弦、arctan2、π,等等。我想就是这样。 也许开方。 我正在编写一个二维 RTS 游戏,我大部分时间都在工作,但是随着时间的推移(10-30 分钟)在多台机器上使用浮点数学(双精度)时的单位移动具有非常小的不准确性,从而导致不同步。 目前仅介于 32 位操作系统和 64 位操作系统之间。 所有 32 位机器似乎都保持同步,没有任何问题,这让我认为这是一个浮点问题。
我从一开始就意识到这是一个可能的问题,因此尽可能限制了我对非整数位置数学的使用,但为了以不同的速度平滑对角线移动,我正在以弧度计算点之间的角度,然后使用 sin 和 cos 获取运动的 x 和 y 分量。 这是主要问题。 我还在对线段相交、线圆相交、圆矩形相交等进行一些计算,这些计算也可能需要从浮点移动到定点以避免跨机器问题。
如果 Java 或 Visual Basic 或其他类似语言有开源的东西,我可能可以转换代码供我使用。 对我来说,最重要的是准确性,尽管我希望与当前性能相比速度损失尽可能小。 这整个定点数学的东西对我来说是非常新的,而且我很惊讶 Google 上关于它的实用信息如此之少——大多数东西似乎要么是理论,要么是密集的 C++ 头文件。
非常感谢您能做的任何事情来为我指明正确的方向; 如果我能做到这一点,我计划将我组装的数学函数开源,以便为其他 C# 程序员提供资源。
我绝对可以让余弦/正弦查找表满足我的目的,但我认为这不适用于 arctan2,因为我需要生成一个包含大约 64,000x64,000 个条目的表(哎呀)。 如果您知道任何关于计算 arctan2 之类的有效方法的编程解释,那就太棒了。 我的数学背景还可以,但是高级公式和传统的数学符号对我来说很难翻译成代码。
Are there some good resources for fixed point math in C#?
I've seen things like this (http://2ddev.72dpiarmy.com/viewtopic.php?id=156) and this (What's the best way to do fixed-point math?), and a number of discussions about whether decimal is really fixed point or actually floating point (update: responders have confirmed that it's definitely floating point), but I haven't seen a solid C# library for things like calculating cosine and sine.
My needs are simple -- I need the basic operators, plus cosine, sine, arctan2, π, etc. I think that's about it. Maybe sqrt. I'm programming a two-dimensional RTS game, which I have largely working, but the unit movement when using floating-point math (doubles) has very small inaccuracies over time (10-30 minutes) across multiple machines, leading to desyncs. This is presently only between a 32-bit OS and a 64-bit OS. All the 32-bit machines seem to stay in sync without issue, which is what makes me think this is a floating point issue.
I was aware from this as a possible issue from the outset, and so have limited my use of non-integer position math as much as possible, but for smooth diagonal movement at varying speeds I'm calculating the angle between points in radians, then getting the x and y components of movement with sin and cos. That's the main issue. I'm also doing some calculations for line segment intersections, line-circle intersections, circle-rect intersections, etc, that also probably need to move from floating-point to fixed-point to avoid cross-machine issues.
If there's something open source in Java or Visual Basic or another comparable language, I could probably convert the code for my uses. The main priority for me is accuracy, although I'd like as little speed loss over present performance as possible. This whole fixed point math thing is very new to me, and I'm surprised by how little practical information on it there is on Google -- most stuff seems to be either theory or dense C++ header files.
Anything you could do to point me in the right direction is much appreciated; if I can get this working, I plan to open-source the math functions I put together so that there will be a resource for other C# programmers out there.
I could definitely make a cosine/sine lookup table work for my purposes, but I don't think that would work for arctan2, since I'd need to generate a table with about 64,000x64,000 entries (yikes). If you know any programmatic explanations of efficient ways to calculate things like arctan2, that would be awesome. My math background is all right, but the advanced formulas and traditional math notation are very difficult for me to translate into code.
发布评论
评论(6)
好的,这是我根据原始问题中的链接提出的定点结构,但还包括对其如何处理除法和乘法的一些修复,并添加了模块、比较、移位等的逻辑:
根据 ShuggyCoUk 的评论,我发现这是在 Q12格式。 对于我的目的来说,这相当精确。 当然,除了错误修复之外,在我提出问题之前我已经有了这个基本格式。 我正在寻找使用这样的结构在 C# 中计算 Sqrt、Atan2、Sin 和 Cos 的方法。 据我所知,C# 中没有任何其他东西可以处理这个问题,但在 Java 中我设法找到了 MathFP 库,作者:Onno Hommes。 这是一个自由源软件许可证,因此我将他的一些函数转换为我在 C# 中的用途(我认为修复了 atan2)。 享受:
Hommes 博士的 MathFP 库中还有许多其他函数,但它们超出了我的需要,因此我没有花时间将它们转换为 C#(由于他我使用的是 long,而我使用的是 FInt 结构,这使得转换规则很难立即看到)。
此处编码的这些函数的准确性足以满足我的目的,但如果您需要更多,您可以增加 FInt 上的 SHIFT AMOUNT。 请注意,如果您这样做,Dr. Hommes 函数的常数将需要除以 4096,然后乘以新的 SHIFT AMOUNT 所需的值。 如果您这样做并且不小心,可能会遇到一些错误,因此请务必对内置数学函数进行检查,以确保您的结果不会因错误调整常量而推迟。
到目前为止,这个 FInt 逻辑看起来与等效的内置 .NET 函数一样快,甚至可能更快一些。 这显然会因机器而异,因为浮点协处理器会确定这一点,所以我没有运行特定的基准测试。 但它们现在已集成到我的游戏中,并且与以前相比,我发现处理器利用率略有下降(这是在 Q6600 四核——平均使用量下降约 1%)。
Ok, here's what I've come up with for a fixed-point struct, based on the link in my original question but also including some fixes to how it was handling division and multiplication, and added logic for modules, comparisons, shifts, etc:
Based on the comments from ShuggyCoUk, I see that this is in Q12 format. That's reasonably precise for my purposes. Of course, aside from the bugfixes, I already had this basic format before I asked my question. What I was looking for were ways to calculate Sqrt, Atan2, Sin, and Cos in C# using a structure like this. There aren't any other things that I know of in C# that will handle this, but in Java I managed to find the MathFP library by Onno Hommes. It's a liberal source software license, so I've converted some of his functions to my purposes in C# (with a fix to atan2, I think). Enjoy:
There are a number of other functions in Dr. Hommes' MathFP library, but they were beyond what I needed, and so I have not taken the time to translate them to C# (that process was made extra difficult by the fact that he was using a long, and I am using the FInt struct, which makes the conversion rules are a bit challenging to see immediately).
The accuracy of these functions as they are coded here is more than enough for my purposes, but if you need more you can increase the SHIFT AMOUNT on FInt. Just be aware that if you do so, the constants on Dr. Hommes' functions will then need to be divided by 4096 and then multiplied by whatever your new SHIFT AMOUNT requires. You're likely to run into some bugs if you do that and aren't careful, so be sure to run checks against the built-in Math functions to make sure that your results aren't being put off by incorrectly adjusting a constant.
So far, this FInt logic seems as fast, if not perhaps a bit faster, than the equivalent built in .NET functions. That would obviously vary by machine, since the floating point coprocessor would determine that, so I have not run specific benchmarks. But they are integrated into my game now, and I've seen a slight decrease in processor utilization compared to before (this is on a Q6600 quad core -- about a 1% drop in usage on average).
我已经在 C# 中实现了定点 Q31.32 类型。 它执行所有基本算术、sqrt、sin、cos、tan,并且很好地涵盖了单元测试。 你可以在这里找到它,有趣的类型是Fix64。
请注意,该库还包括 Fix32、Fix16 和 Fix8 类型,但这些主要用于实验,并不完整且没有错误。
I've implemented a fixed-point Q31.32 type in C#. It performs all basic arithmetic, sqrt, sin, cos, tan, and is well covered by unit tests. You can find it here, and the interesting type is Fix64.
Note that the library also includes Fix32, Fix16 and Fix8 types, but those were mainly for experimenting and are not as complete and bug-free.
使用 64 位整数,例如 1/1000 比例。 可以正常加减。 当您需要乘法时,然后乘以整数,然后除以1000。当您需要sqrt,sin,cos等,然后转换为long double,除以1000,sqrt,乘以1000,转换为整数。 那么机器之间的差异就不重要了。
您可以使用其他比例进行更快的除法,例如 1024 为
x/1024 == x >>> 10.
.Use 64bit integers in for example 1/1000 scale. You can add and subtract normally. When you need to multiply then multiply integers and then divide by 1000. When you need to sqrt, sin, cos etc. then convert to long double, divide by 1000, sqrt, multiply by 1000, convert to integer. The differences between machines should not matter then.
You can use another scale for faster divides, for example 1024 as
x/1024 == x >> 10
.XrossOne Mobile GDI+ 是一个在 C# 中实现定点数学的项目。
XrossOne Mobile GDI+ is a project that implements fixed point math in C#.
我创建了一个类似的定点结构。 使用 new() 会降低性能,因为即使您使用的是结构体,它也会将数据放入堆中。 请参阅 Google(.NET 中的 C# heap(ing) 与 stack(ing):第 I 部分)。 使用结构体的真正威力是能够不使用 new 并按值传递到堆栈。 我下面的示例在堆栈上执行以下操作。
[结果 int ] 在堆栈上
[a int ] 在堆栈上
[b int ] 在堆栈上
[*] 运算符在堆栈上
值结果。 没有堆分配成本。
I created a similar fixed-point struct. You get a performance hit using new(), because it puts data onto the heap even though you are using a struct. See Google (C# heap(ing) vs stack(ing) in .NET: Part I). The true power of using a struct is the ability to not use new and pass by value to the stack. My example below does the following on the stack.
[result int ] on the stack
[a int ] on the stack
[b int ] on the stack
[* ] operator on the stack
value result returned. No heap allocated costs.
除了缩放整数之外,还有一些任意精度的数值库,通常包含“BigRational”类型,而定点只是十分母的固定幂。
As well as scaled integers, there are a few arbitrary precision numeric libraries which usually include a "BigRational" type, and fixed point is just a fixed power of ten denominator.