看来我发现了错误。
这是 VFP11(ARMv6 协处理器)分值错误中的错误。非正规数 http://en.wikipedia.org/wiki/Denormal_number数量非常少。
我在通过转储实现 spring 的物理代码中得到了这个数字
force1 = (Center - P1) * k1 // force1 directed to center
force2 = - Velocity * k2 // force2 directed against velocity
Object->applyForce(force1)
Object->applyForce(force2)
当对象归档时,两种力量都变得非常小Center
我得到denormal
值在最后。
我可以重写字符串和转储,但我无法重写孔子弹物理或所有数学代码并预测非正规数的每个(甚至内部)出现。
链接器有修复代码选项--vfp11-denorm-fix
and --vfp-denorm-fix
http://sourceware.org/binutils/docs-2.19/ld/ARM.html http://sourceware.org/binutils/docs-2.19/ld/ARM.html
NDK 链接器有--vfp11-denorm-fix
此选项有帮助。代码看起来更可靠,但它并不能 100% 解决问题。
我现在看到的错误更少了。
但是如果我等待 sping 稳定对象,那么我最终会得到 denorm -> NaN
我必须等待更长的时间,但同样的问题也出现了。
如果您知道可以修复类似代码的解决方案--vfp11-denorm-fix
那我应该给你赏金吗?
我都尝试过--vfp11-denorm-fix=scalar
and --vfp11-denorm-fix=vector
刷新至零位
int x;
// compiles in ARM mode
asm(
"vmrs %[result],FPSCR \r\n"
"orr %[result],%[result],#16777216 \r\n"
"vmsr FPSCR,%[result]"
:[result] "=r" (x) : :
);
不知道为什么,但它需要LOCAL_ARM_MODE := arm
in Android.mk
May be -mfpu=vfp-d16
而不是仅仅vfp
是必须的。
手动清除非正规数
我有上面描述的弹簧代码。
我通过手动清除非正规数来改进它,而不使用具有以下功能的 FPU。
inline void fixDenorm(float & f){
union FloatInt32 {
unsigned int u32;
float f32;
};
FloatInt32 fi;
fi.f32 = f;
unsigned int exponent = (fi.u32 >> 23) & ((1 << 8) - 1);
if(exponent == 0)
f = 0.f;
}
原始代码在许多地方从一开始就在 15-90 秒内失败。
当前代码在 10 分钟的物理模拟后仅出现了一个可能与此错误相关的问题。
参考错误和修复http://sourceware.org/ml/binutils/2006-12/msg00196.html http://sourceware.org/ml/binutils/2006-12/msg00196.html
他们说GCC
仅使用标量代码并且--vfp11-denorm-fix=scalar
足够。
它添加了 1 个额外的命令来减慢速度。但即使--vfp11-denorm-fix=vector
添加 2 个额外命令是不够的。
问题并不容易重现。在频率较高的 800Mhz 手机上,我比在速度较慢的 600Mhz 手机上更常看到这种情况。修复可能是在市场上没有快速 CPU 的情况下完成的。
我们的项目中有很多文件,每个配置编译大约需要 10 分钟。
根据当前修复状态进行测试需要约 10 分钟才能在手机上玩游戏。 + 我们在灯下加热手机。热手机显示错误的速度更快。
我希望测试不同的配置并报告哪种修复最有效。但现在我们必须添加 hack 来消除最后一个可能与 denorms 有关的错误。
我希望找到解决这个问题的灵丹妙药,但只是-msoft-float
性能下降 10 倍或在 ARMv7 上运行应用程序即可实现。
当我替换了之前的fixDenorm
功能与新fixDenormE
在 spring/dumping 代码中并应用 ViewMatrix 的新函数我摆脱了最后一个错误。
inline void fixDenormE(float & f, float epsilon = 1e-8){
union Data32 {
unsigned int u32;
float f32;
};
Data32 d;
d.f32 = f;
unsigned int exponent = (d.u32 >> 23) & ((1 << 8) - 1);
if(exponent == 0)
f = 0.f;
if(fabsf(f) < epsilon){
f = 0.f;
}
}