程序的反应奇怪

时间:2014-06-02 04:38:04

标签: c double assert

好的,我已经编写了一个将字符串转换为十进制的代码

然而,我不理解为什么当第一个断言正常时,它是第二个断言的核心倾销

如果我从函数中打印出返回它实际上返回它应该返回的内容但是由于某种原因断言失败

那么有人可以帮我理解断言在这里发生了什么吗?我不明白为什么会失败?

这是代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>

double myAtoD(char *);

int main(int argc, char *argv[]){

    char *k="0.1";
    char *l="0.141";
    double m,n;

   m = myAtoD(k);
   n = myAtoD(l);

   printf("%f\n",m);
   assert(m==0.1);

   printf("%f\n",n);
   assert(n==0.141);    

    return 0;
}

double myAtoD (char *message){

   int i=0;
   int prior=0;
   double num=0;

   while(message[i]!='.'){
      prior++;
      i++;
   }

   i=0;

   prior--;

   while(message[i]!='\0'){

      if(message[i]=='.')
      i++;

      printf("num is %f\nnew number to be added is %f\n\n",num, (message[i] - '0')*pow(10,prior));  
      num += (message[i] - '0')*pow(10,prior); 
      i++;
      prior--;
   }

   return num;
}    

2 个答案:

答案 0 :(得分:3)

您处理double精度问题。

计算机无法准确表示数字0.141,因此您必须检查它是否距离epsilon0.141

这是一个更好的断言。

   assert(abs(n-0.141) < DBL_EPSILON);

对于该常量,您需要将#include <float.h>放在源文件的顶部。

答案 1 :(得分:1)

myAtoD()的候选人改进计算稳定性更高。虽然它为“0.141”提供了一个很好的答案,但它可能也不是所有输入的最佳选择 - 需要做更多的测试。但@ merlin2011建议允许一点摆动空间是好的。

#include <ctype.h>
#include <math.h>

double myAtoD (const char *message){
  double num = 0.0;
  int dp = '.';
  size_t dpi;
  size_t i = 0;
  for (i=0; message[i]; i++) {
    int ch = (unsigned char) message[i];
    if (ch == dp) {
      dp = '\0';
      dpi = i;
      continue;
    }
    if (isdigit(ch)) {
      num = num*10 + (ch - '0');
    }
    else {
      break; // illegal character
    }
  }
  if (dp == '\0') {
    num /= pow10(i - dpi - 1);
  }
  return num;
}

[编辑]

非常将文本精确而强大地转换为double并非易事 - 最好是使用某种扩展精度。上述简单例程肯定会在2 ULP内提供答案。