首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C程序中的Bizzare行为::Kernighan & Ritchie练习2-3

C程序中的Bizzare行为::Kernighan & Ritchie练习2-3
EN

Stack Overflow用户
提问于 2014-11-24 22:04:22
回答 2查看 118关注 0票数 0

全。

我编写了一个程序,作为Kernighan &Ritchie练习2-3的解决方案,它在测试过程中的行为(IMHO)非常不直观。

问题规范要求编写一个程序,将十六进制值转换为它们的十进制等价物。我编写的代码对于较小的十六进制值很好,但是对于更大的十六进制值,事情会变得有点.很奇怪。例如,如果输入0x1234,则另一端会弹出十进制值4660,这恰好是正确的输出(代码也适用于字母,即0x1FC -> 508)。另一方面,如果我要输入一个很大的十六进制值,例如,作为一个具体的例子,0x123456789ABCDEF,,我应该得到81985529216486895,,但是我得到的是81985529216486896 (以一位数表示!)。

转换中的错误是不一致的,有时十进制值太高,而其他时间太低。通常,更大的十六进制值会导致十进制输出中更多不正确的位置值。

以下是我的整个计划:

代码语言:javascript
复制
/*Kernighan & Ritchie's Exercise 2-3

Write a function 'htoi' which converts a string of hexadecimal digits (including an 
optional 0x or 0X) into its equivalent integer value.
*/
#include <stdio.h>

#define MAXLINE 1000 //defines maximum size of a hex input

//FUNCTION DEFINITIONS
signed int htoi(char c); //converts a single hex digit to its decimal value

//BEGIN PROGRAM////////////////////////////////////////////////////////////
main()
{
   int i = 0; //counts the length of 'hex' at input
   char c; //character buffer
   char hex[MAXLINE]; //string from input
   int len = 0; //the final value of 'i'
   signed int val; //the decimal value of a character stored in 'hex'
   double n = 0; //the decimal value of 'hex'

   while((c = getchar()) != '\n') //store a string of characters in 'hex'
   {
      hex[i] = c;
      ++i;
   }
   len = i;
   hex[i] = '\0'; //turn 'hex' into a string

   if((hex[0] == '0') && ((hex[1] == 'x') || (hex[1] == 'X'))) //ignore leading '0x'
   {
      for(i = 2; i < len; ++i)
      {
        val = htoi(hex[i]); //call 'htoi'
        if(val == -1 ) //test for a non-hex character
        {
            break;
        }
        n = 16.0 * n + (double)val; //calculate decimal value of hex from hex[0]->hex[i]
      }
   }
   else
   {
      for(i = 0; i < len; ++i)
      {
          val = htoi(hex[i]); //call 'htoi'
          if(val == -1) //test for non-hex character
          {
             break;
          }
          n = 16.0 * n + (double)val; //calc decimal value of hex for hex[0]->hex[i]
      }
   }

 if(val == -1)
 {
    printf("\nSTRING FROM INPUT WAS NOT A HEX VALUE\n");
 }
 else
 {
    printf("\n%s converts to %.0f\n", hex, n);
 }

 return 0;
 }

 //FUNCTION DEFINITIONS OUTSIDE OF MAIN()///////////////////////////////////
 signed int htoi(char c)
 {
   signed int val = -1;

   if(c >= '0' && c <= '9')
     val = c - '0';

   else if(c == 'a' || c == 'A')
     val = 10;

   else if(c == 'b' || c == 'B')
     val = 11;

   else if(c == 'c' || c == 'C')
     val = 12;

   else if(c == 'd' || c == 'D')
     val = 13;

   else if(c == 'e' || c == 'E')
     val = 14;

   else if(c == 'f' || c == 'F')
     val = 15;

   else 
   {
     ;//'c' was a non-hex character, do nothing and return -1
   }

   return val;
 }

巴斯丁:http://pastebin.com/LJFfwSN5

对这里发生了什么有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-24 22:12:18

您可能超过了double存储整数的精度。

我的建议是修改代码以使用unsigned long long作为结果;并在这里添加一个溢出检查,例如:

代码语言:javascript
复制
unsigned long long n = 0; 
// ...

if ( n * 16 + val < n )  
{
    fprintf(stderr, "Number too big.\n");
    exit(EXIT_FAILURE);
}

n = n * 16 + val;

我的“小于”检查有效,因为当无符号整数类型溢出时,它们会被包装为零。

如果您想要添加比unsigned long long更高的精度,那么您必须使用更高级的技术(可能超出Ch的范围)。但一旦你读完了这本书,你还可以再读一遍)。

注意:如果您接受我对exit的建议,您还需要使用exit;并且不要忘记在最后的printf中将%.0f更改为%llu。另外,获取输入( K&R涵盖的输入)的一种更安全的方法是:

代码语言:javascript
复制
int c;
while((c = getchar()) != '\n' && c != EOF)

当我第一次在ideone上运行代码时,我得到了分段错误,因为我没有在stdin的末尾放一个换行符,所以这个循环一直将EOF插入到hex中,直到缓冲区溢出。

票数 2
EN

Stack Overflow用户

发布于 2014-11-24 22:21:45

这是浮点不准确的典型例子。

与大多数浮点误差的例子不同,这显然不是关于非二进制分数或非常小的数字;在这种情况下,浮点表示是近似于非常大的数字,随着精度的降低,你走得越高。这个原则和写"1.6e10“来表示”大约16000000000“(我想我就在那里数零了)是一样的,而实际数字可能是16000000001。

实际上,由于浮点变量的宽度只有一部分可以用来表示整个数字,所以比相同大小的整数的精度更快。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27115039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档