如何在 C++ 中精确显示 double 的十进制数字?

发布于 2024-11-19 13:10:26 字数 1281 浏览 0 评论 0原文

问题
给定两个整数 a, b, a < b.显示其十进制展开式。您将打印给定整数商的小数​​扩展,在扩展终止时或在重复模式第一次重复自身时停止。如果有重复模式,您会说出重复模式中有多少位数字。

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

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

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

如果我们应用这三个定理,这个问题的算法并不困难: 在此处输入图像描述

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

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 位数字都是正确的。所以我的问题是,在这种特殊情况下执行计算时如何防止截断数字?有什么想法吗?

Problem
Given two integers a, b, a < b. Display its decimal expansion. You will print the decimal expansion of integer quotient given, stopping just as the expansion terminates or just as the repeating pattern is to repeat itself for the first time. If there is a repeating pattern, you will say how many of digits are in the repeating pattern.

Sample Input
3 7
345 800
112 990
53 122

Sample Output
.428751
The last 6 digits repeat forever.
.43125
This expansion terminates.
.113
The last 2 digits repeat forever.
.4344262295081967213114754098360655737704918032786885245901639
The last 60 digits repeat forever.

Note: This problem is original from the ProgFest programming contest.

The algorithm for this problem is not difficult if we apply these three theorems:
enter image description here

However, the problem that I'm facing is the rounding-off when calculating alpha using the recursive formula given in Theorem 1. The display function is defined as follows:

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;
    }
}

And my output was:

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

where the problem output was:

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

As you can see, it was correct up to the 16th digit. So my question is, how I can prevent the truncating digits when performing the calculation in this particular situation? Any idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尸血腥色 2024-11-26 13:10:26

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

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

The problem is that double doesn't have infinite amounts of precision, but instead can only manage about 16 decimal digits worth. Which is where you run into trouble (funny, that!) as the fundamental lack of information in the input double shows up.

You need to find a way of tackling the problem that will keep getting closer to the answer as you get more digits out of it. That means you'll need to think much more about Theorem 3, and also work on writing your code in terms of rationals instead of floating point.

孤千羽 2024-11-26 13:10:26

使用 bignum 库,例如 gmp。双打可以容纳的信息有限。

Use a bignum library like gmp. There's only so much information you can pack into a double.

初心未许 2024-11-26 13:10:26

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

,比如 gnu MP bignum,尽管其他风格是 可用

I think you want an arbitrary precision library

Something like the gnu MP bignum, although other flavours are available

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文