开发者

Input from file in C, data types

thanks in advance for taking the time to read through my question...

/* Binary search for use with Gen_window.comp */
#include <stdio.h>

int main()
{
  char line[1000];
  double sig, E;

  FILE *fp, *fopen();
  fp = fopen("sig_data", "r");

  if (fp==NULL){
        printf("Error opening file!");
  }
  else {
        printf("Processing file...");
  }



  while( (fgets(line, 25, fp) != NULL) ){
        fscanf(fp, "%lf\t%lf", &E, &sig);
        printf开发者_运维问答("\nThe energy is: %lf eV\nThe corresponding cross section is: %lf barns\n",E, sig);
  }

}

Numbers in the file are of the format X.XXXXXX+X or X.XXXXXX-X accordingly. Does C have a way to specify this as input? Is it a bother that there is no 'e'. I cannot find any documentation that tells about inputing exponential, only returning exponential...

I do not need it to print that exact format, any other exponential format would be fine.

I realize there should be some specifiers and precision in my %lf, or maybe it should be %e, but I have tried everything that makes sense to me, so I am basically leaving it blank.

Thanks for your help.


Jester and plinth's answers are broadly correct, but flawed. There is indeed no way to make the stock number-parsing routines (*scanf, atof, strtod) process a number in the format you have. However, the suggested workarounds are bad. First off, it is my personal opinion that *scanf and ato* should never be used, due to their horrifically bad handling of malformed input. More seriously, decimal-to-float conversion requires extended-precision arithmetic to avoid loss of accuracy. strtod (which is the routine that should be used for this problem) can be relied on to do this correctly, but processing the mantissa and exponent separately and then combining them in the obvious fashion does not. You need an intermediate type bigger than double and you need powers of 10 that are accurately computed all the way to the last bit, which pow doesn't reliably give you.

So my recommendation is to rewrite each line on the fly to make it acceptable to strtod.

  1. Read each line into a pair of string buffers, splitting at \t. I would do this by hand, but you can probably get away with using fscanf as long as you only use %s formats. Make sure that each buffer has at least two extra bytes of space available.
  2. Scan each buffer for the + or -. Use memmove to shift that and all subsequent bytes of the string down one. Poke an e into the buffer at the original position of the sign. (If you do step 1 by hand you can combine this step with the loop for that step.)
  3. You now have the number in a format that strtod can process.


Unfortunately C does require the "e". So you will have to parse the input for yourself. Such as:

#include <stdio.h>
#include <math.h>

double parse(const char** cursor)
{
    int len;
    double mantissa, exponent;
    char sign;
    sscanf(*cursor, " %lf%[+-]%lf%n", &mantissa, &sign, &exponent, &len);
    *cursor += len;
    return mantissa * pow(10, (sign == '-' ? -exponent : exponent));
}

int main()
{
  char line[1000];
  double sig, E;

  FILE *fp, *fopen();
  fp = fopen("sig_data", "r");

  if (fp==NULL){
        puts("Error opening file!");
        return 1;
  }
  puts("Processing file...");

  while( (fgets(line, 25, fp) != NULL) ){
        const char* cursor = line;
        E = parse(&cursor);
        sig = parse(&cursor);
        printf("The energy is: %e eV\nThe corresponding cross section is: %e barns\n",E, sig);
  }
  return 0;
}

(Add error handling as needed)


fscanf won't help you if there are no exponents so you're on your own. That means splitting the string at the +/-, calling atof() on the left, atoi() (or atof()) on the right and multiplying the first by the first to 10 raised to the second:

char *splitAt(char *s, char *stops)
{
   if (!s) return 0;
   char *t;
   for (t = s; *t && strchr(stops, *t) == NULL; t++)
       ;
   int len = t - s;
   t = malloc(len + 1);
   strncpy(t, s, len);
   t[len] = '\0';
   return t;
}


double parse_my_float(char *input)
{
    /* allocates a new string */
    char *mantissaStr = splitAt(input, "+-"); /* check for null! */
    double mantissa = atof(mantissaStr);
    int len = strlen(mantissaStr);
    free(mantissaStr);
    int exponent = atoi(input + len);
    return mantissa * pow(10, exponent);
}


How about using strtok and strtod, it should do it for you quite nicely. Using sscanf or fscanf very error prone. See below:

const char* insertE(char* out, const char* src)
{
    char* p = out;
    while (*src) {
        if (*src == '+' || *src == '-') {
            *p++ = 'e';
        }
        *p++ = *src++;
    }
    return out;
}
.
.
.
char line[1000];
char tmp[100];
double sig, E;
FILE *fp;
char* end;

fp = fopen("sig_data", "r");
if (fp==NULL){
    printf("Error opening file!");
    return;
}
else {
    printf("Processing file..."); 
    while(! feof(fp) && (fgets(line, 1000, fp) != NULL) ) {            
        E = strtod(insertE(tmp, strtok(line, "\t")), &end);
        sig = strtod(insertE(tmp, strtok(NULL, "\t")), &end);
        printf("\nThe energy is: %lf eV\nThe corresponding cross section is: %lf barns\n", E, sig);
    }
    fclose(fp);
}

This comes with a notice that this code assumes the input file is formatted exactly correctly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