C++ 加速双有理数转换

C++ 加速双有理数转换,c++,rational-numbers,C++,Rational Numbers,我编写了一个相对简单的代码,将double转换为有理数。代码是有效的,它保证找到给定双精度的最小有理数;然而,它比一月份的糖蜜慢。我花了一天时间尝试各种方法来改进它,但都没有用。有没有办法加快速度?实际的算法在while循环中,只有8行 #include <iostream> #include <iomanip> using namespace std; void rationalize(double number) { bool isNegative = false;

我编写了一个相对简单的代码,将double转换为有理数。代码是有效的,它保证找到给定双精度的最小有理数;然而,它比一月份的糖蜜慢。我花了一天时间尝试各种方法来改进它,但都没有用。有没有办法加快速度?实际的算法在while循环中,只有8行

#include <iostream>
#include <iomanip>
using namespace std;

void rationalize(double number) {
bool isNegative = false; 

if (number == 0.0) { 
    cout << number << ": " << "0/1" << endl; 
    return; 
}   
if (abs(number) < (1.0 / (double) LONG_MAX)) {
    cout << number << " is to small " << endl; 
    return; 
}
if (abs(number) > (double)LONG_MAX) {
    cout << number << " is to big " << endl; 
    return;
}
if (number < 0) {
    isNegative = true;  
    number *= -1; 
}
long numerator = 1;         // at this point, both numerator 
long denominator = 1;       // and denominator must be >= 1
double diff = 1.0 - number; 

//while ((abs(diff) > DBL_EPSILON)  && (numerator >  0) && (denominator > 0)) { 
while ((abs(diff) > FLT_MIN)  && (numerator >  0) && (denominator > 0)) {       
    if (diff > 0) {
        denominator++;
    } else {
        numerator++; 
    }
    diff = ((double) numerator / (double) denominator) - number; 
}   // end while 

if ((numerator <=  0) || (denominator <= 0)) {
    cout << "\nInteger overflow!" << endl; 
    cout << "diff: " << diff <<  ", numerator: " << numerator << "  denominator: " << denominator << endl; 
    return; 
}

if (diff == 0.0) {
    cout << "      Exact result: "; 
    cout << (isNegative ? -numerator : numerator) << "/" << denominator << endl; 
} else if (diff <= FLT_MIN) {
    cout << "Approximate result: "; 
    cout << (isNegative ? -numerator : numerator) << "/" << denominator << endl; 
} else {
    cout << "You've got bugs...  :( " << endl; 
    cout << "diff: " << diff << ",   num:" << numerator << ",  den: " << denominator << endl; 
}
#包括
#包括
使用名称空间std;
无效合理化(双倍数字){
bool为阴性=假;
如果(数字==0.0){

您可以使用GMP进行以下操作:

mpq_t op;
mpq_set_d(op, number);
mpq_canonicalize(op);
long numer = mpz_get_si(mpq_numref(op));
long denom = mpz_get_si(mpq_denref(op));

Ref:

我想你应该在这里使用GCD。你不能在
double
中存储大多数有理值,因此你的解决方案将不起作用。所有的double实际上都是形式为
有效位/2^(-exp)
a)我想将double转换为有理数,而不是相反,b)根据我的代码,范围限制为:[1/(2^31-1)…2^31-1]c)IEEE-754双工仅代表有限数量的双工d)它不一定必须精确,如(diff
FLT_MIN
?这是用于
float
而不是
double
。这只是一个非常小的数字,如果它以FLT开头实际上并不重要,因为double具有更高的分辨率。在我的编译中,DBL_EPSILON=2.2204460492503131e-016,FLT_MIN=1.175494351e-38,DBL_MIN=2.225073858585072014e-308供参考r、 为什么要在头文件中已经定义了很多值的情况下定义一些非常小的值呢?顺便说一句,当使用DBL_EPSILON时,我通常会得到不太精确的结果。基于几十个随机数的运行,(abs(diff)>FLT_MIN)的结果与(diff!=0.0)的结果相同。
mpq_t op;
mpq_set_d(op, number);
mpq_canonicalize(op);
long numer = mpz_get_si(mpq_numref(op));
long denom = mpz_get_si(mpq_denref(op));