【问题标题】:Float operations using double使用双精度浮点运算
【发布时间】:2020-09-24 07:18:39
【问题描述】:

我有一个函数,它需要两个字符串(浮点),运算和浮点位宽:

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

输入 str1 和 str2 可以是 float(32 位)或 double(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

PS:

  1. 我们假设不会有任何级联操作,即 out = a + b + c 相反,它将转换为: temp = a +b out = temp + c
  2. 我不关心 inf 和 nan 值。
  3. 我正在尝试编码冗余,否则我有两个执行相同的操作 两次浮动一次,其他两次两次

【问题讨论】:

  • double 的精度不低于floatfloat 可以表示的值集是double 可以表示的值集的严格子集。因此,从floatdouble 的转换没有潜在的精度损失,但是会转换回来。如果您只使用floats 进行操作,您可能会得到不同的结果。这些情况并不表明您通过使用double 进行操作而失去了精度 - 这意味着您获得的精度比仅在floats 上进行操作所获得的精度更高,但比使用@ 做所有事情要少987654333@s.
  • 谢谢彼得。可能是我错误地提出了我的问题,我们是一个等价检查工具,所以我们需要根据语言语义匹配任何结果。
  • 你给我们的信息太少了,看你为什么想做,你做什么。就我而言,我真的不明白为什么会有刺痛,当你在花车上操作时。尽管如此。当你的操作都是双倍并返回一个浮点数时,你肯定会得到不同的结果。与对浮点数的操作相比并返回浮点数。不仅在精度上,结果也会不同,因为 float 不如 double 精确,因此操作会有所不同。你无法比较结果并获得匹配。你必须实现一个带有增量的比较函数,然后你将创建匹配项。
  • @skratchi.at 我们是一个等价检查工具,所以我们需要根据语言语义匹配任何结果。
  • 你确定str1str2 有准确的float 表示吗?例如,像 0.1 这样的“简单”数字没有。在您的“PS 3”中:为什么不编写模板方法?

标签: c++ casting floating-point


【解决方案1】:

C++ 没有指定 floatdouble 使用哪些格式。如果使用 IEEE-754 binary32 和 binary64,则 +-*/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)

这是根据 Samuel A. Figueroa del Cid 的论文A Rigorous Framework for Fully Supporting the IEEE Standard for Floating-Point Arithmetic in High-Level Programming Languages,2000 年 1 月,纽约大学。从本质上讲,doublefloat 之外有很多数字(位),因此舍入到double 永远不会隐藏正确舍入到float 所需的信息以获取这些操作的结果。 (这不适用于一般操作;它取决于这些操作的属性。)在第 57 页,Figueroa del Cid 给出了一个表格,表明如果float 格式具有 p 位,那么,为避免双舍入错误,double 必须有 2p+1 位用于加法或减法,2p 用于乘法和除法,2p i>+2 表示sqrt。由于 binary32 的有效位有 24 位,double 有 53 位,因此这些都满足。 (详见论文。有一些注意事项,例如对于各种操作,p 必须至少为 2 或 4。)

【讨论】:

    【解决方案2】:

    根据标准对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;
                    }
            }
    }
    

    【讨论】:

    • 嗨 gmatht,这里的一个区别是您将输入保持为双精度与浮点数,而在我的情况下,输入将浮点数只是我们将其存储在双精度数中。我稍微修改了你的代码,它可以无限运行:
    • int main() { double epsilon=1.0;诠释我=0;而 (1) { epsilon=epsilon/2.0;浮动 f = (float)(1 + epsilon) ;浮动 g = (float)(1 + epsilon);浮动 h = f * g;双 d = f ;双 e = g;双 x = d * e; std::cout
    • 不知何故在我的机器上它继续运行。你能在它停止之前分享输出吗?它是一个 nan 值吗?
    • 我很确定两个float 的乘积总是完全可以表示为double(假设标准 IEEE 754 并且只有有限因子)。您实际上是将两个 24 位数字相乘(最多给出 48 个有效位)并将它们存储到一个 53 位数字中。但是您很可能会在您的测试中找到带有除法的示例。
    • @gmatht 是的,但我认为你找不到两个浮点数 xy 其中 double(x)*double(y) 需要四舍五入。
    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 2018-07-06
    • 2018-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 1970-01-01
    相关资源
    最近更新 更多