如何在溢出时停止双重自动转换?

发布于 2024-12-06 15:58:30 字数 3094 浏览 1 评论 0原文

我有一个代码,其中使用 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

I have a code in which i am extracting strings from environment using getenv, parsing them into numbers using strtod.
If user enters, 213.123. Then 213 and 123 will be individually fed to a long type.

long a1 = 213; long a2 = 123

The problem i am facing is, if user enters a very long number like: 123456789123.45678, it is automatically getting rounded off, which i don't want and instead throw an error, however ERANGE isn't working.

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 }

Here is the output:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

落在眉间の轻吻 2024-12-13 15:58:30

“超出可表示值的范围”意味着大于DBL_MAX。您的输入在范围内,它只是不能完全表示为双精度。

就此而言,0.1 也在范围内,并且也不能完全表示。这也应该是一个错误吗?如果不是,有什么区别?

我不知道该建议你做什么,因为我不知道为什么你认为你的情况是错误的。一种选择是,一旦获得双精度数,就使用 snprintf 将其转换回字符串,并与原始输入进行比较,看看它们是否至少在小数点上相等。不过,这忽略了科学记数法,因此可能需要做更多的工作来识别您不喜欢的数字。

编辑:啊,最初我并没有真正理解这一点:“如果用户输入 213.123。那么 213 和 123 将被单独输入到一个 long 类型。”

听起来您正在读取的不是双精度值,而是由句点字符分隔的两个整数值。因此,不要使用 strtod,找到 .,然后在其每一侧调用 strtol

"Outside the range of representable values" means bigger than DBL_MAX. Your input is in range, it just isn't exactly representable as a double.

For that matter, 0.1 is also in range, and also isn't exactly representable. Should that also be an error, and if not, what's the difference?

I'm not sure what to advise you to do, because I'm not sure why you consider your case an error. One option would be that once you have your double, convert it back to string with snprintf and compare to the original input, see whether they are equal at least as far as the decimal point. That ignores scientific notation, though, so there may be more work required to identify the numbers you don't like.

Edit: ah, initially I didn't really assimilate this: "If user enters, 213.123. Then 213 and 123 will be individually fed to a long type."

Sounds like what you are reading is not a double value, it's two integer values separated by a period character. So don't use strtod, find the . and then call strtol on each side of it.

本宫微胖 2024-12-13 15:58:30

我认为你必须解析输入,识别可能的类型(和错误)并采取相应的行动(不需要 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

I think you have to parse the input, identify the possible types (and errors) and act accordingly (no double necessary)

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文