给出2个数字,A <= B
例如A = 9
和B = 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
的使用相关的某些精度会丢失。
有没有办法避免在我的情况下失去精确度?
答案 0 :(得分:10)
似乎您正在寻找的公式是
int result = 10000 - (A*10000+B/2)/B;
这个想法是用整数进行所有计算并推迟除法。
在执行除法之前添加一半的分母(否则你会在除法中截断,因此因为100%-x而得到上舍入)
例如,A = 9且B = 11,百分比为18.18181818 ......并且舍入18.18,没有舍入的计算将得到1819而不是预期结果1818。
请注意,计算是以整数形式完成的,因此对于A
和B
的较大值存在溢出的风险。例如,如果int
是32位,那么A
可以达到大约200000,然后在计算A*10000
时冒着溢出的风险。
在公式中使用A*10000LL
代替A*10000
会以一定的速度进行交易,以将限制提高到更大的值。
答案 1 :(得分:2)
当然,浮点数可能会出现精确损失。您应该使用固定点数作为@ 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
,则可以保证比预期更多。现在,当您将此值转换为整数时,您将得到预期的答案。 (地板或ceil值取决于方程结果的小数部分是高于还是低于0.5)
答案 2 :(得分:0)
我试过
float floatpercent = (((1 - (double)A/B) / 0.01)) * 100;
int percentage = (int) floatpercent;
cout<< percentage;
显示1000
我怀疑将自动转换为int的精度损失作为代码的根本问题。
答案 3 :(得分:0)
[我在对原始问题的评论中提到了这一点,但我发布了它作为答案。]
核心问题是,当表示10的简单分数时,您使用的表达形式会放大不可避免的浮点精度损失。
你的表达(暂时删除了强制转换,使用标准优先级来避免一些parens)
((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
我已经对此进行了测试,并且可靠地运行。正如其他人所指出的那样,使用双打而不是花车通常会更好,因为它们的额外精度使它们不太容易(但不能免疫)这种困难。