在C++函数中发生奇怪的舍入

Weird Rounding Occurs in C++ Function

本文关键字:舍入 C++ 函数      更新时间:2023-10-16

我正在用c++编写一个函数,该函数应该查找传递的数字(inputValue)中的最大个位数。例如,.345的答案是5。然而,过了一段时间,程序将inputValue更改为.3449行的值(然后将最大数字设置为9)。我不知道为什么会发生这种事。如果能为解决这个问题提供任何帮助,我们将不胜感激。

这是我的.hpp文件中的函数

void LargeInput(const double inputValue)
//Function to find the largest value of the input
{
int tempMax = 0,//Value that the temporary max number is in loop
digit = 0,//Value of numbers after the decimal place
test = 0,
powerOten = 10;//Number multiplied by so that the next digit can be checked
double number = inputValue;//A variable that can be changed in the function
cout << "The number is still " << number << endl;
for (int k = 1; k <= 6; k++)
{
test = (number*powerOten);
cout << "test: " << test << endl;
digit = test % 10;
cout << (static_cast<int>(number*powerOten)) << endl;
if (tempMax < digit)
tempMax = digit;
powerOten *= 10;
}
return;
}

您不能在计算机中精确地表示实数(双精度)-它们需要近似。如果你改变你的函数来处理long或int,就不会有任何不准确的地方。对于你的问题来说,这似乎很自然,你只看数字,而不是数字,所以.345可以是345,得到同样的结果。

试试这个:

int get_largest_digit(int n) {
int largest = 0;
while (n > 0) {
int x = n % 10;
if (x > largest) largest = x;
n /= 10;
}
return largest;
}    

这是因为实数的分数分量是1/2^n的形式。因此,你可以获得非常接近你想要的值,但你永远无法获得像1/3这样的精确值。

通常使用整数并进行转换(如1000=1),因此如果您的数字为1333,则使用printf("%d.%d", 1333/1000, 1333 % 1000)打印1.333。

顺便说一下,第一句话是对浮点数实际表示方式的简化。欲了解更多信息,请查看;http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding

不幸的是,浮点数就是这样工作的。问题的核心是存在无限多个浮点数。更具体地说,在0.1和0.2之间有无限多个值,在0.01和0.02之间有无穷多个值。然而,计算机有有限数量的位来表示浮点数(双精度数为64位)。因此,大多数浮点数都必须近似。在任何浮点运算之后,处理器必须将结果四舍五入到它可以用64位表示的值。

浮点数的另一个特性是,随着数字越来越大,它们的精度越来越低。这是因为相同的64位必须能够表示非常大的数字(1000000000)和非常小的数字(000000000001)。因此,使用较大的数字时,舍入误差会变大。

这里的另一个问题是,您正在从浮点转换为整数。这会引入更多的舍入误差。似乎当(0.345*10000)转换为整数时,结果更接近3449,而不是3450。

我建议你不要把数字转换成整数。用浮点数编写程序。不能对浮点数字使用模(%)运算符来获取数字的值。而是使用C数学库(cmath.h)中的fmod函数

正如其他答案所示,二进制浮点无法准确表示大多数十进制数字。因此,你必须重新考虑你的问题陈述。一些替代方案是:

  • 数字以双精度(特别是64位IEEE-754二进制浮点值)传递,您希望在传递的确切值的十进制表示中找到最大的数字。在这种情况下,用户millimouse建议的解决方案将起作用(前提是所使用的asprintfsnprintf函数质量良好,这样它就不会产生舍入误差,从而无法产生正确的舍入输出)
  • 该数字是以双精度传递的,但其目的是表示一个可以精确表示为具有已知位数的十进制数字的数字。在这种情况下,用户millimouse建议的解决方案再次奏效,修改了格式规范,将双精度转换为所需位数的十进制(例如,可以使用"%.64f"而不是"%.6f")
  • 函数被更改为以另一种方式传递数字,例如十进制浮点、缩放整数或包含十进制数字的字符串

一旦您澄清了问题语句,考虑如何使用浮点运算来解决它可能会很有趣,而不是为格式化输出调用库函数。这可能具有教学价值(顺便说一句,可能会产生一个比调用库函数在计算上更高效的解决方案)。