这更像是一个数学问题,但我认为这是一个要求的权利地点,它可能对某人有用。
以下是问题所在:
给出两个实数(rA和rB)找到最小的两个自然数(nA和nB),以便
rA / rB = nA / nB
对于那些不理解的人,问题是要求Irreducible fraction等于给定的实数。
当问题变成精确问题并且需要花费大量时间才能找到这些数字时(Ex:rA = 665.32
和rB = 875.1
),我甚至不知道是否存在这样的组合自然数来匹配问题。
我还实施了一些KeyPress
,这样您仍然可以检查nA
和nB
获得了多少,而无需让控制台满。
我提出的最有效方式是:
#include <iostream>
#include <windows.h> // just for GetAsyncKeyState()
int main()
{
/** The two natural numbers*/
unsigned long long nA=1;
unsigned long long nB=1;
/** The two real numbers*/
double rA;
double rB;
std::cin >> rA >> rB;
bool bPairFound = false;
/** The maximum of which nA or nB could go. */
/** If the value is set to 0, the algorithm will stop when nA or nB overflows */
#define NUMBER_LIMIT 0x0
if ((double) nA / nB == rA / rB) bPairFound = true;
while(bPairFound == false)
{
if ((double) nA / nB > rA / rB) nB++;
if ((double) nA / nB < rA / rB) nA++;
if ((double) nA / nB == rA / rB) bPairFound = true;
/** A little keyPress that will show you how much nA and nB got. */
/** Press space while the program is running. */
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
std::cout << "nA: "<<nA<<" nB: " << nB << " ---> "<< (double) nA / nB << " " << rA / rB << std::endl;
if (nA <= NUMBER_LIMIT || nB <= NUMBER_LIMIT) break;
}
if (bPairFound == false) std::cout << "No pair could be found in the set limit." << std::endl;
if (bPairFound == true) std::cout << "nA: "<<nA<<" nB: " << nB << std::endl;
return 0;
}
我的问题是:
我可以提高效率吗?
如何将比较的precision
设置为6位数?
有没有办法从一开始就确定unsigned long long
范围内是否有这样的一对?
编辑:以下是一些需要花费太多时间来解决或无法解决的例子。
rA = 1426.33
rB = 12.7
rA = 764342.33
rB = 98.02001
rA = 1.0001
rB = 1.010001
答案 0 :(得分:4)
除了精确问题(a)之外,你可以通过确保数字是整数然后用最大公约数除以它们来最有效地做到这一点。
具体来说,伪代码如:
tA = rA
tB = rB
while tA != int(tA) or tB != int(tB):
tA = tA * 10
tB = tB * 10
gcd = calcGcd(tA, tB)
nA = tA / gcd
nB = tB / gcd
在Stack Overflow上可以很容易地找到GCD实现。
事实上,这里one I prepared earlier: - )
(a)使用MPIR之类的任意精度算术库可以解决精度问题。
答案 1 :(得分:1)
我相信这会更有效率。
while(bPairFound == false)
{
double left=(double)nA*rB;
double right=(double)nB*rA;
if(left>right){
double quotient=left/right;
unsigned long long prevB=nB;
nB*=quotient;
if(prevB==nB){
nB++;
}
}else if(right>left){
int quotient=right/left;
unsigned long long prevA=nA;
nA*=quotient;
if(prevA==nA){
nA++;
}
}else{
bPairFound = true;
}
/** A little keyPress that will show you how much nA and nB got. */
/** Press space while the program is running. */
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
std::cout << "nA: "<<nA<<" nB: " << nB << " ---> "<< (double) nA / nB << " " << rA / rB << std::endl;
if (nA <= NUMBER_LIMIT || nB <= NUMBER_LIMIT) break;
}
由于您使用商增加数量,因此您将在早期过程中跳过相当多的步骤。 此实现也有更多的乘法和更少的划分。由于乘法费用较低,因此该方法效率更高。
我希望这会有所帮助。
编辑1: 我找到了一种向系统添加精度的方法
double left=(double)nA*rB;
double right=(double)nB*rA;
double quotient=left/right;
unsigned long long test;
if(quotient>=1){
test=quotient*1000000;
}else{
test=100000/quotient;
}
if(test==1000000){
bPairFound = true;
}else if(left>right){
unsigned long long prevB=nB;
nB*=quotient;
if(prevB==nB){
nB++;
}
}else if(right>left){
unsigned long long prevA=nA;
nA*=1/quotient;
if(prevA==nA){
nA++;
}
}