淘客熙熙

主题:【求助】由一个编程考试想到的 -- 东方射日

共:💬9 🌺8
全看分页树展 · 主题 跟帖
家园 要想高精度计算,绝对不能用浮点数(附计算e的源代码)

要想高精度计算,绝对不能用浮点数。由于计算机是二进制的,在电脑中的浮点数总有一个误差。例如你所说的1/3就是一个例子。

这个误差会有很多问题,例如:

float a = 1.0f / 3.0f;

a /= 5.0f;

float b = 1.0f / 5.0f;

b /= 3.0f;

这里你可以试试比较a和b,应当得到是不等的。

所以通常我们比较两个浮点数是否相等不是直接用“==”而是比较两者差值小于一个我们可以接受的误差即认为相等。

如果如我说说的进行高精度计算只能自己用一个数组进行管理。

例如我们要计算到小数点后10000位,就建立一个至少10000位的数组,当然你最好建立一个类:

class Digit

{

public:

Digit();

~Digit();

friend Digit & operator + (const Digit & a, const Digit & b);

// 你自己可以添加其他诸如 - * / > < ==等运算符的实现

private:

int mInterger;

char mDecimal[10000]; // 当然最好在构造函数中指定位数,或提供一个成员函数来设定或变更精确的位数

}

下面,我把e计算的源代码贴出来,请各位指教,看看是否还有性能提高的余地。

不过该程序是测试时写的,如果想作为库还是不合格,因为 result在内部分配的内存,不符合自动释放或谁分配谁释放的原则,存在内存泄露的危险

// num:小数点后位数,为保证精度,调用时可以多一个经验值,例如10位。比如需要精确到小数点后10000位,就设num位10010

//result:返回结果,第一位为整数部分,其余为小数,每字符为一位,为0-9;如果需要直接可打印的结果,可以将各字符加上‘0’

void calculateE(int num, char * &result)

{

// e = 1 + 1 + 1/2! + 1/ 3! + 1/4! + ..... + 1/n!

if (result) SAFE_DELETE(result);

result = new char[num];

memset(result ,0,num);

assert(result);

char * tmp;

char * lastTmp;

char * tempResult[2];

tempResult[0] = new char[num];

assert(tempResult[0]);

tempResult[1] = new char[num];

assert(tempResult[1]);

tmp = tempResult[0];

lastTmp = tempResult[1];

int tmpIndex = 0;

memset(lastTmp,0,num);

lastTmp[0] = 1;

for (int cal = 2;cal <= num; ++cal)

{

memset(tmp,0,num);

int firstNoZero = 0;

static int div = 1;

for (;div <= cal; ++div)

{

int quo = 0;

int rem = 0;

for (int j = 0; j< num; ++j)

{

quo = rem * 10 + lastTmp[j];

rem = quo % div;

quo = quo / div;

tmp[j] = quo;

if (firstNoZero == 0 && div == cal && tmp[j] != 0)

{

firstNoZero = j;

}

}

}

div = cal;

int flag = 0;

if (firstNoZero == 0)

{

break; // no need to calculate anymore 此时在需要的精度内全为零,不需要继续计算了

}

for (int i = num - 1; i >= firstNoZero - 1; --i)

{

int tmp_sum = tmp[i] + result[i] + flag;

flag = (tmp_sum >= 10 ? 1 : 0);

result[i] = (flag ? tmp_sum - 10 : tmp_sum);

}

lastTmp = tmp;

tmpIndex = (tmpIndex ? 0 : 1);

tmp = tempResult[tmpIndex];

}

delete[] tempResult[0];

delete[] tempResult[1];

result[0] += 2;

}

全看分页树展 · 主题 跟帖


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河