如何重现 C++双舍入问题

发布于 2024-10-23 20:09:40 字数 142 浏览 2 评论 0原文

浮点精度在 C++ 中受到限制,对于新手程序员来说,在舍入值时常常会造成麻烦。

在教授学生时,演示浮点精度数字舍入问题通常很有用。您知道哪些可能的方法可以在所有 C++ 编译器上一致地演示此类舍入问题?

Floating point precision is limited in C++ and for novice programmers that often causes trouble when rounding values.

When teaching students it is often useful to demonstrate the floating point precision number rounding issue. What possible ways do you know to demonstrate such rounding issue consistently on all C++ compilers?

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

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

发布评论

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

评论(5

本王不退位尔等都是臣 2024-10-30 20:09:40

您可以使用以下示例:

#include <iostream>
using namespace std;

int main() {
  for (double d = 0.0; d != 1.0; d += 0.1)
    cout << d << "\n";
}

程序永远不会终止,因为 d 永远不等于 1。

You can use this example:

#include <iostream>
using namespace std;

int main() {
  for (double d = 0.0; d != 1.0; d += 0.1)
    cout << d << "\n";
}

The program will never terminate as d never equals 1.

森林很绿却致人迷途 2024-10-30 20:09:40

首先,我们应该注意到,在IEEE754浮点中,1.50.52.0都是精确表示的。因此,在这个具体示例中,1.5 永远不会是 1.499999999999

话虽如此,我认为要做的事情是让你的学生接触到不能完全可表示的数字。比如说,1.1

这是一个示例程序:

#include <iostream>
#include <iomanip>

int main() {
   std::cout << std::setprecision(30);
   double d1(1.1);
   std::cout << d1 << "\n";
   double d2(11);
   double eps = d2/10 - d1;
   std::cout << d2 << "\n";
   std::cout << eps << "\n";
   bool equal = (d1 == d2);
   std::cout << equal << "\n";
}

也许您可以引导他们完成这个程序,请小心地说 d1d2大约等于 1.1 。

对于高级学生,您可以通过派系二进制算术来了解为什么 1/2 可以表示,但 1/10 则不能。

编辑:我认为阐明这一点的方法是将重复的十进制分数与重复的二进制分数进行比较。以十进制显示您的学生 1/7。在黑板上做长除法。指出您无法使用有限的资源精确地写出1/7。然后,要么向他们展示如何将 1/10 写为二进制分数,要么只是告诉他们您无法使用有限的资源写下它。

指出浮点数是有限的(32 位),双精度数是有限的(64 位)。也许引入鸽子原理并说你不能用有限的字长表示无限集(像所有有理数一样)。

无论您尝试什么,请返回此处报告并让我们知道它是如何工作的。

First, we should note that, in IEEE754 floating point, 1.5, 0.5, and 2.0 are all exactly represented. So, in this specific example, 1.5 will never be 1.499999999999.

Having said that, I think the thing to do is to expose your students to numbers are not exactly representable. Say, 1.1.

Here is a sample program:

#include <iostream>
#include <iomanip>

int main() {
   std::cout << std::setprecision(30);
   double d1(1.1);
   std::cout << d1 << "\n";
   double d2(11);
   double eps = d2/10 - d1;
   std::cout << d2 << "\n";
   std::cout << eps << "\n";
   bool equal = (d1 == d2);
   std::cout << equal << "\n";
}

Perhaps you can walk them through this program, being careful to say that d1 and d2 are both approximately equal to 1.1.

For advanced students, you can go through factional binary arithmetic and see why 1/2 is representable, but 1/10 is not.

EDIT: I think the way to bring the point home is to compare repeating decimal fractions with repeating binary fractions. Show your students 1/7 in decimal. Do the long division on the board. Point out that you cannot write 1/7 down exactly using finite resources. Then, either show them how to write 1/10 as a binary fraction, or just tell them that you can't write down it either using finite resources.

Point out that floats are finite (32 bits) and doubles are finite (64 bits). Maybe introduce pigeonhole principal and say that you can't represent an infinite set (like all rationals) in a finite word length.

Whatever you try, please report back here and let us know how it works.

生生漫 2024-10-30 20:09:40

我喜欢下面的例子:

double sum = 0;
for (int i = 0; i < 10; i++, sum += 0.1);
cout << "sum = " << sum << endl;
cout << "(sum == 1.) is " << boolalpha << (sum == 1.)  << endl;

输出如下:

sum = 1
(sum == 1.) is false

矛盾的原因是浮点计算。

I like the following example:

double sum = 0;
for (int i = 0; i < 10; i++, sum += 0.1);
cout << "sum = " << sum << endl;
cout << "(sum == 1.) is " << boolalpha << (sum == 1.)  << endl;

The output follows:

sum = 1
(sum == 1.) is false

The cause of contradiction is floating point calculations.

極樂鬼 2024-10-30 20:09:40
printf("%.20f\n",0.1f);

或者

cout << fixed << setprecision(20) << 0.1f << endl;

:)

printf("%.20f\n",0.1f);

or

cout << fixed << setprecision(20) << 0.1f << endl;

:)

被翻牌 2024-10-30 20:09:40

试试这个例子:

#include <cstdio>
int main() {
    printf("%.20lf rounded to two decimal places is %.2lf\n", 0.075, 0.075);
    return 0;
}

它打印出

0.07499999999999999722 rounded to two decimal places is 0.07

note that 0.075 四舍五入到小数点后两位应该是 0.08,而不是我们在输出中看到的 0.07。这个例子清楚地展示了双重舍入问题

Try this example:

#include <cstdio>
int main() {
    printf("%.20lf rounded to two decimal places is %.2lf\n", 0.075, 0.075);
    return 0;
}

which prints

0.07499999999999999722 rounded to two decimal places is 0.07

note that 0.075 rounded to two decimal places should be 0.08, not 0.07 as we see in the output. This example clearly demonstrates double rounding issue

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