神奇的sqrt函数以及高精度记时函数

转载

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 >相比,虽然写的代码量多了一点,但是看上去逼格略高,精度也更高~

 

也可以把上面两个方法封装一下。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值