当前位置: 首页 > news >正文

C语言求平方和倒数

文章目录

    • 1. 代码实现
      • float类型数据
      • double类型数据
      • 使用 double 类型的调整
    • 2. 魔数与位级别操作
      • 浮点数表示
      • 位级别魔数操作
    • 3. 牛顿迭代
    • 4. 复杂代码具体解释
      • 具体解释:
      • 目的:
      • 举例:
    • 5.感谢

平方和倒数 广泛用于计算机图形学中,尤其是在处理大规模3D渲染时。这种方法的核心思想是利用了位级别的操作和牛顿迭代法,以非常高效的方式计算平方根的倒数。

平方根倒数(Reciprocal Square Root)计算的问题是,对于一个给定的数 n,我们希望快速找到 1/√n。在图形学和物理模拟中,这种计算非常常见,通常用于归一化向量。

传统的平方根计算通常使用浮点运算,较为耗时。为了提高效率,特别是在早期硬件性能有限的情况下,出现了一种基于“魔数”(magic number)的快速算法。


1. 代码实现

float类型数据

float Q_rsqrt(float n)
{long i;float x2, y;const float threehalfs = 1.5F;x2 = n * 0.5F;y = n;i = *(long *)&y;i = 0x5f3759df - (i >> 1);y = *(float *)&i;// First iterationy = y * (threehalfs - (x2 * y * y));// Second iteration for higher precisiony = y * (threehalfs - (x2 * y * y));// Third iteration for higher precisiony = y * (threehalfs - (x2 * y * y));// Fourth iteration for higher precisiony = y * (threehalfs - (x2 * y * y));return y;
}

double类型数据

double Q_rsqrt(double n)
{long long i;double x2, y;const double threehalfs = 1.5;x2 = n * 0.5;y = n;i = *(long long *)&y;i = 0x5fe6eb50c7b537a9 - (i >> 1); // 使用64位常量y = *(double *)&i;// First iterationy = y * (threehalfs - (x2 * y * y));// Second iteration for higher precisiony = y * (threehalfs - (x2 * y * y));// Third iteration for higher precisiony = y * (threehalfs - (x2 * y * y));// Fourth iteration for higher precisiony = y * (threehalfs - (x2 * y * y));return y;
}

使用 double 类型的调整

在处理 double 类型时,需要进行一些调整:

  • long 类型需要扩展为 long long 以适应 64 位浮点数的表示。
  • 魔数 0x5f3759df 替换为适用于 64 位的 0x5fe6eb50c7b537a9

2. 魔数与位级别操作

这个方法的核心是通过使用魔数对浮点数进行位级别的操作,得到平方根倒数的一个初始近似值。

浮点数表示

在现代计算机中,浮点数通常采用 IEEE 754 标准表示,包括符号位、指数部分和尾数部分。对于 32 位浮点数来说,结构如下:

  • 1 位符号位
  • 8 位指数部分
  • 23 位尾数部分

位级别魔数操作

Q_rsqrt 方法的精妙之处在于,它将浮点数视作一个整数,通过操作位来得到平方根倒数的近似值。核心操作如下:

i = 0x5f3759df - (i >> 1);

在这个公式中,i 是浮点数 y 在内存中的位表示,0x5f3759df 是一个特定的常量,这个常量通过经验或实验计算得出,能够将位级别的操作映射到一个相对合理的平方根倒数的近似值。对于 double 类型,需要将这个常量替换为 64 位的版本,即 0x5fe6eb50c7b537a9

这个操作的本质是近似计算了数值的对数,再通过魔数进行校正,使得结果在位操作的基础上接近实际的平方根倒数值。

3. 牛顿迭代

初始近似值得到后,使用牛顿迭代法进一步提高精度。牛顿迭代法是一种经典的数值方法,用于求解方程的根。对于平方根倒数问题,目标是找到 y,使得 y = 1/√n

牛顿迭代的公式如下:

y = y * (threehalfs - (x2 * y * y));

其中:

  • x2 = n * 0.5,是数值的一半,用于简化计算。
  • threehalfs = 1.5,是一个常量,用于调整收敛速度和稳定性。

