C语言之美——平方根倒数快速计算

article/2025/9/4 7:16:42

C语言之美——平方根倒数快速计算

前言

由于特殊原因,陆陆续续接触陀螺仪很长一段时间,对于各种解析算法的运算速率有了切身体会,不断追求更快、更准。最近,发现了一份比较特殊的平方根倒数速算法,一下子来了兴趣,要知道,陀螺仪解析算法里,倒数可是很常见的啊。下面来看一看这一份优美的代码,足以体现C语言的独特美感。

源码

你看不懂就对了<( ̄ˇ ̄)/,不然谁听我下面的哔哔呢?

float rsqrt(float number)
{long i;                        //32-bit numberfloat x2, y;                   //32-bit decimal numberconst float threehalfs = 1.5F; //1.5(also 32-bit)x2 = number * 0.5F;y = number;i = *(long *)&y;           // evil floating point bit hacki = 0x5f3759df - (i >> 1); //what the fuck?y = *(float *)&i;y = y * (threehalfs - (x2 * y * y)); //1st iteration//y = y * (threehalfs - (x2 * y * y)); // 2st iteration,can be removereturn y;
}

IEEE754标准

定点数

定点数,自然是相对于浮点数而言的。
何为定点?何为浮点?

定点,通俗来说就是小数点位置是固定的。
官方一丢丢的解释(>▽<):

在定点数表达法中,其小数点固定地位于实数所有数字中间的某个位置。例如,货币的表达就可以采用这种表达方式,如 55.00 或者 00.55 可以用于表达具有 4 位精度,小数点后有两位的货币值。由于小数点位置固定,所以可以直接用 4 位数值来表达相应的数值。

但我们不难发现,定点数表达法的缺点就在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。因此,最终绝大多数现代的计算机系统都采纳了所谓的浮点数表达法。

浮点数

浮点,通俗来说就是小数点位置是浮动的。
官方一点的解释(o゜▽゜)o☆:

浮点数表达法采用了科学计数法来表达实数,即用一个有效数字。一个基数(Base)、一个指数(Exponent)以及一个表示正负的符号来表达实数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。

表示方法 (仅限于单精度浮点数)

在IEEE 754标准中浮点数由三部分组成:符号位(sign bit),有偏指数(biased exponent),小数(fraction)。浮点数分为两种,单精度浮点数(single precision)和双精度浮点数(double precision),它们两个所占的位数不同。

单精度浮点数(共32位):
1个符号位
8个指数位
23个小数位

先来看看下面的例子,简单阐述了浮点数的表示方法:

在简单知道了浮点数表示方法之后,一个有意思的事情又开始了:
我们知道了,浮点数的表示方法其实灵感来源于科学计数法,科学计数法表示的数如1.2×10²,数字的首位一定不为0,即不会出现0.2×10²的情况。于是,在二进制里相应的最高位一定也不会为0,只能为1。
研究754标准那帮人特牛,嗯~ o( ̄▽ ̄)o,直接把确定的1省去默认,23个小数位全为真·小数位(哈哈哈),简单来说,又省了一位确定的,将他分配给小数表示。

到现在,我们可以又下面的公式 (敲黑板(☄⊙ω⊙)☄)
( 1 + m 2 23 ) × 2 e − 127 \left ( {1+\frac {m} {{2}^{23}}} \right )\times {2}^{e-127} (1+223m)×2e127
其中m表示23位的小数部分,e表示8位的指数部分 由于指数有正负,所以减去127

下面我们跟着将浮点数公式取对数变换,最终得到:
l o g 2 ( 1 + m 2 23 ) + e − 127 {log}_{2}\left ( {1+\frac {m} {{2}^{23}}} \right )+e-127 log2(1+223m)+e127

然后咋办呢~ ( ̄▽ ̄) ~*?我们这样:
l o g 2 ( 1 + x ) ≈ x {log}_{2}\left ( {1+x} \right )\approx x log2(1+x)x
这一波神之操作,很多人会说底数应该为e才对,不过呢,你把2带进去会发现在两端图像重合,加一个修正系数就好了
即:

