使用双精度的浮点运算



>我有一个函数,它接受两个字符串(浮点(、运算和浮点位宽:

EvaluateFloat(const string &str1, const string &str2, enum operation/*add,subtract, multiply,div*/, unsigned int bit-width, string &output)

输入 str1 和 str2 可以是浮点数(32 位(或双精度(64 位(。

是否可以 如果将输入存储在双精度中并执行双精度操作,而不管位宽如何,并且取决于位宽类型转换,如果它是 32 位,则将其转换为浮点数。 例如

double num1 = atof(str1);
double num2 = atof(str2);
double result = num1 operation num2; //! operation will resolved using switch
if(32 == bit-width)
{
float f_result = result;
output = std::to_string(f_result);
}
else
{
output = std::to_string(result);
}

如果我使用浮点类型执行浮点操作的操作,我可以安全地假设f_result

完全相同,即
float f_num1 = num1;
float f_num2 = num2;
float f_result = f_num1 operation f_num2

附注:

  1. 我们假设赢了;t 是任何级联操作,即 out = a + b + c 相反,它将转换为:温度 = a +b 输出 = 温度 + c
  2. 我不关心 inf 和 nan 值。
  3. 正在尝试编码冗余,否则我有两个做相同的操作 两次一次用于浮点,其他一次用于双倍

C++没有指定用于floatdouble的格式。如果使用 IEEE-754 二进制 32 和二进制 64,则不会对+-*/sqrt发生双重舍入错误。给定float xfloat y,以下成立(左边float算术,右边double(:

  • x+y=(float) ((double) x + (double) y).
  • x-y=(float) ((double) x - (double) y).
  • x*y=(float) ((double) x * (double) y).
  • x/y=(float) ((double) x / (double) y).
  • sqrt(x)=(float) sqrt((double) x).

这是根据论文完全支持高级编程语言中的浮点运算的IEEE标准的严格框架,作者Samuel A. Figueroa del Cid,2000年1月,纽约大学。从本质上讲,double具有超出float的太多数字(位(,因此舍入double永远不会隐藏正确舍入以float这些操作的结果所需的信息。(这不能适用于一般操作;这取决于这些操作的属性。在第57页,Figueroa del Cid给出了一个表格,显示如果float格式有p位,那么为了避免双重舍入错误,double必须有2个p+1位用于加法或减法,2p用于乘法和除法,2p+2用于sqrt。由于 binary32 的有效位数为 24 位,double位为 53 位,因此满足这些要求。(详见论文。有一些注意事项,例如对于各种操作,p必须至少为 2 或 4。

根据标准,对double进行浮点运算相当于以无限精度进行操作。如果我们将其转换为float我们现在已将其四舍五入两次。一般来说,这并不等同于首先四舍五入到float。例如。0.47 舍入为 0.5,四舍五入为 1,但 0.47 直接舍入为 0。正如 chtz 所提到的,两个浮点数的乘法应该总是正好是一些双倍数(使用 IEEE 数学,其中double的精度是float的两倍以上(,所以当我们投射到一个float时,我们仍然只损失了一次精度,所以结果应该是相同的。同样,加法和减法应该不是问题。

除法不能完全表示为双精度(甚至不是 1/3(,因此我们可能会认为除法存在问题。 但是,我已经在一夜之间运行了示例代码,尝试了超过 3 万亿个案例,并且没有发现任何将原始除法作为double运行给出不同答案的情况。

#include <iostream>
int main() {
long i=0;
while (1) {
float x = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
float y = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
float  f = x / y;
double d = (double)x / (double)y;
if(++i % 10000000 == 0) { std::cout << i << "t" << x << "," << y << std::endl; }
if ((float(d) !=  f)) {
std::cout << std::endl;
std::cout << x << "," << y << std::endl;
std::cout << std::hex << *(int*)&x << "," << std::hex << *(int*)&y << std::endl;
std::cout << float(d) - f << std::endl;
return 1;
}
}
}

最新更新