这个公式利用当前的 y 值,结合原数 n,逐步逼近实际的 1/√n。每次迭代后,y 的值会变得更接近真实的平方根倒数值。

为了提高精度,通常会进行多次迭代。在最常见的实现中,进行一次或两次迭代已经可以满足大部分应用场景中的精度要求。

4. 复杂代码具体解释

代码 i = *(long *)&y; y = *(float *)&i; 是一种类型惩断(type punning)的操作方式,用于在不改变底层数据的情况下,以另一种类型访问相同的内存位置。以i = *(long *)&y;为例:

具体解释:

  • y 是一个 float 类型的变量。
  • &y 获取的是变量 y 的内存地址,这个地址是指向 float 类型数据的指针。
  • (long *)&y 将这个 float 类型的指针强制转换为 long 类型的指针。注意,这个操作并不改变 y 的实际数据,只是告诉编译器,“虽然 &y 原本是 float* 类型,但我要以 long* 类型来看待它。”
  • *(long *)&y 是取出这个 long* 指针所指向的数据。这意味着它会将 y 所在内存位置的位模式当作一个 long 类型的整数来读取。

目的:

在这种操作中,i 将会持有 y 变量的位表示形式,但被解释为一个 long 整数。这种操作允许我们以整数的形式直接操纵浮点数的底层位数据。在 Q_rsqrt 算法中,目的是利用这个位模式来快速估算平方根的倒数。

举例:

假设 y 是一个 float 类型的变量,假定其在内存中的二进制表示为 0x40490FDB(假设是浮点数 3.14159 的表示)。将它以 long 类型解读后,i 就会得到一个与 0x40490FDB 位模式相同的整数值。

这种方法的核心在于能够绕过浮点数的常规处理路径,直接对其位级别的数据进行操作,从而实现快速近似计算。这在一些高性能要求的算法中非常常见,特别是在图形处理、信号处理等领域。

5.感谢

代码出自小黑盒贴吧的一位老哥的分享,学习之后觉得着实精妙,针对代码中的重点部分进行了详细解释并分享给大家,再次感谢老哥分享!
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【区块链+社会公益】第一反应互助急救链 | FISCO BCOS应用案例
  • leetcode50. Pow(x, n),快速幂算法
  • Java 代码详解:删除链表中的倒数第 N 个节点
  • JavaScript 数组迭代
  • WPF篇(5)- Border控件(边框布局)+GridSplitter分割窗口
  • Linux虚拟化技术的演进:Xen与KVM的历程与影响
  • 【Kubernetes】k8s集群之Pod容器资源限制和三种探针
  • 河南萌新联赛2024第(四)场:河南理工大学补题(B,C,I)
  • 软件测试面试题汇总,超详细整理。。。
  • 【https】无法安装OpenSSL时如何在局域网开通https服务
  • 常见8种数据结构
  • 好领导都会用三招管好下属!
  • 三数之和(LeetCode)
  • 全栈监控:一目了然的 IT 管理
  • 第13节课:Web Workers与通信——构建高效且实时的Web应用
  • flutter的key在widget list的作用以及必要性
  • go append函数以及写入
  • interface和setter,getter
  • JavaScript对象详解
  • PHP面试之三:MySQL数据库
  • Sass 快速入门教程
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue2.0 实现互斥
  • windows下如何用phpstorm同步测试服务器
  • Yeoman_Bower_Grunt
  • 初识MongoDB分片
  • 关于字符编码你应该知道的事情
  • 前端
  • 一、python与pycharm的安装
  • ​低代码平台的核心价值与优势
  • ​人工智能书单(数学基础篇)
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #控制台大学课堂点名问题_课堂随机点名
  • (11)MATLAB PCA+SVM 人脸识别
  • (39)STM32——FLASH闪存
  • (C语言)二分查找 超详细
  • (java)关于Thread的挂起和恢复
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • (一)80c52学习之旅-起始篇
  • (转) Android中ViewStub组件使用
  • (转)ORM
  • **python多态
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .NET MVC之AOP
  • .net 后台导出excel ,word
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .Net多线程总结
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • :class的用法及应用
  • ?
  • ?php echo $logosrc[0];?,如何在一行中显示logo和标题?