l o g 2 ( 1 + x ) ≈ x + u {log}_{2}\left ( {1+x} \right )\approx x+u log2(1+x)x+u
(u=0.430时,在0~1的区间内,误差最小)

于是公式又能化简为:

1 2 23 ( m + 2 23 × e ) + u − 127 \frac {1} {{2}^{23}}\left ( {m+{2}^{23}\times e} \right )+u-127 2231(m+223×e)+u127

了解这些后我们就可以做接下来的神奇操作了。

奇葩的位操作

哼哼( ̄ー ̄)ノ~~マ☆’.・.・:★,很显然,在754标准里,float类型是不适合位操作的,不过long类型绝对适合,为嘛呢?

如二进制数 1001.101,我们可以根据上面的表达式表达为: 1 × 2 3 + 0 × 2 2 + 0 × 2 1 + 1 × 2 0 + 1 × 2 − 1 + 0 × 2 − 2 + 1 × 2 − 3 1×2^3+0×2^2+0×2^1+1×2^0+1×2^-1+0×2^{-2}+1×2^{-3} 1×23+0×22+0×21+1×20+1×21+0×22+1×23,其规范浮点数表达为 1.001101 × 2 3 1.001101×2^3 1.001101×23
由上面的等式,我们可以得出:向左移动二进制小数点一位相当于这个数除以 2,而向右移动二进制小数点一位相当于这个数乘以 2。

所以知道了为毛long类型适合位操作了吧。

C语言的技巧

强制转换

不懂强制转换的同学叉出去

 i = (long)y;

将浮点数(单双精度)转换为整数时,将舍弃浮点数的小数部分, 只保留整数部分。

嗯,不知叫啥的方法

 i = *(long *)&y;

就只是改变了类型,内存里的数值没有改变
(简单来说,C语言:“你又骗我!这到底是不是float?”)

牛顿迭代法

详细操作自己去看看百度,爷懒了不想写<(ˉ^ˉ)>
致敬牛顿

解析源码

 i = *(long *)&y;           // evil floating point bit hack

很显然,这是进行类型转化

 i = 0x5f3759df - (i >> 1); //what the fuck?

what the fuck? 为啥有一个0x5f3759df,嘛呢?
我们看下面的操作:
先设 l = 1 y l=\frac {1} {\sqrt {y}} l=y 1
化简得 l o g ( l ) = − 1 2 l o g ( y ) log\left ( {l} \right )=-\frac {1} {2}log\left ( {y} \right ) log(l)=21log(y)
由于我们已推导 1 2 23 ( m + 2 23 × e ) + u − 127 \frac {1} {{2}^{23}}\left ( {m+{2}^{23}\times e} \right )+u-127 2231(m+223×e)+u127
代入化简得
( m l + 2 23 × e l ) = 3 2 × 2 23 ( 127 − u ) − 1 2 ( m y + 2 23 × e y ) \left ( {{m}_{l}+{2}^{23}\times {e}_{l}} \right )=\frac {3} {2}\times {2}^{23}\left ( {127-u} \right )-\frac {1} {2}\left ( {{m}_{y}+{2}^{23}\times {e}_{y}} \right ) (ml+223×el)=23×223(127u)21(my+223×ey)
其中 3 2 × 2 23 ( 127 − u ) = 0 x 5 f 3759 d f \frac {3} {2}\times {2}^{23}\left ( {127-u} \right )=0x5f3759df 23×223(127u)=0x5f3759df

y = *(float *)&i;

逆向操作,类型转化即可

 y = y * (threehalfs - (x2 * y * y)); //1st iteration

牛顿迭代, f ( y ) = 1 y 2 − x f\left ( {y} \right )=\frac {1} {{y}^{2}}-x f(y)=y21x,用它来推导即可

