前话
前些时间考虑了下VS要不要顺便也讲下Linux的开发。最后还是决定算了:1.现在主流开发Linux的团队,比较排斥使用Windows来对Linux进行开发,虽然他们自己也承认VS开发很方便;2.Linux在VS和C++工程上和Android的基本没啥区别,唯一需要注意的要在VS的配置里面加上远程调试目标也就是Linux的IP和用户名之类的,具体参考微软官方文档:https://docs.microsoft.com/en-us/cpp/linux/connect-to-your-remote-linux-computer?view=vs-2019。总之VS可以远程调试,部署Linux服务器,还有像RaspberryPi这样的Linux设备,很方便。最后还是写了:VS2019 C++的跨平台开发——Linux开发
正题
最近在对神经网络进行CUDA并行计算的时候碰到了两次计算结果有偏差的情况:1. CUDA10.1在Debug和Release下计算出的结果并不一样;2. 通过CUDA使用多线程对数组二分求和的结果和单线程计算结果不一样。
这两种如标题写的那样都是假的误差,更像是一种差异,由于float 32bits的数据结构所限定的有效数据位数带来的显示差异。这两种不同的显示结果无法区分哪种更优。
第一种,具体来说是由于Release配置打开了-fmad造成的。fmad是一种基于硬件的加速技术,这里需要提到的一点就是数字电路里面的逻辑电路和组合电路。fmad的意思是将浮点小数的乘法和加法合并在一起,即通常情况下是a*b+c=d。那么需要先进行乘法计算,把结果按照浮点有效位数保存后再根据保存结果进行一次加法计算。这个操作在硬件级别上就是两个时钟完成的操作,两层时序逻辑。而fmad是把这两个操作转换成了一个时钟的组合逻辑电路,这个不单是时间上的减少,而且还减少了一次有效位数的保存操作。这里把计算结果按照有效位数保存的操作叫做Rounding。正是少了的这次Rounding导致计算结果的差异。这里先不解释怎么导致的,因为第二种也是由于这个导致的。
fmad的Wiki百科: