如何在C语言中使用银行家舍入法将double类型的数字四舍五入为int类型。

6
我想编写一个函数,使用银行家舍入法(四舍六入五成双:http://zh.wikipedia.org/wiki/四舍六入五成双)将double舍入为int,例如:
int RoundToInt(double x);

我该怎么做?

更新:

我能得到的最好结果是这样的:

int RoundToInt(double x)
{
  int s = (int)x;
  double t = fabs(x - s);

  if ((t < 0.5) || (t == 0.5 && s % 2 == 0))
  {
    return s;
  }
  else
  {
    if (x < 0)
    {
      return s - 1;
    }
    else
    {
      return s + 1;
    }
  }
}

但这样做太慢了,而且我也不确定它是否准确。

是否有一种快速而准确的方法来做到这一点?


StackOverflow不是你的个人研究助手。 - Adam Casey
@AdamCasey 我需要解决这个问题,但我自己无法解决,所以来这里寻求帮助。或者我的问题很愚蠢吗? - EFanZh
你的需求和问题并不是问题所在。请查看我评论中的链接;你需要展示出:a. 在研究问题时付出了一些努力,b. 尝试自己编写了一些代码,c. 当代码运行失败时尝试进行调试。 - Adam Casey
@AdamCasey 我已经做了研究,但我认为这并没有帮助。我的代码运行缓慢且笨拙,我不确定它是否准确。这是我所能做到的最好程度。 - EFanZh
这就是一个好问题应该看起来的样子。我把我的踩转成了赞! - Adam Casey
2个回答

5

使用标准的lrint函数;在默认的舍入模式下,它会精确地给出您需要的结果。


1
lrint遵守当前的舍入模式。默认的舍入模式是四舍五入,也被称为偶数舍入或“银行家”舍入。 - R.. GitHub STOP HELPING ICE
我正在使用VC++,它不支持lrint - EFanZh
它支持 rint 吗?使用 rint 然后将结果转换为整数类型(或通过赋值隐式转换)应该同样有效。 - R.. GitHub STOP HELPING ICE
依赖于全局状态的东西是一个可怕的想法。例如,一个库可能会修改舍入模式,甚至在将其转换为整数时,旧版本的Visual Studio也被知道暂时修改它。如果这发生在另一个线程中,而此代码正在运行,则可能会得到错误的结果。 - Arthur Tacca
@ArthurTacca:舍入模式是线程本地状态,而不是全局状态。 - R.. GitHub STOP HELPING ICE
显示剩余4条评论

1
double decimal = x % 1;
if(decimal < 0.5) return (int)x;
if(decimal > 0.5) return (int)x + 1;
return (int)x + ((int)x % 2 == 1 ? 1 : 0);

这就是银行家舍入的定义。“完美的一半四舍五入到最接近的偶数。”如果你不确保将7/2舍入为4,那就不是银行家舍入。 - David Schwartz
1
我在谈论你的说法,即应将2.4999999993视为2.5;我看不出任何依据。此外,你声称5.0/2.0可能是2.4999999993是无稽之谈;5.0/2.0始终是精确的。 - R.. GitHub STOP HELPING ICE
这就是为什么我说“如果”的原因。我试图用一个简单的例子来展示问题所在。如果其他函数四舍五入,以便您看不到精确的一半,那么银行家舍入函数将会出错。如果一堆分数被加在一起,也可能发生同样的事情。 - David Schwartz
银行家舍入的目的是确保如果精确结果恰好为一半偶数,则将结果四舍五入到最近的整数。该函数不会这样做,因为它是根据四舍五入后的结果是否为一半偶数来操作的,而不是根据精确结果。 (如何修复取决于上下文,并且通常涉及在检查0.5时使用某些增量 - 这将在许多情况下无法执行银行家舍入。) - David Schwartz
1
双重舍入并不是解决问题的方法;对于它“修复”的每个案例,都有同样多的案例会导致舍入方向错误。故事的寓意是浮点数永远不是货币的有效格式。 - R.. GitHub STOP HELPING ICE
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接