//y = y * (threehalfs - (x2 * y * y)); // 2st iteration,can be remove

迭代两次,精度更高,取决于你自己啰!!!

总结

喵的,强啊!!!
七夕节到了,向C语言献花,向牛顿献花,向约翰·卡马克(代码编写者)献花


http://chatgpt.dhexx.cn/article/dU3V4odI.shtml

相关文章

【C语言求素数(质数)的三种方法】

失踪人口回归&#xff0c;假期因为太懒&#xff0c;刚开学的这几天又真的忙&#xff0c;所以好长时间没有发文章了&#xff0c;马上我们要进行C语言考试了&#xff0c;我发现学的东西好多都不太懂&#xff0c;所以慢慢要在进行一次复习了&#xff1b;上周数据结构课上老师让写程…

平方根求和c语言编程,计算并输出3到100(包括3和100)之间所有素数之和的平方根。 C语言,求救...

满意答案 zh19951006 2014.07.02 采纳率&#xff1a;56% 等级&#xff1a;12 已帮助&#xff1a;6562人 //先求3到100间的所有素数,存在数组中; //求该数组的所有为素数的元素之和,然后开方求平方根 #include <stdio.h> #include <math.h> int sushu[98];//开辟…

word封面下划线怎么对齐(非常简单+彻底解决)

之前遇到这个问题&#xff0c;也在网上百度了很多次&#xff0c;有的说段落调整对齐方式为两端对齐&#xff0c;对称什么的&#xff0c;试了一下都不管用&#xff0c;也有的说是加一个表格&#xff0c;但是并没有解决根本问题&#xff0c;最后突然想起&#xff0c;有一次打印东…

【Office】Word空格无法添加下划线

缘由 在弄文档封面的时候&#xff0c;需要在项目名称后面加一条下划线 于是出现了这个情况&#xff1a; 1.在没有内容的一行&#xff0c;带下划线的空格直接不显示下划线了&#xff08;下图第一行&#xff09; 2.空格应用下划线格式&#xff0c;内容前面的是能显示的&#…

Word公式居中,公式编号右对齐

1. 选择开始-样式-新建样式。编辑名称为公式 2. 左下角选择格式-制表位 打开Word标尺&#xff0c;找到中间和最右边的位置。比如我这里是17和34&#xff0c;输入位置分别设置居中对齐和右对齐 3. 在样式中选择公式 4. 在公式右侧键入编号&#xff0c;然后将光标放在公式左侧&am…

php输入域无法对齐,下划线输入内容后怎么对齐

下划线输入内容后设置对齐的方法&#xff1a;首先打开Word&#xff1b;然后依次选择“菜单栏->插入->表格”&#xff1b;接着将内容分别输入表格中&#xff0c;并调整表格的列宽等格式&#xff1b;最后右键选择“边框和底纹”&#xff0c;并设置只保留底部边框和中间横线…

Word 里文字对齐的4种方法

转自&#xff1a;微点阅读 https://www.weidianyuedu.com 我们在用Word写论文、制作简历的时候&#xff0c;通常会遇到把word中某些特定文字对齐的情况。那么问题来了&#xff0c;你平时都是怎么对齐文字的&#xff1f;傻傻的用空格来对齐吗&#xff1f; 在字符数不等的情况下&…

Word 里文字对齐4种方法推荐

我们在用Word写论文、制作简历的时候&#xff0c;通常会遇到把word中某些特定文字对齐的情况。那么问题来了&#xff0c;你平时都是怎么对齐文字的&#xff1f;傻傻的用空格来对齐吗&#xff1f; 在字符数不等的情况下&#xff0c;加空格不仅麻烦而且不准确&#xff0c;下面传…

Windows系统中Word文档中文字后面的空格下的下划线不显示的解决办法

笔者最近在做课程设计&#xff0c;需要写Word文档&#xff0c;在写文档的时候遇到了一堆bug&#xff0c;现在课程设计肝完了&#xff0c;终于有时间梳理梳理这些bug然后发布出来做个备忘录。    第一个bug是Windows系统中Word文档中文字后面的空格下的下划线不显示&#xff0…

