Как остановить двойное автоматическое преобразование при переполнении? - PullRequest
0 голосов
/ 26 сентября 2011

У меня есть код, в котором я извлекаю строки из окружения, используя getenv, разбирая их в числа, используя strtod. Если пользователь входит, 213.123. Тогда 213 и 123 будут индивидуально поданы на длинный тип.

long a1 = 213; long a2 = 123

Проблема, с которой я сталкиваюсь, заключается в том, что если пользователь вводит очень длинное число, например: 123456789123.45678, оно автоматически округляется, чего я не хочу, и вместо этого выдает ошибку, однако ERANGE не работает.

9 static  volatile int flag;                   /* flag variable to indicate when the measurement should start */
10 static  time_t       ef_errtrack_start_sec;  /* error track start time in seconds */
11 static  long         ef_errtrack_start_nsec; /* error track start time in nanoseconds */
12 static  time_t       ef_errtrack_end_sec;    /* error track end time in seconds */
13 static  long         ef_errtrack_end_nsec;   /* error track end time in nanoseconds */

21 int main(int argc, char **argv)
22 {
23     extractTime(1); /* Extracting start time */
24     extractTime(0); /* Extracting end time   */
25 
26     printf("start: %12d, %12d\n", ef_errtrack_start_sec, ef_errtrack_start_nsec);
27     printf("end:   %12d, %12d\n", ef_errtrack_end_sec,   ef_errtrack_end_nsec);
28 
29     return 0;
30 }


35 void extractTime(int extractStartTime)
36 {
37         char * charPtr, * numberFormatErr;
38         regex_t re;
39 
40         ( extractStartTime == 1 ) ? ( charPtr = getenv("EF_ERRTRACK_START") ) :
41                 ( charPtr = getenv("EF_ERRTRACK_END") );
42 
43         if ( charPtr == NULL )
44                 return;
45 
46         double envVal = strtod(charPtr, &numberFormatErr);
47 
48         if ( (numberFormatErr == charPtr) || (*numberFormatErr != '\0') ) {
49                 ( extractStartTime == 1 ) ? printf("eFence exited: EF_ERRTRACK_START is not a number\n") :
50                         printf("eFence exited: EF_ERRTRACK_END is not a number\n");
51                 exit(1);
52         }
53         if ( errno == ERANGE )
54         {
55                 ( extractStartTime == 1 ) ? EF_Print("eFence exited: EF_ERRTRACK_START is out of range\n") :
56                         EF_Print("eFence exited: EF_ERRTRACK_END is out of range\n");
57                 exit(1);
58         }
59         else if ( envVal < 0 ) {
60                 ( extractStartTime == 1 ) ? printf("eFence exited: EF_ERRTRACK_START a negative number\n") :
61                         printf("eFence exited: EF_ERRTRACK_END is a negative number\n");
62                 exit(1);
63         }
64 
65         if ( extractStartTime ) {
66                 ef_errtrack_start_sec = envVal;
67                 double nsec = (envVal) - (double)(ef_errtrack_start_sec);
68                 ef_errtrack_start_nsec = (long)(nsec * 1000000000);
69         }
70         else {
71                 ef_errtrack_end_sec = envVal;
72                 double nsec = (envVal) - (double)(ef_errtrack_end_sec);
73                 ef_errtrack_end_nsec = (long) (nsec * 1000000000);
74         }
75 }

Вот вывод:

Output:
/tmp # export EF_ERRTRACK_START=1234567891234.123456789123
/tmp # export EF_ERRTRACK_END=10e2

/tmp/time_related # ./a.out 

start:   2147483647,   2147483647
end:           1000,            0

Ответы [ 2 ]

3 голосов
/ 26 сентября 2011

«Вне диапазона представимых значений» означает больше, чем DBL_MAX.Ваш вход находится в диапазоне, он просто не может быть представлен в виде двойного числа.

В этом отношении, 0.1 также находится в диапазоне, и также не является точно представимым.Если это тоже ошибка, а если нет, то в чем разница?

Я не уверен, что вам посоветовать, потому что я не уверен, почему вы считаете свой случай ошибкой.Одним из вариантов будет то, что когда у вас есть двойник, преобразуйте его обратно в строку с snprintf и сравните с исходным вводом, посмотрите, равны ли они по крайней мере до десятичной точки.Однако это игнорирует научную нотацию, поэтому может потребоваться больше работы для определения чисел, которые вам не нравятся.

Редактировать: ах, изначально я не ассимилировал это: «Если пользователь входит, 213.123.Тогда 213 и 123 будут индивидуально переданы длинному типу. "

Похоже, то, что вы читаете, не является двойным значением, это два целых значения, разделенных символом точки.Поэтому не используйте strtod, найдите . и затем вызовите strtol с каждой стороны от него.

0 голосов
/ 26 сентября 2011

Я думаю, что вы должны проанализировать ввод, определить возможные типы (и ошибки) и действовать соответственно (без double необходимо)

if input has no '.' and no 'e' then secs = input; nano = 0;
if input has '.' and no 'e' then secs = firstpart; nano = secondpart (scaled appropriately)
if input has no '.' but has 'e' then convert into the 1st or 2nd format above
if input has '.' and 'e' then convert into the 1st or 2nd format above
if input has '.' after 'e' then give error
if input has 2 or more '.' then give error
if input has 2 or more 'e' then give error
... something else I didn't think about
...