我正在研究一种应该实时运行的流体动力学Navier-Stokes求解器.因此,表现很重要.
现在,我正在研究一些紧密的循环,每个循环占执行时间的很大一部分:没有单一的瓶颈.这些循环中的大多数都进行了一些浮点运算,但是它们之间存在很多分支.
浮点运算主要限于加法,减法,乘法,除法和比较.所有这些都是使用32位浮点数完成的.我的目标平台是x86,至少有SSE1指令.(我在汇编器输出中验证了编译器确实生成了SSE指令.)
我正在使用的大多数浮点值具有相当小的上限,而接近零值的精度并不是非常重要.所以我想到了这样的想法:也许转换到定点算法会加快速度?我知道唯一可以确定的方法是测量它,可能需要数天,所以我想事先了解成功的可能性.
在Doom的时代,定点已经风靡一时,但我不确定它在2010年的位置.考虑到现在有多少芯片被用于浮点性能,是否有可能定点运算仍然存在给我一个显着的速度提升?有没有人有任何可能适用于我的情况的实际经验?
我有一个连接到主处理器的协处理器.某些浮点计算需要在协处理器中完成,但它不支持硬件浮点指令,并且仿真速度太慢.
现在,一种方法是让主处理器缩放浮点值,以便它们可以表示为整数,将它们发送给执行某些计算的协处理器,并在返回时缩减这些值.然而,这在大多数情况下都不会起作用,因为数字最终会变得太大或太小而不能超出这些整数的范围.所以我的问题是,正确做到这一点的最快方法是什么.
我试图用C++实现一个定点类,但我遇到性能问题.我已经将问题简化为浮点类型的简单包装,它仍然很慢.我的问题是 - 为什么编译器无法完全优化它?
'float'版本比'Float'快50%.为什么?!
(我使用Visual C++ 2008,测试了所有可能的编译器选项,当然是Release配置).
请参阅以下代码:
#include <cstdio>
#include <cstdlib>
#include "Clock.h" // just for measuring time
#define real Float // Option 1
//#define real float // Option 2
struct Float
{
private:
float value;
public:
Float(float value) : value(value) {}
operator float() { return value; }
Float& operator=(const Float& rhs)
{
value = rhs.value;
return *this;
}
Float operator+ (const Float& rhs) const
{
return Float( value + rhs.value );
}
Float operator- (const Float& rhs) const …Run Code Online (Sandbox Code Playgroud) 我正在使用Dobb博士的文章" 使用定点运算优化数学密集型应用 "中描述的Anthony Williams的定点库,使用Rhumb Line方法计算两个地理点之间的距离.
当点之间的距离很大(大于几公里)时,这种方法运行良好,但在较小距离处则非常差.最坏的情况是当两个点相等或接近相等时,结果是194米的距离,而我需要距离> = 1米时至少1米的精度.
通过与双精度浮点实现的比较,我将问题定位到fixed::sqrt()函数,该函数在小值时表现不佳:
x std::sqrt(x) fixed::sqrt(x) error
----------------------------------------------------
0 0 3.05176e-005 3.05176e-005
1e-005 0.00316228 0.00316334 1.06005e-006
2e-005 0.00447214 0.00447226 1.19752e-007
3e-005 0.00547723 0.0054779 6.72248e-007
4e-005 0.00632456 0.00632477 2.12746e-007
5e-005 0.00707107 0.0070715 4.27244e-007
6e-005 0.00774597 0.0077467 7.2978e-007
7e-005 0.0083666 0.00836658 1.54875e-008
8e-005 0.00894427 0.00894427 1.085e-009
Run Code Online (Sandbox Code Playgroud)
fixed::sqrt(0)通过将其视为一种特殊情况来校正结果是微不足道的,但是这不能解决小的非零距离问题,其中误差从194米开始并且随着距离的增加趋于零.我可能至少需要将精度提高到零的顺序.
该fixed::sqrt()algorithim简要上面链接的文章第4页的解释,但我在努力遵循它更不用说确定它是否能够改善它.该功能的代码如下:
fixed fixed::sqrt() const
{
unsigned const max_shift=62;
uint64_t a_squared=1LL<<max_shift;
unsigned b_shift=(max_shift+fixed_resolution_shift)/2;
uint64_t a=1LL<<b_shift;
uint64_t x=m_nVal;
while(b_shift && a_squared>x)
{
a>>=1;
a_squared>>=2; …Run Code Online (Sandbox Code Playgroud) 这是(AFAIK)这个一般主题中的一个具体问题.
情况如下:
我有一个基于32位RISC微控制器(NEC V810的变体)的嵌入式系统(视频游戏控制台).我想写一个定点数学库.我读过这篇文章,但随附的源代码是用386汇编编写的,所以它既不能直接使用也不能轻易修改.
V810有内置的整数乘法/除法,但我想使用上面文章中提到的18.14格式.这需要将64位int除以32位int,而V810仅执行(有符号或无符号)32位/ 32位除法(产生32位商和32位余数).
所以,我的问题是:如何使用32位/ 32位模拟64位/ 32位除法(以允许红移的预移位)?或者,从另一种方式来看问题,使用标准的32位算术/逻辑运算将18.14定点除以另一种定义的最佳方法是什么?("最好"意味着最快,最小或两者兼而有之).
代数,(V810)汇编和伪代码都很好.我将从C调用代码.
提前致谢!
编辑:不知怎的,我错过了这个问题 ...但是,它仍然需要一些修改才能超级高效(它必须比v810提供的浮点div快,尽管它可能已经......),因此,我可以随意为我工作,以换取声望点;)(当然,我的图书馆文档中也有用).
值得庆幸的是,complex类型修饰符被引入C99标准.我不明白为什么决定省略对定点运算的支持(特别是支持分数类型,如1.15 {signed}或0.32 {unsigned}),这些类型对于DSP编程是如此重要?
GCC是否通过扩展支持这些?
我遇到过这个函数:
static inline INT32 MPY48SR(INT16 o16, INT32 o32)
{
UINT32 Temp0;
INT32 Temp1;
// A1. get the lower 16 bits of the 32-bit param
// A2. multiply them with the 16-bit param
// A3. add 16384 (TODO: why?)
// A4. bitshift to the right by 15 (TODO: why 15?)
Temp0 = (((UINT16)o32 * o16) + 0x4000) >> 15;
// B1. Get the higher 16 bits of the 32-bit param
// B2. Multiply them with the 16-bit param
Temp1 = (INT16)(o32 …Run Code Online (Sandbox Code Playgroud) 我正在寻找C或D的现有实现,或者实现具有浮点语义的实现,有符号和/或无符号整数类型的建议.
也就是说,这表现为浮点类型整型运算做什么时候:溢出产生无穷大(-infinity的签署下溢),而不是缠绕或具有不确定的行为,不确定的操作产生的NaN等
本质上是一个浮点版本,其中可呈现数字的分布均匀地落在数字线上,而不是在0附近聚合.
此外,所有操作都应该是确定性的 ; 任何给定的二进制补码32位架构应该为相同的计算产生完全相同的结果,无论其实现如何(而浮点可能,并且通常会产生稍微不同的结果).
最后,性能是一个问题,让我担心潜在的"bignum"(任意精度)解决方案.
另请参见:定点和饱和算术.
我正在用C++编写一个小型RTS引擎,并希望使用锁步同步.
由于浮点确定性是我甚至无法实现的,我必须使用定点数学.
确定性地(在不同的编译器和cpus上)是如何定义无符号整数的典型操作的?
我对分工特别感兴趣,因为这会导致四舍五入.
我有以下方法以固定点19.13格式乘以两个32位数
.但我认为这种方法存在问题:
1.5f向上舍入到2.0f,而-1.5f向上舍入到-1.0f.
在我看来-1.5应该向下舍入到-2.0f.
首先,当前的舍入是否有意义,如果没有,我怎样才能将其更改为更一致?
static OPJ_INT32 opj_int_fix_mul(OPJ_INT32 a, OPJ_INT32 b) {
OPJ_INT64 temp = (OPJ_INT64) a * (OPJ_INT64) b ;
temp += 4096;
assert((temp >> 13) <= (OPJ_INT64)0x7FFFFFFF);
assert((temp >> 13) >= (-(OPJ_INT64)0x7FFFFFFF - (OPJ_INT64)1));
return (OPJ_INT32) (temp >> 13);
}
Run Code Online (Sandbox Code Playgroud) fixed-point ×10
c++ ×4
c ×3
embedded ×2
performance ×2
assembly ×1
c99 ×1
d ×1
gcc ×1
int ×1
math ×1
optimization ×1
sqrt ×1
square-root ×1
x86 ×1