word里面怎样输入空白下划线

在编写文档时&#xff0c;有时需要留些空格下划线的位置&#xff0c;那怎么加入空白下划线呢&#xff1f;下面我用我常用的speedoffice来说明一下。 方法1&#xff1a;将输入法设置为英文状态&#xff0c;同时按下“Shift”键和“-”键即可可持续不断敲空白下划线。 方法2&…

Word空格自动加下划线

经常用到在文档签署页加下划线&#xff0c;老是忘记&#xff0c;记录下来&#xff0c;步骤如下&#xff1a; 文件——选项——高级——为尾部空格添加下划线&#xff08;选中&#xff09;——确定。

解决word空格后无法打出下划线

问题 即使点击了word开始菜单栏中的下划线选项&#xff0c;也打不出下划线 解决办法 找到word的&#xff1a; 1-文件 ——>2-选项——>3-高级——>4-以下对象的布局选项——>5-为尾部空格添加下划线

Word中下划线自动换行版式不…

原文地址&#xff1a;Word中下划线自动换行版式不变形 作者&#xff1a;破烂小笔 Word中编辑合同、协议、考卷、介绍信一类文档时&#xff0c;往往需要在文本中留出一定的空格并设置下划线以便填写。当这些空格出现在上一行末和下一行开头时&#xff0c;如果空格后有字符则会造…

怎么让WORD中多行(常带下划线)头和尾都完全对齐

『如何』让WORD中多行&#xff08;常带下划线&#xff09;头和尾都完全对齐 “为啥Word多行下划线后面总是长短不一&#xff0c;无论怎么调不是多了就是少了&#xff1f;怎样才能完美对齐呢&#xff1f;” 通过本文你可以 如何对齐Word中的多行文本&#xff0c;达到可以容忍的…

解决 Word 中空格下划线居中后下划线不显示的问题

1、Word 左上角“文件”--“选项”--“高级”--“以下对象的布局选项”--“为尾部空格添加下划线” 2、选中要居中的部分&#xff0c;右键“段落”--“缩进和间距”--常规 对齐方式“居中”&#xff0c;一定要在这里选才可以 “中文版式”--选中“允许西文在单词中间换行” 效果…

word封面下划线对齐

word封面下划线对齐 如图所示&#xff0c;班级下划线与前面三条下划线没有对齐 于是你尝试删除 &#xff0c;可是删除一下却删多了。 不要慌张&#xff0c;按我说的办。全删掉&#xff0c;重来。 首先插入一个2*4的表格 输入内容 对文本稍作调整 全选表格&#xff0c;右击选择…

word论文封面下划线对齐

效果如下图&#xff0c;话不多说操作。 一、打开 word 的然后插入一个 4 行 2 列的表格&#xff08;按照自己需要的来设置&#xff09; 二、在表格的 第 1 列中输入你需要的文字&#xff0c;设置字体为黑体三号后右对齐&#xff08;这里是我设置的你可以按照自己的来&#xff0…

如何对齐word封面的下划线(word标尺如何使用)

写过论文的同学都应该遇到过一个问题&#xff0c;就是封面的下划线对不齐。下面介绍下自己如何解决这个问题的。 工具/原料 wps 方法/步骤 在顶栏中选择“视图”。 点出“标尺”工具。 如图所示&#xff0c;左边的标尺点&#xff0c;是文档的左边默认区域边界&#xff0c;右边的…

关于使用Word下划线不对齐的问题

今天编写论文初稿遇到下划线无法对齐的问题。因此&#xff0c;无意之中发现一个解决方式&#xff0c;可以减小字号的方式来使下划线对齐&#xff0c;话不多说&#xff0c;上图&#xff1a; 这是一个下划线不对齐的情况&#xff0c;怎么调整也无法对齐的情况&#xff0c;可以通过…