如何将2个int值的百分比计算为表示百分比的int值(perthousands以获得更高的精度)?
背景/目的:使用没有FPU的处理器,浮点计算需要100倍的时间。
int x = 25;
int y = 75;
int resultPercentage; // desire is 250 which would mean 25.0 percent
resultPercentage = (x/(x+y))*1000; // used 1000 instead of 100 for accuracy
printf("Result= ");
printf(resultPercentage);
输出:
结果= 0
但我真正需要的是250美元。我不能使用任何浮点运算。
正常FPU计算示例:
int x = 25;
int y = 75;
int resultPercentage; // desire is 250 which would mean 25.0 percent
resultPercentage = (int)( ( ((double)x)/(double(x+y)) ) *1000); //Uses FPU slow
printf("Result= ");
printf(resultPercentage);
输出:
结果= 250
但是输出是以使用浮点计算为代价的。
7条答案
按热度按时间wljmcqd81#
resultPercentage = (x/(x+y))*1000;
不工作,因为在乘法*1000
发生之前,(x/(x+y))
可能是0
或1
。相反:对于
x/(x+y)
的四舍五入无符号整数计算,让a = x
和b = x+y
然后找到a/b
用途:对于舍入的无符号整数percent %,
a/b
的计算使用对于舍入的无符号整数permil ‰,
a/b
的计算使用对于舍入的无符号整数permyriad ‱,
a/b
的计算使用关于吃掉整数范围的担忧:使用更宽的整数数学(
unsigned long long
)进行乘法运算,可能还有x+y
。对于 signed
a, b
,它更复杂,因为b/2
需要匹配a/b
的符号。可以对一个衬垫进行编码:
b/-2
比-b/2
更好地防止b == INT_MIN
的UB。或者使用-(b/2)
。当然,替换
vaj7vani2#
你可以直接写
如果您关心正确的舍入,并且
如果你不这么做的话
你说的是“百分比”,但我注意到你乘以1000,结果是千分之一。如果这就是你的意思,那么当然你需要将乘法因子分别更改为10000和1000。
此外,使用整数会显著减少要执行计算的值的有效范围。如果您强制中间结果为更长的类型,特别是(有符号或无符号)
long long
,则可以稍微扩大:应该做的伎俩(由于整数提升)。
nbnkbykc3#
使用长除法的解决方案
现在来看看纸笔的答案不确定这是否会比你的处理器内置的浮点运算更快,但这是一个有趣的事情(也许可以改进)。这是一个长除法的实现(还记得吗?)-原则上它是“无限精确的”,有点像BigDecimal数学-实际上它是有限的,因为为字符串分配了有限的空间(您可以使用
malloc/free
来更改)。如果你在处理器上的(代码)空间上有问题(以及缺乏专用的浮点单元),那么这绝对不是要走的路;我还假设 all 除法(偶数)会很慢,并且只使用乘法,加法和减法。最后的好处-结果以字符串的形式输出,省去了以后单独进行
printf
样式转换的需要。有许多可以想象的方法来加速这一点;现在,看看你如何用有限精度的整数来解决这个问题,还能得到一个“非常好”的答案,这很有趣。顺便说一句,根据我的行人计时代码,结果比divide-and-sprintf例程快(这很令人满意)。几乎可以肯定的是,转换成一串数字是“几乎免费”的(如果你想一下通常是如何完成的,它需要大量的除法/模数学...)。EDIT在当前形式下,此代码甚至考虑了四舍五入(计算一个额外的数字,然后进行必要的调整)。一个警告:它只对正整数有效。
玩一玩告诉我你喜不喜欢!
结果(未启用优化):
bqjvbblv4#
你为什么不用
8hhllhi25#
稍微改变一下表情就能达到目的。就像这个例子:
result =(x*1000)/(x+y);应该能胜任
sshcrbum6#
试试这个:
j5fpnvbx7#
如果你的要求只是找到一个值,它给出了两个数字之间的关系,那么不用1000,你可以用1024
与1000相乘需要几个周期,但您可以使用
result =(x<<10)/(x+y);
乘法只需要10个周期。即使结果与1000也不会有很大的变化。找到百分比后,您可能会使用所获得的百分比进行一些阈值处理,只需更改比较值即可。
假设您正在使用
代替使用
通过这种方式,您可以找到对应的Map值并将其替换。如果你是非常严格的周期和准确性,然后去保存查找表转换为0-1024到0-1000,但它使用了大量的RAM