说,我有一些整数n,并希望根据某种比例将其细分为另外两个整数。我有一些方法,我问自己它是否有效。
例如:20%与70%的比例应细分为14,6。
显而易见的解决方案是:
int n = 20;
double ratio = .7;
int n1 = static_cast<int>(n * ratio);
int n2 = static_cast<int>(n * (1 - ratio));
然而,由于演员总是floor
,我通常会低估我的结果。如果我使用std::round
,仍有一些情况无效。例如,如果第一个小数位是5,则两个数字都将向上舍入。
有些同事建议:Ceil是第一个,第二个是第二个。在我的大多数测试中,这都有效:
1)它是否真的一直有效,还考虑到在乘法数字中自然出现的可能的舍入误差?我的想法:20 * .7可能是14,而20 * .3可能是5.999999。所以,我的总和可能是14 + 5 = 19.这只是我的猜测,但是,我不知道这些结果是否可以发生(否则答案就是这种舍入命题不起作用)
2)即使它确实有效......为什么?
(我记得我可以用n *比率计算数字1并用n - n *比率计算数字2,但我仍然对这个问题的答案感兴趣)
答案 0 :(得分:2)
这个怎么样?
int n = 20;
double ratio = .7;
int n1 = static_cast<int>(n * ratio);
int n2 = n - n1;
答案 1 :(得分:1)
以下示例证实了您的怀疑,并表明ceil + floor方法并不总是有效。它是由计算机上浮点数的有限精度引起的:
#include <iostream>
#include <cmath>
int main() {
int n = 10;
double ratio = 0.7;
int n1 = static_cast<int>(floor(n * ratio));
int n2 = static_cast<int>(ceil(n * (1.0 - ratio)));
std::cout << n1 << " " << n2 << std::endl;
}
输出:
7 4
7 + 4是11,所以它错了。
答案 2 :(得分:0)
你的解决方案并不总是有效,比率为77%,你会得到15和4(See on coliru)。
欢迎来到数值分析领域。
首先,您的计算机无法始终完美地存储浮动数字。正如您在示例中所看到的,.77
存储为0.77000000000000001776
(这是一个以2的幂的总和来表示数字的方法。)
进行浮点计算时,总是会有精度损失。您可以使用std::numeric_limits<double>::epsilon()
获得此精度。
此外,从浮点数转换为整数时,您仍然会获得更多的精度损失,在您的情况下,差异足以让您得到不连贯的结果。
@ToniBig提供的解决方案和你的最后一句话具有“隐藏”这种损失并保持连贯数据的优势。