代码之家  ›  专栏  ›  技术社区  ›  Alessandro Jacopson

如果一个实数可以用双精度数来精确表示,我该如何编写一个返回true的C++函数?

  •  5
  • Alessandro Jacopson  · 技术社区  · 17 年前

    如果一个实数可以用双精度数来精确表示,我该如何编写一个返回true的C++函数?

    bool isRepresentable( const char* realNumber )
    {
       bool answer = false;
       // what goes here?
       return answer;
    }
    

    简单测试:

    assert( true==isRepresentable( "0.5" ) );
    assert( false==isRepresentable( "0.1" ) );
    
    6 回复  |  直到 17 年前
        1
  •  5
  •   Alexei    17 年前

    将数字解析为a+N/(10^k)的形式,其中a和N是整数,k是小数位数。

    示例:12.0345->12+345/10^4,a=12,N=345,k=4

    现在,10^k=(2*5)^k=2^k*5^k

    你可以将你的数字表示为精确的二进制分数,如果并且只有当你去掉分母中的5^k项时。

    结果将检查(N mod 5^k)==0

        2
  •  5
  •   Mike G.    17 年前

    神圣的家庭作业,蝙蝠侠! :)

    有趣的是,你不能简单地做(atof|strtod|sscanf)->sprintf循环并检查是否恢复了原始字符串。例如,许多平台上的sprintf检测到“尽可能接近0.1”的双精度值,并将其打印为0.1,即使0.1不能精确表示。

    #include <stdio.h>
    
    int main() {
        printf("%llx = %f\n",0.1,0.1);
    }
    

    打印: 3fb9999999999a=0.100000

    在我的系统上。

    真正的答案可能需要解析出双精度,将其转换为精确的分数表示(0.1=1/10),然后确保atof转换乘以分母等于分子。

    我想。

        3
  •  1
  •   schnaader    17 年前

    这是我的版本。sprintf将0.5转换为0.50000,必须删除末尾的零。

    EDIT:必须重写才能正确处理以0结尾的没有小数点的数字(如12300)。

    bool isRepresentable( const char* realNumber )
    {
       bool answer = false;
    
       double dVar = atof(realNumber);
       char check[20];
       sprintf(check, "%f", dVar);
    
       // Remove zeros at end - TODO: Only do if decimal point in string
       for (int i = strlen(check) - 1; i >= 0; i--) {
         if (check[i] != '0') break;
         check[i] = 0;
       }
    
       answer =  (strcmp(realNumber, check) == 0);
    
       return answer;
    }
    
        4
  •  0
  •   community wiki Richard Poole    17 年前

    这应该能奏效:

    bool isRepresentable(const char *realNumber)
    {
        double value = strtod(realNumber, NULL);
    
        char test[20];
        sprintf(test, "%f", value);
    
        return strcmp(realNumber, test) == 0;
    }
    

    可能最好使用sprintf的“安全”版本来防止潜在的缓冲区溢出(在这种情况下是否有可能?)

        5
  •  0
  •   Trap    17 年前

    我会将字符串转换为它的数字位表示(位数组或long),然后将字符串转换成double,看看它们是否匹配。

        6
  •  -2
  •   Treb    17 年前

    将字符串转换为作用域大于double的浮点数。将其转换为双倍,看看它们是否匹配。