首页 > 其他分享 >整数平方和开根号的性能优化

整数平方和开根号的性能优化

时间:2023-04-15 21:13:15浏览次数:41  
标签:查表 res 整数 平方和 xx u32 bit 根号

整数的平方和开根号操作通过sqrt实现性能已经不容易优化,但如果要求精度不高,可以进一步优化,方法有三种:1、isqrt;2、查表法;3、三角函数法

1、isqrt即整数平方根,有多种算法。通过询问ChatGPT,AI给出了几种实现,这里取一种比较快的实现:

 1 u32 isqrt2(u32 x)
 2 {
 3     u32 res = 0;
 4     u32 bit = 1 << 30; // The second-to-top bit is set: 1 << 30 for 32 bits
 5     // "bit" starts at the highest power of four <= the argument.
 6     while (bit > x) bit >>= 2;
 7     while (bit != 0)
 8     {
 9         if (x >= res + bit)
10         {
11             x -= res + bit;
12             res = (res >> 1) + bit;
13         }
14         else res >>= 1;
15         bit >>= 2;
16     }
17     return res;
18 }

这种算法的速度比浮点sqrt函数慢很多。又尝试了牛顿迭代法、割线法求整数平方根的整数部分,其性能均不如浮点算法。牛顿迭代法的迭代次数为2~3次的时候就能满足精度指标,但其性能已经远远落后于sqrt。

2、查表法

整数平方和是一个非常大的数,一般项目中都在16bit以上,要做一个超级大的表才能实现精确的查表。所以这里的查表法是分两部分查表,若输入小,则直接查表输出。若输入较大,则将其高位数值查表,低位忽略。这样就能大大降低表的大小,并且仅通过一次查表实现输出。理论上误差为表大小开根号乘以0.414。例如,256的表,最大误差时为计算511的平方根,结果为16,误差为16*0.414=6.6;4K的表最大误差27。

一个实现的例子:

1 u8 isqrt_N(u16 x) //只能算根在256以内的,超过就错了
2 {
3     u16 x0=x>>8;
4     if(x0<=0) return isqrt_N_tab[x];
5     u16 x1=isqrt_N_tab[x0]; //高8bit开方
6     return x1<<4;
7 }

3、三角函数法

整数平方和开根号可以看做是已知三角形的两个直角边,求斜边。首先设其中比较大的输入为x,小的为y。则x边的角度为atan(y/x),斜边长度为x/cos(atan(y/x))。由于y/x这个比值小于1,不会让atan出现很多不均匀的情况,所以可以将1/ x/cos(atan(y/x))做成查找表,并通过定点数存储。计算平方根时,只需计算x/查表值即可。由于需要计算除法,导致此算法效率并没有比浮点sqrt快很多

一个例程:

 1 u16 isqrt_sq_sum(int x,int y) //平方和开根号
 2 {
 3     u32 xx=abs(x);
 4     u32 yy=abs(y);
 5     if(xx>yy)
 6     {
 7         if(xx==0) return 0;
 8         u32 ind=yy*128/xx; //肯定是正的,肯定小于128
 9         return (xx*cos_tan_tab[ind])>>12; // x*4096/cos(tan(y/x))/4096
10     }
11     else
12     {
13         if(yy==0) return 0;
14         u32 ind=xx*127/yy; //有x=y的情况
15         return (yy*cos_tan_tab[ind])>>12; // x*4096/cos(tan(y/x))/4096
16     }
17 }

以上三种算法均依赖-O3编译器优化,才能实现比sqrt快的性能。而sqrt函数本身是经过优化的,所以编译器优化对其无优化效果。

标签:查表,res,整数,平方和,xx,u32,bit,根号
From: https://www.cnblogs.com/yangzifb/p/17321880.html

相关文章

  • 【230415-2】已知:a+b=4(a>0,b>0) 求:根号下(a^2+1)+根号下(b^2+1)的最小值?
    ......
  • HDU 1042 N! (大整数阶乘)
    这道题开始并不会,是看了别人的代码,自己又改造了一下,代码如下:(PS:这个时候自带大整数运算的java就有优势了)#include<bits/stdc++.h>usingnamespacestd;constintN=20000+10;intans[N];voidfact(intn){ans[0]=ans[1]=1;inttot=1;for(inti=......
  • 调整数组顺序使奇数位于偶数前面
    输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。示例:输入:nums= [1,2,3,4]输出:[1,3,2,4]注:[3,1,2,4]也是正确的答案之一。提示:0<=nums.length<=500000<=nums[i]<=10000int*exchange(int*nums,......
  • HashMap内部的bucket(桶)数组长度为什么一直都是2的整数次幂?
    这样做有两个好处:第一,可以通过(table.length-1)&key.hash()这样的位运算快速寻址,第二,在HashMap扩容的时候可以保证同一个桶中的元素均匀的散列到新的桶中,具体一点就是同一个桶中的元素在扩容后一半留在原先的桶中,一半放到了新的桶中。......
  • 带有PV面板和电池的孤岛微电网的混合整数线性规划(MILP)调度
    带有PV面板和电池的孤岛微电网的混合整数线性规划(MILP)调度测试环境:MATLAB,YALMIP,GUROBI将负荷和太阳辐射预测作为输入。返回计划范围内(例如一周)的每个组件的计划。试图最大程度地减少甩负荷和减少发电量。ID:14100644860196918......
  • 充电站位置规划22 建立了混合整数编程(MIP)模型 在模型优化部分中,我们通过人口分布划分
    充电站位置规划221.建立了混合整数编程(MIP)模型。对于农村来说,交通网络并不像他们的城市同行那样强大。充电站可以辐射到应考虑的周围区域,因此纸张使用加权Vorinor图模型(WVDM)来分析该方面。对于城市的充电站,考虑了交通流量的效果。同时,引入排队理论以计算驱动程序的平均等待时......
  • 两整数的加法
    一、内容简介:本题目要求读入2个整数A和B,然后输出它们的和(在一行中输入2个绝对值不超过1000的整数A和B)。二、思路:1、输入两个整数2、输出它们的和三、流程图:  四、代码实现:#include<iostream>usingnamespacestd;intmain(){inta,b,sum;cin>>a>>b;sum=a+b;cou......
  • 两数平方和(嵌套函数)
    求两整数平方和。#include<iostream>usingnamespacestd;intpower(intx,intn);intmain(){ inta,b; cout<<"请输入两个整数a,b:"<<endl; cin>>a>>b; intsum; sum=power(a,2)+power(b,2); cout<<"sum="<<sum<<end......
  • 求任一两个正整数的最大公约数。
    二、设计思路:1、输入两个正整数;2、将两个数中较小的数值赋给temp;3、接着用其中一个数与temp求余,若余数不为0,则temp-1,循环该步骤直到余数为0。4、再用另一个数,重复此步骤,最后得出的值为这两个数的最大公约数。 #include<stdio.h>intmain(){ inti=0; intm,n,temp; printf......
  • UVa 113 / POJ 2109 Power of Cryptography (使用double处理大整数&泰勒公式与误差分
    113-PowerofCryptographyTimelimit:3.000secondshttp://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=99&page=show_problem&problem=49http://poj.org/problem?id=2109题意:给出n和p,求出 ,但是p可以很大()如何存储p?不用大数可不可以?先看看double......