𝗛𝗲𝗿𝗲'𝘀 𝗛𝗼𝘄 𝗧𝗼 𝗔𝗽𝗽𝗿𝗼𝘅𝗶𝗺𝗮𝘁𝗲 𝗠𝗼𝗿𝗲 𝗘𝗳𝗳𝗶𝗰𝗶𝗲𝗻𝘁𝗹𝘆
我相信他所寻找的是一种更有效的近似1.0/x的方法,而不是近似的一些技术定义,即可以使用1作为非常不精确的答案。我也相信这满足了这一点。
#ifdef __cplusplus#包括<cstdint>#其他#包括<stdint.h>#结尾__内联_双__attribute_((常数))倒数(双x){活接头{双dbl;#如果定义__cplusplus标准::uint_least64_tull;#其他uint_least64_tull;#结尾}u;u.dbl=x;u.ull=(0xbfcdd6a18f6a6f52ULL-u.ul)>>1;//功率(x,-0.5)u.dbl*=u.dbl;//功率(pow(x,-0.5),2)=功率(x,-1)=1.0/x返回u.dbl;}__内联__float __attribute_((常量))倒数(float x){活接头{浮动单;#ifdef __cplusplus标准::uint_least32_t uint;#其他uint_least32_t单位;#结尾}u;美国单数=x;u.uint=(0xbe6eb3beU-u.uint)>>1;//功率(x,-0.5)u.single*=美国单身;//功率(pow(x,-0.5),2)=功率(x,-1)=1.0/x返回美国单身;}
嗯……我想如果CPU制造商知道在他们设计CPU时,只需一次乘法、减法和位移位就可以近似求倒数。。。。隐马尔可夫模型。。。。。。。。。
至于基准标记,硬件x2结合硬件减法指令的指令与现代计算机上的硬件1.0/x指令一样快(我的基准测试是在Intel i7上进行的,但我会假设其他处理器也有类似的结果)。然而,如果将此算法作为一条新的汇编指令实现到硬件中,那么速度的提高可能足以使此指令变得非常实用。
有关此方法的更多信息,此实现基于“快速”逆平方根算法.
正如Pharap引起我注意的那样,从联合中读取非活动属性是未定义的行为,因此我从他的有益评论中设计了两种可能的解决方案,以避免未定义行为。第一种解决方案看起来更像是绕过一种实际上并不比原始解决方案更好的语言语义的一种令人讨厌的技巧。
#ifdef __cplusplus#包括<cstdint>#其他#包括<stdint.h>#结尾__内联_双__attribute_((常数))倒数(双x){活接头{双dbl[2];#ifdef __cplusplus标准::uint_least64_tull[2];#其他uint_least64_tull[2];#结尾}u;u.dbl[0]=x;//dbl现在是活动属性,因此现在只能读取dblu.ull[1]=0//将ull设置为活动属性以便读取ull的技巧u.ull][0]=(0xbfcdd6a18f6a6f52ULL-u.ull[0])>>1;u.dbl[1]=0;//现在将dbl设置为活动属性,以便可以读取它u.dbl[0]*=u.dbl[0];返回u.dbl[0];}__内联__float __attribute_((常量))倒数(float x){活接头{浮子flt[2];#ifdef __cplusplus标准::uint_least32_tull[2];#其他uint_least32_tull[2];#结尾}u;u.flt[0]=x;//现在flt处于活动状态u.uint[1]=0;//将uint设置为活动的读写u.uint[0]=(0xbe6eb3beU-u.uint[0])>>1;u.flt[1]=0;//让外语教学活跃于阅读和写作u.flt[0]*=u.flt[0];返回u.flt[0];}
第二种可能的解决方案更受欢迎,因为它完全摆脱了工会。然而,如果编译器没有对该解决方案进行适当优化,那么该解决方案将慢得多。但是,从好的方面来看,下面的解决方案将完全不依赖于所提供的字节顺序:
- 字节的宽度是8位
- 这些字节是目标机器上最小的原子单位。
- 双精度数是8字节宽,浮点数是4字节宽。
#ifdef __cplusplus#包括<cstdint>#包括<cstring>#定义stdIntWithEightBits标准::uint8_t#定义stdIntSizeOfFloat标准::uint32_t#定义标准IntSizeOfDouble标准::uint64_t#其他#包括<stdint.h>#包括<string.h>#定义stdIntWithEightBits uint8_t#定义stdIntSizeOfFloat uint32_t#定义双uint64_t的stdIntSizeOf#结尾
__内联_双__attribute_((常数))倒数(双x){双字节IndexFloat=1.1212798184631136e-308//00 08 10 18 20 28 30 38位stdIntWithEightBits*byteIndexs=reinterpret_cast(字节索引浮点);stdIntWithEightBits*inputBytes=reinterpret_cast(&x);stdIntSizeOfDouble输入AsUll=((输入字节[0]<字节索引[0])|(输入字节[1]<<字节索引[1])|(输入字节[2]<<字节索引[2])|(inputBytes[3]<<字节索引[3])|(输入字节[4]<字节索引[4])|(输入字节[5]<字节索引[5])|(输入字节[6]<字节索引[6])|(输入字节[7]<字节索引[7]));inputAsUll=(0xbfcdd6a18f6a6f52ULL-输入AsUll)>>1;双输出双;const stdIntWithEightBits输出字节[]={inputAsUll>>字节索引[0],inputAsUll>>字节索引[1],inputAsUll>>字节索引[2],inputAsUll>>字节索引[3],inputAsUll>>字节索引[4],inputAsUll>>字节索引[5],inputAsUll>>字节索引[6],inputAsUll>>字节索引[7]};memcpy(&outputDouble,&output1Bytes,8);return outputDouble*outputDuuble;}
__内联__float __attribute_((常量))倒数(float x){浮点字节IndexFloat=7.40457e-40;//0x00 08 10 18位stdIntWithEightBits*byteIndexs=reinterpret_cast(字节索引浮点);stdIntWithEightBits*inputBytes=reinterpret_cast(&x);stdIntSizeOfFloat输入AsInt=((输入字节[0]<字节索引[0])|(输入字节[1]<<字节索引[1])|(输入字节[2]<<字节索引[2])|(inputBytes[3]<<字节索引[3]));inputAsInt=(0xbe6eb3beU-inputAsInt)>>1;浮点输出浮点;const stdIntWithEightBits输出字节[]={inputAsInt>>字节索引[0],inputAsInt>>字节索引[1],inputAsInt>>字节索引[2],inputAsInt>>字节索引[3]};memcpy(&outputFloat,&output1Bytes,4);返回outputFloat*outputFloat;}
免责声明:最后,请注意,我在C++方面是一个新手。因此,我热烈欢迎任何最佳实践、适当的格式或含意清晰的编辑,以提高所有阅读者的答案质量,并在今后的岁月里扩展我的C++知识。