2017-03-07 77 views
1

为以下代码输入大数字会导致scanf成功,尽管该值未被正确存储。scanf成功,但存储的值对于某些大型浮点数不适用

printf("\nDouble max: %f\n", DBL_MAX); 
printf("\nFloat max: %f\n", FLT_MAX); 
printf("\nPlease insert root1 data: "); 
float input1; 
scanResult = scanf("%f", &input1); 
printf("\nScan Result is %d\n", scanResult); 

double input2; 
printf("\nPlease insert root2 data: "); 
scanResult = scanf("%lf", &input2); 
printf("\nScan Result is %d\n", scanResult); 

printf("%f", input1); 
printf("%f", input2); 

输出:

Double max: 17976931348623157000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 
0.000000 

Float max: 340282346638528860000000000000000000000.000000 

Please insert root1 data: 1872389723948273985723984756982375698374568 

Scan Result is 1 

Please insert root2 data: 928734812348721834.2348275 

Scan Result is 1 


1.#INF00 

928734812348721790.000000 

所以我的问题是:

  1. 首先扫描:为什么scanf还是要说的扫描结果为1,当你可以看到,价值存储不正确?

  2. 第二次扫描:为什么它会舍入它,我该如何解决它?

  3. 一般:我们可以看到,通过0的数量,该​​和FLT_MAX比我给的输入大得多。那为什么它不正确地存储输入?

+0

您需要更好的'c'书籍(或网站) – KevinDTimm

+0

@KevinDTimm我可以理解为什么吗? –

+0

对于scanf()有关溢出处理的有趣问题+1。这不仅抵消了你不努力验证你的输入;-)。 –

回答

1
  1. 首先扫描:为什么scanf还是要说的扫描结果为1,当你可以看到,值存放不当?

的第一数量大于FLT_MAX大,因此被正确地解析为无穷大。

  • 第二次扫描:为什么会这样四舍五入它,以及如何解决 呢?
  • 的第二数量比​​小,所以它找到用于输入数字的最佳双精度浮点值。这是显示的内容。如果你不明白这是什么意思, this article will help

  • 一般来说:我们可以看到,通过0的数,使得​​和FLT_MAX比我给输入大得多。那为什么它不正确地存储输入?
  • 不正确。您正在将较大的数字解析为双精度数字,并将较小的数字解析为精度。

    3
    1. 首先扫描:为什么scanf还是要说的扫描结果为1,当你可以看到,值存放不当?

    扫描结果为1,因为一个输入项被匹配,转换和分配。这是scanf()的非负值时的返回值的含义。

    此外,我看到值存储不正确。您提供了一个数字序列,该数字序列被解释为一个十进制数字,它大于float可以表示的最大值。 scanf()函数将这些输入转换为float作为表示系统可以表示的最大“值”的数字;在你的实现中,这是一个float正无限。

  • 第二次扫描:为什么会这样四舍五入它,我怎么能解决这个问题?
  • 浮点数具有固定大小的表示形式,就像所有C的内置数据类型一样。因此,它们的精度有限制,并且其范围内有许多数字不能完全表示。这是浮点和整数之间的折衷:前一类的类型具有更宽的范围和比例,但它们通常不精确。

    您的机器很可能使用IEEE-754二进制双精度作为其格式double。该格式提供15-16个十进制数字的精度。当某些输入转换为double(即使使用不同的表示形式)时,您无法避免舍入,因为数字格式无法将输入表示为其原始精度。通过scanf()读取输入而不舍入的唯一方法是将其作为字符串而不是数字读取。

  • 一般来说:我们可以看到,通过0的数,使得​​和FLT_MAX比我给输入大得多。那为什么它不正确地存储输入?
  • 除了有限精度问题,我已经讨论过,也请注意,你的第一个输入大于FLT_MAX较大,但您尝试读取它作为一个float。如果您认为输入在目标数字格式的范围内,则说明您错了。

    +0

    良好的信息。我实际上会期望scanf()在溢出的情况下失败;我发现[man page](http://pubs.opengroup.org/onlinepubs/7908799/xsh/fscanf.html)缺少错误条件。对'strtod'的引用只涉及格式,而不是错误处理。例如,我可以期待scanf()设置“errno”吗? –

    +0

    @ PeterA.Schneider,您明确引用的手册页说:“如果发生读取错误,则设置流的错误指示符,返回”EOF“,并将”errno“设置为指示错误。它也指向'fgetc()'和'fgetwc()'来设置可能的错误,并指定一些附加的错误。 –

    +0

    @ PeterA.Schneider,请注意,错误条件仅为*读取错误*而明确定义。 'scanf()'在匹配失败时不报告错误。此外,它不能报告超出范围数字输入的匹配失败,因为如果匹配失败,则需要将整个不匹配的输入保留在流中。你不能依赖于能够推回多个字符,所以到'scanf()'可以检测到输入对应于超出范围的数字时,它就承诺以某种方式转换*。 –

    相关问题