全。
我编写了一个程序,作为Kernighan &Ritchie练习2-3的解决方案,它在测试过程中的行为(IMHO)非常不直观。
问题规范要求编写一个程序,将十六进制值转换为它们的十进制等价物。我编写的代码对于较小的十六进制值很好,但是对于更大的十六进制值,事情会变得有点.很奇怪。例如,如果输入0x1234,则另一端会弹出十进制值4660,这恰好是正确的输出(代码也适用于字母,即0x1FC -> 508)。另一方面,如果我要输入一个很大的十六进制值,例如,作为一个具体的例子,0x123456789ABCDEF,,我应该得到81985529216486895,,但是我得到的是81985529216486896 (以一位数表示!)。
转换中的错误是不一致的,有时十进制值太高,而其他时间太低。通常,更大的十六进制值会导致十进制输出中更多不正确的位置值。
以下是我的整个计划:
/*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
对这里发生了什么有什么想法吗?
发布于 2014-11-24 22:12:18
您可能超过了double存储整数的精度。
我的建议是修改代码以使用unsigned long long作为结果;并在这里添加一个溢出检查,例如:
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涵盖的输入)的一种更安全的方法是:
int c;
while((c = getchar()) != '\n' && c != EOF)当我第一次在ideone上运行代码时,我得到了分段错误,因为我没有在stdin的末尾放一个换行符,所以这个循环一直将EOF插入到hex中,直到缓冲区溢出。
发布于 2014-11-24 22:21:45
这是浮点不准确的典型例子。
与大多数浮点误差的例子不同,这显然不是关于非二进制分数或非常小的数字;在这种情况下,浮点表示是近似于非常大的数字,随着精度的降低,你走得越高。这个原则和写"1.6e10“来表示”大约16000000000“(我想我就在那里数零了)是一样的,而实际数字可能是16000000001。
实际上,由于浮点变量的宽度只有一部分可以用来表示整个数字,所以比相同大小的整数的精度更快。
https://stackoverflow.com/questions/27115039
复制相似问题