【问题标题】:How to display precisely the decimal digits of a double in C++?如何在 C++ 中精确显示双精度数的十进制数字?
【发布时间】:2011-07-11 08:20:02
【问题描述】:

问题
给定两个整数 a, b, a

示例输入
3 7
345 800
112 990
53 122

样本输出
.428751
最后 6 位数字永远重复。
.43125
此扩展终止。
.113
最后 2 位数字永远重复。
.4344262295081967213114754098360655737704918032786885245901639
最后 60 位数字永远重复。

注意:这个问题来自 ProgFest 编程竞赛。

如果我们应用这三个定理,这个问题的算法并不难:

但是,我面临的问题是使用定理 1 中给出的递归公式计算 alpha 时的四舍五入。显示函数定义如下:

void displayFraction( int n, int d, int length ) {
    std::cout << ".";
    double alpha = static_cast<double>( n ) / d;
    for( int i = 1; i <= length; ++i ) {
        int c = std::floor( 10.0 * alpha );
        alpha = 10.0 * alpha - c;
        std::cout << c;
    }
}

我的输出是:

.4344 2622 9508 1967 3732 7807 5683 6291 4025 7835 3881 8359 3750 0000 0000 0

问题输出在哪里:

.4344 2622 9508 1967 2131 1475 4098 3606 5573 7704 9180 3278 6885 2459 0163 9

如您所见,直到第 16 位数字都是正确的。所以我的问题是,在这种特殊情况下执行计算时如何防止截断数字?有什么想法吗?

【问题讨论】:

  • 为什么投反对票?询问如何获得更好的精度来解决舍入误差似乎足够有效?
  • 我不明白为什么要投 2 票?至少给我一些 cmets,这样如果你不喜欢我的问题,我可以改进我的答案。
  • 您不能为此使用浮点数。 Double only has precision of about 16 digits.
  • @Asgeir:谢谢。有什么推荐的算法吗?
  • 定理1 算法。只是你对它的实现是不稳定的。请记住,整数数学中的除法会自动为您做一个底...

标签: c++ algorithm numbers double


【解决方案1】:

问题在于double 没有无限的精度,而是只能管理大约 16 位十进制数字。这就是你遇到麻烦的地方(很有趣,那个!),因为输入 double 中根本缺少信息。

您需要找到一种解决问题的方法,随着您从中获得更多数字,该方法将越来越接近答案。这意味着您需要更多地考虑定理 3,并且还需要根据有理数而不是浮点数编写代码。

【讨论】:

  • 谢谢。事实上,我应用定理 3 来找到前期长度和周期长度。但是,我想不出比浮点数更好的方式来表达它。
  • 真的吗?通过从理性的角度思考(并且仅使用普通整数),我解决了这个小难题,并在答案和响应之间的时间内将其与您的样本进行了核对。
  • 是的,我用定理3计算了前周期长度和周期长度,这是我displayFraction函数中的第三个参数。
【解决方案2】:

使用像 gmp 这样的 bignum 库。您可以将这么多信息打包成一个替身。

【讨论】:

  • 谢谢你,我还是不能在比赛期间使用任何外部库。
【解决方案3】:

我想你想要一个任意精度的库

类似于gnu MP bignum,虽然其他口味是available

【讨论】:

  • 谢谢,但是我不认为这个解决方案是可行的,因为这个问题来自一个仅限于标准 C++ 库的竞赛。
  • @Chan - 那么您要么必须聪明,要么必须重新发明轮子。 (gnu 项目是开源的——你可以看看他们是怎么做的)
  • 没错。我忘记了我可以使用他们的想法,因为它是开源的。再次感谢。
  • @Tom:那是用热核装置拍打苍蝇。它会起作用,但是对于这项任务来说它过度了。
  • 不确定它是否会起作用,实际上。 bignum 具有可数有限的精度(显然受可用内存的限制)。然而,正如示例所示,我们在这里处理的是没有有限表示的数字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-07
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 1970-01-01
  • 2018-02-28
相关资源
最近更新 更多