C ++函数中出现奇怪的舍入

时间:2012-10-12 00:39:27

标签: c++ floating-point

我正在用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;
}

4 个答案:

答案 0 :(得分:1)

您无法在计算机中精确表示实数(双精度) - 它们需要近似。如果您将功能更改为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 :(得分:0)

这是因为实数的分数分量是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

答案 2 :(得分:0)

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

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

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

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

答案 3 :(得分:0)

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

  • 该数字作为double传递(具体地说,是64位IEEE-754二进制浮点值),并且您希望找到传递的精确值的十进制表示中的最大数字。在这种情况下,用户millimoose建议的解决方案将起作用(假设使用的asprintfsnprintf函数具有良好的质量,因此它不会产生舍入错误,从而无法生成正确的舍入输出)
  • 该数字作为double传递,但旨在表示一个数字,该数字可以精确表示为具有已知位数的十进制数字。在这种情况下,用户millimoose建议的解决方案再次起作用,格式规范被更改为将double转换为带有所需位数的十进制(例如,而不是“%.64f”,您可以使用“%.6f”)
  • 更改该函数以另一种方式传递数字,例如使用十进制浮点数,缩放整数或包含十进制数字的字符串。

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