D3D修改浮点数精度

前几天策划要求给任务系统加上日常任务的功能,这个需求很简单:象 wow 一样,日常任务在每天某个时候定时刷新。在思考添加这个功能时,很直接想到的方案是服务器取出 3 个时间:任务上次完成时间( pre ),当前时间( now )和当天刷新时间( refresh ),然后经过一些较复杂的逻辑完成(此处省略 xx 字)。由于该方案需要涉及一些时间操作,而在 lua c++ 里面做日期时间的操作又是比较麻烦的一件事。水古给出了一个解法,很好的解决了这个问题:首先用当前时间(比如现在是 18:00 )减去当天刷新时间(比如 wow 的日常每天 15:00 刷新),这样就把时间对齐到前一天的 0 点,然后分别用当前时间和上次完成时间除以一天的秒数( 24*60*60 ),就分别得到了当前时间和上次完成时间的天数,如果上次完成时间的天数小于当前时间的天数,则日常任务刷新。 lua 代码大致如下:

local now = os.time()

local pre = task.completed_time

local refresh = (15-8)*(60*60)   -- 8 是因为 os.time() 得到的是 UTC 时间,而北京时间是 UTC+8

local pre_days = (pre-refresh)/(24*60*60)

local now_days = (now-refresh)/(24*60*60)

if(now_days > pre_days) then

       -- 刷新任务

end

很简洁,整个算法只需要一个时间函数—— os.time()

 

本以为这个功能就这样完成了,但经过反复测试,悲剧发生了:服务器的时间正确,客户端却有 1 分钟左右的偏差。同样的库,同样的脚本,却得到不同的时间。掘地三尺后发现在客户端中 lua 中的双精度浮点数经过加减运算后变成了单精度浮点数,由于精度问题导致产生一定的时间偏差——和谐的阳光照在杯具上,每一个杯具都笑开颜。

首先想到的还是 lua 库的问题,毕竟是在 lua 脚本里面精度变了,但我直接在 c++ 里面写了一个简单的测试,发现精度也改变了。再次和几个朋友讨论这个问题,水古提到: DX 会改变浮点精度,确实,我记忆中好像在哪看到过,搜索 D3D sdk ,在 CreateDevice 中发现 D3DCREATE 有这么一个选项

D3DCREATE_FPU_PRESERVE

Set the precision for Direct3D floating-point calculations to the precision used by the calling thread. If you do not specify this flag, Direct3D defaults to single-precision round-to-nearest mode for two reasons:

  • Double-precision mode will reduce Direct3D performance.
  • Portions of Direct3D assume floating-point unit exceptions are masked; unmasking these exceptions may result in undefined behavior.

很明显了, d3d 在未指定该参数的时候会把 FPU 设置为单精度模式,其原因是因为处理单精度数据比双精度具备更好的性能。由于 D3D 默认修改了 FPU ,影响到了 lua 的精度( lua 里面 number 只有 double ),造成了一定时间的误差。

至于性能问题,我是这样想的,以单个浮点运算来看,现代 cpu double float 的运算效率非常接近了,更多的效率考虑可能是 cpu 高速缓存的命中和内存带宽的暂用吧,毕竟 double float 多一倍的数据量,而在 3D 环境中浮点运算大量存在。

 

最后说一下,该问题只是一个中间过程,最后把客户端时间修改成服务器的时间,在客户端就不用很精确的时间控制,所以这里暂时无需修改客户端代码,客户端仍然以默认的 24 FPU 精度模式运行,如何兼顾性能和精度,也就没去深究了。

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值