c++ - 在 C++ 中标记 double 损失的算法不会标记正确的位置

标签 c++ c++11

作为我的一门类(class)的一部分,我应该通过打印 1./3. 的结果来证明使用 C++ 进行双除法可能会导致精度损失。保留20位小数,并标出非3的位置。

但是,我的算法(我在下面列出)似乎一直遇到相同的运行时错误。

我在下面留下了代码以及下面的预期和实际输出。有没有解决的办法?我尝试了其他方法(包括 ostringstream 中的 <sstream> ),但这是迄今为止我能想到的最准确的方法。


算法

  1. 存储1./3.的结果到一个变量。
  2. 打印出1./3.保留到 20 位小数并添加适当的间隔符。
  3. 将第 1 步中的变量乘以 10(即将所有数字左移一位)。
  4. 检查个位数是否为 3。如果是,打印 ;否则,打印 ^ .
  5. 递减个位直到个位为0。
  6. 再重复步骤 3-6 19 次。

预期输出

1./3. Precision test
1./3.: 0.33333333333333331483
                         ^^^

实际输出(带调试输出)

1./3. Precision test
1./3.: 0.33333333333333331483
                         ^ ^^
         33333333333333330372

#include <iostream>
#include <math.h>
#include <cmath>
#include <iomanip>

using namespace std;

int main()
{
    double third = 1./3.;
    cout << "1./3. Precision test" << endl;
    cout << setw(7) << "1./3.: " << setprecision(20) << third << endl;
    cout << "         ";
    for (int i = 1; i <= 20; i++) {
        third *= 10;
        if (int(third) == 3)
            cout << " ";
        else
            cout << "^";
        while (third >= 1) third -= 1;
    }
    cout << endl;

    // For debugging purposes
    third = 1./3.;
    cout << "         ";
    for (int i = 1; i <= 20; i++) {
        third *= 10;
        cout << int(third);
        while (third > 1) third -= 1;
    }
    cout << endl;
}

最佳答案

您陷入了精度问题的陷阱。如果您重复将 1/3 乘以 10,将得到以下结果:

    0.33333333333333331483
    3.3333333333333330373
    33.333333333333328596
    333.33333333333325754
    3333.3333333333325754
    33333.333333333328483
    333333.33333333325572
    3333333.3333333325572
    33333333.333333324641
    333333333.33333325386
    3333333333.3333325386
    33333333333.333324432
    333333333333.33325195
    3333333333333.3325195
    33333333333333.324219
    333333333333333.25
    3333333333333332.5
    33333333333333324
    333333333333333248
    3333333333333332480
    33333333333333323776

请注意,最后一位数字正在发生变化。您需要先转换为字符串,如下所示:

    double third = 1. / 3.;
    cout << "1./3. Precision test" << endl;
    ostringstream s;
    cout << setw(7) << "1./3.: ";
    s << setprecision(20) << third << endl;
    string str = s.str();
    cout << str;
    cout << "         ";
    for (int i = 2; i <= 21; i++) {
        if (str[i] == '3')
            cout << " ";
        else
            cout << "^";
    }
    cout << endl;

关于c++ - 在 C++ 中标记 double 损失的算法不会标记正确的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35545951/

相关文章:

c++以不止一种方式访问​​相同的元素

C++:获取 native dll依赖项而无需在进程中加载​​它

c++ - 为什么在我的程序中出现段错误?

c++ - 使用 std::prev(vector.begin()) 或 std::next(vector.begin(), -1) 像 some_container.rend() 作为反向哨兵是否安全?

c++ - C++0x lambda 和 operator()、闭包和仿函数之间的区别

c++ - 更紧密地打包位域

c++ - 线程如何运行循环直到加入?

c++ - 防止构造函数参数隐式转换为外部库类型

c++ - 命名空间中的静态变量与非静态变量

C++ 入门(第 5 版)和 C++14