c++中的精确百分比

Accurate percentage in C++

本文关键字:百分比 c++      更新时间:2023-10-16

给定2个数字,其中A <= B说例如A = 9B = 10,我试图得到A与b相比有多小的百分比。我需要将百分比作为int,例如,如果结果是10.00%,int应该是1000。

下面是我的代码:
int A = 9;
int B = 10;
int percentage = (((1 - (double)A/B) / 0.01)) * 100;

我的代码返回999而不是1000。使用double会丢失一些精度

是否有一种方法可以避免在我的情况下失去精度?

似乎你正在寻找的公式是

int result = 10000 - (A*10000+B/2)/B;

其思想是用整数和延迟除法来完成所有的计算。

要进行四舍五入,在执行除法之前要加上分母的一半(否则在除法中会被截断,从而由于100%-x而导致四舍五入)

例如,A=9, B=11,百分比为18.18181818…然后将18.18舍入,不舍入的计算将得到1819,而不是预期的结果1818。

请注意,计算全部以整数进行,因此AB的大值有溢出的风险。例如,如果int是32位,那么A可以在计算A*10000时冒溢出风险之前高达200000左右。

在公式中使用A*10000LL而不是A*10000将以一定的速度将限制提高到更大的值

当然,浮点数可能存在精度损失。要么你应该使用固定点数字作为@6502回答,要么在结果中添加偏见以获得预期的答案。你最好做

assert(B != 0);
int percentage = ((A<0) == (B<0) ? 0.5 : -0.5) + (((1 - (double)A/B) / 0.01)) * 100;

由于精度损失,(((1 - (double)A/B) / 0.01)) * 100的结果可能略低于或高于预期。如果您添加了额外的0.5,那么它肯定会比预期的稍微多一些。现在,当你将这个值转换为整数时,你会得到预期的答案。(下限或上限值取决于方程结果的小数部分是大于还是小于0.5)

我试过了

float floatpercent = (((1 - (double)A/B) / 0.01)) * 100;
int percentage = (int) floatpercent;
cout<< percentage;

显示1000

我怀疑自动转换为int时的精度损失是您代码的根本问题。

[我在对最初问题的评论中提到了这一点,但我想我应该把它作为一个答案贴出来。]

核心问题是,当表示10的简单分数时,您使用的表达式形式放大了不可避免的浮点精度损失。

你的表达式(现在去掉了强制转换,使用标准优先级来避免一些父级)

((1 - A/B) / 0.01) * 100

是一种相当复杂的表示你想要的东西的方式,尽管它在代数上是正确的。不幸的是,浮点数只能精确地表示1/2、1/4、1/8等数字、它们的倍数以及它们的和。特别是,9/10、1/10或1/100都没有精确的表示。

上面的表达式两次引入了这些错误:第一次是在计算A/B时,第二次是在除以0.01时。然后将这两个不精确的值相除,这进一步放大了固有的误差。

最直接的方式(同样不需要强制类型转换)是

((B-A) / B) * 10000

这产生了正确的答案,我认为,比原文更容易阅读。完全正确的C形式是

((B - A) / (double)B) * 10000

我已经测试过了,它工作可靠。正如其他人所指出的那样,通常使用双精度数而不是浮点数更好,因为它们的额外精度使它们不太容易(但并非完全免疫)出现这种困难。