转载
https://diducoder.com/sotry-about-sqrt.html
// TestC.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "math.h"
#include <windows.h>
#define eps 1e-7
float InvSqrt(float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x; // get bits for floating VALUE
i = 0x5f375a86- (i>>1); // gives initial guess y0
x = *(float*)&i; // convert bits BACK to float
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
x = x*(1.5f-xhalf*x*x); // Newton step, repeating increases accuracy
return 1/x;
}
float SqrtByNewton(float x)
{
float val = x;//最终
float last;//保存上一个计算的值
do
{
last = val;
val =(val + x/val) / 2;
}while(abs(val-last) > eps);
return val;
}
float SqrtByBisection(float n) //用二分法
{
if(n<0) //小于0的按照你需要的处理
return n;
float mid,last;
float low,up;
low=0,up=n;
mid=(low+up)/2;
do
{
if(mid*mid>n)
up=mid;
else
low=mid;
last=mid;
mid=(up+low)/2;
}while(abs(mid-last) > eps);//精度控制
return mid;
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int LoopCount = 1000;
float x = 65535;
LARGE_INTEGER d1,d2,d3,d4,d5;
QueryPerformanceCounter(&d1);
for(unsigned int i=0;i<LoopCount;i++)
SqrtByBisection(x);
QueryPerformanceCounter(&d2);
for(unsigned int i=0;i<LoopCount;i++)
SqrtByNewton(x);
QueryPerformanceCounter(&d3);
for(unsigned int i=0;i<LoopCount;i++)
InvSqrt(x);
QueryPerformanceCounter(&d4);
for(unsigned int i=0;i<LoopCount;i++)
sqrt(x);
QueryPerformanceCounter(&d5);
printf("下面是计算sqrt(65535)结果的对比\n");
printf("-----------------------------------------\n");
printf(" 方法 \t时间\t计算结果\n");
//printf("二分法 : %8.2f\t%8.8f\n",((float)d2.QuadPart - (float)d1.QuadPart)/LoopCount,SqrtByBisection(x));
//printf("牛顿迭代法 : %8.2f\t%8.8f\n",((float)d3.QuadPart - (float)d2.QuadPart)/LoopCount,SqrtByNewton(x));
//printf("神奇的方法 : %8.2f\t%8.8f\n",((float)d4.QuadPart - (float)d3.QuadPart)/LoopCount,InvSqrt(x));
//printf("System方法 : %8.2f\t%8.8f\n",((float)d5.QuadPart - (float)d4.QuadPart)/LoopCount,sqrt(x));
printf("二分法 : %8.2f\t%8.8f\n",((float)d2.QuadPart - (float)d1.QuadPart),SqrtByBisection(x));
printf("牛顿迭代法 : %8.2f\t%8.8f\n",((float)d3.QuadPart - (float)d2.QuadPart),SqrtByNewton(x));
printf("神奇的方法 : %8.2f\t%8.8f\n",((float)d4.QuadPart - (float)d3.QuadPart),InvSqrt(x));
printf("System方法 : %8.2f\t%8.8f\n",((float)d5.QuadPart - (float)d4.QuadPart),sqrt(x));
printf("-----------------------------------------\n");
return 0;
}
在Windows系统中,高精度计时:
QueryPerformanceFrequency用于获取性能计数的频率,每秒多少次,
QueryPerformanceCounter用于获取当前性能计数的值,
秒级耗时 = (结束性能计数值 - 开始性能计数值) / 性能计数频率
微秒耗时 = (结束性能计数值 - 开始性能计数值)* 1000000 / 性能计数频率
微秒计时
{
LARGE_INTEGER freq_;
QueryPerformanceFrequency(&freq_);
LARGE_INTEGER begin_time;
LARGE_INTEGER end_time;
QueryPerformanceCounter(&begin_time);
Sleep(100);
QueryPerformanceCounter(&end_time);
double ns_time = (end_time.QuadPart - begin_time.QuadPart) * 1000000.0 / freq_.QuadPart;
}
微妙级记时封装
class stop_watch
{
public:
stop_watch()
: elapsed_(0)
{
QueryPerformanceFrequency(&freq_);
}
~stop_watch(){}
public:
void start()
{
QueryPerformanceCounter(&begin_time_);
}
void stop()
{
LARGE_INTEGER end_time;
QueryPerformanceCounter(&end_time);
elapsed_ += (end_time.QuadPart - begin_time_.QuadPart) * 1000000 / freq_.QuadPart;
}
void restart()
{
elapsed_ = 0;
start();
}
//微秒
double elapsed()
{
return static_cast<double>(elapsed_);
}
//毫秒
double elapsed_ms()
{
return elapsed_ / 1000.0;
}
//秒
double elapsed_second()
{
return elapsed_ / 1000000.0;
}
private:
LARGE_INTEGER freq_;
LARGE_INTEGER begin_time_;
long long elapsed_;
};
使用
stop_watch watch;
watch.start();
Sleep(100);
watch.stop();
cout << watch.elapsed() << " ns" << endl;
下面方法在linux上运行:
传统的 #include < ctime >
#include <ctime>
using namespace std;
clock_t start = clock();
// do something...
clock_t end = clock();
cout << "花费了" << (double)(end - start) / CLOCKS_PER_SEC << "秒" << endl;
此方法可以精确到毫秒,输出样例:花费了0.123秒
C++11的 #include< chrono >
C++11的”最佳计时方法“
#include <chrono>
using namespace std;
using namespace chrono;
auto start = system_clock::now();
// do something...
auto end = system_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout << "花费了"
<< double(duration.count()) * microseconds::period::num / microseconds::period::den << "秒" << endl;
此方法可以精确到微妙,输出样例:花费了0.123456秒
system_clock 是 C++11 提供的一个 clock。除此之外,还有两个clock:steady_clock 和 high_resolution_clock
now( ) 表示计时的那“一瞬间”
duration_cast< > 表示类型转换
microseconds 表示微妙。除此之外,还有五种时间单位:hours, minutes, seconds, milliseconds, nanoseconds
num 和 den分别表示分子(numerator)和分母(denominator)。在我给出的代码中,num等于1, den等于1,000,000
count( ) 用来返回时间
如果想深究,查看 cplusplus
C++11的 #include< chrono >和传统的 #include < ctime >相比,虽然写的代码量多了一点,但是看上去逼格略高,精度也更高~
也可以把上面两个方法封装一下。