Carmack的快速开平方根倒数算法

基本原理

需求y=1x

log(ab×ac)=bloga+cloga=(b+c)loga

32位浮点表示法:二进制的科学计数法
符号位1+阶码8(有符号的反码表示幂指数)+小数位23(二进制小数首位必为1,默认,只需表示小数位即可)

../all images/快速开平方根倒数算法-20240511163945890.webp

字符串形式:S0E1E2...E7E8M9M10...M30M31

正数符号位S0忽略,并引入两个常量B=127,L=223,关联到指数E和小数M

故:
x=argI(E,M)=(1+L/M)×2EB

对x取对数:
log2(x)=log2[(1+ML)×2EB]

泰勒近似:

log2(1+m)=m+α,m[0,1), α为误差

log2(x)=log2[(1+ML)×2EB]=(E+ML)×LL+αB

(E+ML)×L正是32bits 二进制数decoding为整数

../all images/快速开平方根倒数算法-20240511171551171.webp

I(y)=R12I(x)

y=argI(Ey,My)=(1+MyL)2EyB

α=Error(x)=log2(1+x)x,x[0,1)

源代码作者采取α=0.0450465

../all images/快速开平方根倒数算法-20240511172133421.webp

C代码实现

float Q_rsqrt( float number )
{
	long i;
	float x2, y;
	const float threehalfs = 1.5F;

	x2 = number * 0.5F;
	y  = number;
	i  = * ( long * ) &y;                       // evil floating point bit level hacking
	i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
	y  = * ( float * ) &i;
	y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//	y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

	return y;
}

python实现

import struct
import math
  
def fast_inverse_square_root(number):
    threehalfs = 1.5
    x2 = number * 0.5
    y = number
    i = struct.unpack('i', struct.pack('f', y))[0]
    i = 0x5f3759df - (i >> 1)
    y = struct.unpack('f', struct.pack('i', i))[0]
    y = y * (threehalfs - (x2 * y * y))
    y  = y * ( threehalfs - ( x2 * y * y ) );   # 2nd iteration, this can be removed
    return y

# 测试
number = 101.0
inverse_sqrt = fast_inverse_square_root(number)
error = inverse_sqrt / (1/math.sqrt(number))
print("Fast Inverse Square Root of", number, "is:", inverse_sqrt, "error", error)

在这段代码中,struct.unpack('i', struct.pack('f', y))[0]这行代码涉及到了struct模块的使用,主要是对浮点数和整数进行打包和解析操作。让我解释一下各个参数的含义:

  1. struct.pack('f', y)

    • struct.pack(format, value)函数用于将值打包为指定格式的字节对象。
    • 'f'是格式化字符串,代表将值打包为浮点数。
    • y是要打包的值,即输入的浮点数。
  2. struct.unpack('i', ...)

    • struct.unpack(format, data)函数用于从字节对象中解析出值。
    • 'i'是格式化字符串,代表解析的值为整数。
    • ...是前面打包得到的字节对象,即浮点数y打包后的字节对象。
  3. struct.unpack('i', struct.pack('f', y))[0]

    • 这个表达式的含义是先将浮点数y打包为字节对象,然后再从字节对象中解析出整数值。
    • [0]表示取解析结果中的第一个值,因为struct.unpack返回的是一个元组。

综合起来,这行代码的作用是将浮点数y转换为字节对象(即二进制表示),然后再从字节对象中解析出整数值。这个操作是算法中的一个关键步骤,用于对输入的浮点数进行位操作和处理。

作者:invo

出处:https://www.cnblogs.com/invo/p/18230258

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Invo1  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示