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.感谢

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/395592.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot - 通过ApplicationListener实现接口请求的性能监控

文章目录 概述1. ServletRequestHandledEvent事件2. 实现步骤3. 优缺点分析4. 测试与验证小结其他方案1. 自定义拦截器2. 性能监控平台3. 使用Spring Boot Actuator4. APM工具 概述 在Spring框架中,监控接口请求的性能可以通过ServletRequestHandledEvent事件实现。…

【数据结构】—— 内部排序算法详解

1、前言2、常见排序算法3、排序算法实现3.1 直接插入排序3.2 希尔排序3.3 选择排序3.4 堆排序3.5 冒泡排序3.6 快速排序3.6.1 单趟排序hoare法挖坑法双指针法 3.6.2 非递归实现3.6.3 常见问题基准值的选取小区间优化 3.7 归并排序3.7.1 递归实现3.7.2 非递归实现 3.8 计数排序 …

glibc的安装及MySQL的安全用户角色权限(twenty-one day)

一、glibc安装 mysql 清空/etc/目录下的my.cnf ls -l /etc/my.cnf rm -rf /etc/my.cnf yum -y remove mariadb find / -name "*mysql*" -exec rm -rf {} \; 安装mysql软件包 wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.33-li nux-glibc2.1…

面壁的智能开源 MiniCPM-V 2.6 边缘人工智能多模态功能与 GPT-4V 不相上下

"MiniCPM-V2.6 "是一个边缘多模态人工智能模型,仅拥有 80 亿个参数,却在单图像、多图像和视频理解任务中取得了低于 200 亿个参数的三项 SOTA(艺术境界)成绩,显著增强了边缘多模态能力,并与 GPT-…

爬虫入门--了解相关工具

目录 1.爬虫与python 2.第一个爬虫 3.web请求的全过程 3.1服务器渲染 3.2前端JS渲染 4.浏览器工具 4.1Elements 4.2Console 4.3Source 4.4network(重点) 5.小结 1.爬虫与python 首先我们要知道,爬虫一定要用Python么? 非也~…

云计算任务调度优化matlab仿真,对比蚁群优化和蛙跳优化

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 ACO蚁群优化 4.2 蛙跳优化 5.完整程序 1.程序功能描述 云计算任务调度优化,优化目标位任务消耗时间,调度后的经济效益以及设备功耗,对比蚁群优化算法和蛙跳优化…

三星、小米和 OPPO设备实验室将采用Android设备流技术

早在 5 月份的年度开发者大会上,Google就发布了 Android 设备流测试版。开发人员可以在Google数据中心的真实物理设备上更轻松、更互动地测试自己的应用程序,这些设备会直接串流到 Android Studio。今天,Google宣布与三星、小米和 OPPO 合作扩…

关于LLC知识5

RLC的增益曲线不知一条 频率升高,增益会越来越低 无论在容性区还是感性区,当负载加重的时候,R阻值会变小,所以R的分压也会变小,导致增益会变低 当负载突然加重,输出电压会变低,增益曲线由红色变…

如何让左右两个div各占50%,并且高度相同?

如何设置两个div各占一半,并且高度随着内容增加,而且两边div的高度一致呢?默认会发现高度不一致,改用flex就可以了,另外发现传统的table也可以轻易实现。不知道不用flex的话是否可以实现。 方法1(div实现&a…

环境配置:如何在IntelliJ IDEA中安装和修改JDK版本配置(以Windows为例)

环境配置:如何在IntelliJ IDEA中安装和修改JDK版本配置(以Windows为例) 为了在Java开发中使用最新的功能和优化,升级和配置JDK版本是必不可少的。本文将详细介绍如何下载、安装、配置最新的JDK版本,并在IntelliJ IDEA…

pikachu文件包含漏洞

一:漏洞基础 程序在引用文件的时,引用的文件名存在可控的情况,传入的文件名没有经过合理的校验或校验不严,从而操作了预想之外的文件,就有可能导致文件泄漏和恶意的代码注入; 文件包含漏洞概念 在PHP程序…

安卓将子模块打aar包,并将其远程依赖打包进去

生成 AAR 包 在Android Studio Terminal 窗口输入以下命令: ./gradlew :monitor:assembleRelease把 monitor 换成你子模块的名称,不出意外的话 就会在下面目录生成相应aar文件 注意:如果你的Java运行环境是Java 8 则在老一点的AS上 可以运…

PCIe学习笔记(19)

TLP Prefix(前缀)规则 以下规则适用于任何包含TLP Prefix的TLP: •对于任何TLP, TLP第0字节的Fmt[2:0]字段值为100b表示存在TLP Prefix, Type[4]位表示TLP Prefix的类型。 ◦Type[4]位的值为0b表示存在Local TLP Prefix ◦Type[4]位的值为1b表示存在…

牛客JS题(二十三)判断质数

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; 原型链如何优雅的判断质数 题干&#xff1a; 我的答案 <!DOCTYPE html> <html><head><meta charsetutf-8></head><body><script type"text/javascript">/*** 素…

Vue引入使用iconfont字体图标

由于element-ui或element-plus提供的图标有时候并不能满足日常需求,所以这篇介绍一下前端引入阿里巴巴矢量图标库使用,不止是vue使用,不限于vue2、vue3,html或是其他框架也是同样的道理,只要引入都是同样可以使用的。 1. 首先进入阿里巴巴矢量图标库官网 官网:https://…

螺旋矩阵

螺旋矩阵 思路&#xff1a; 这题是一个模拟的题目。 可以观察出一些性质&#xff1a;每次需要换方向的时候都是到达了边界&#xff08;长度和宽度的边界&#xff09;。 不知道怎么转化为代码&#xff01; 哭了 看看题解吧&#xff1a;真不会 看到一个太妙的方法了&#x…

初识云计算

随着科技的飞速发展&#xff0c;云计算作为一种新兴的信息技术架构&#xff0c;正在逐渐改变我们的工作方式和生活方式。 云计算是什么&#xff1f; 云计算是一种通过互联网提供计算资源和服务的计算模式。它通过互联网将计算和存储资源进行集中和共享&#xff0c;为用户提供…

zabbix的自动发现和注册、proxy代理和SNMP监控

一、zabbix自动发现和注册 1.概念 zabbix客户端主动的和服务端联系&#xff0c;将自己的地址和端口发送给服务端&#xff0c;实现自动添加监控主机。 客户端是主动的一方 缺点&#xff1a;自定义网段中主机数量太多&#xff0c;登记耗时会很久&#xff0c;而且这个自动发现…

Java 处理一张单据,处理花费时间挺久,有单号,不用redis怎么可以快速判断其在处理中,不需要再处理

在Java中处理长时间的任务并且需要避免重复处理同一张单据的情况下&#xff0c;在不使用Redis或其他外部存储服务情况下。 方法一&#xff1a;使用数据库表 表记录记录状态 方法二&#xff1a;使用文件系统 创建和删除文件记录状态 方法三&#xff1a;使用本地缓存 import …

6种常用的AR跟踪方法

增强现实 (AR) 是一项令人着迷的技术&#xff0c;可将虚拟内容与现实世界无缝集成。实现这种无缝集成的关键组件之一是跟踪。各种类型的跟踪用于确定 AR 内容在环境中的准确位置和方向。本文介绍 AR 最常见的6种跟踪方法。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - Y…