我希望能够作为输入获取指向基数2到16中的数字的字符指针,并作为第二个参数,数字所在的基数,然后将其转换为基数2中的数字。可以是任意长度的。我的解决方案现在可以实现atoi()函数的功能,但如果可以使用查找表解决方案,我很好奇,仅仅是出于学术兴趣。
我发现这对二进制,八进制和十六进制来说很简单。我可以简单地为每个数字使用查找表来获得一系列位。例如:
0xF1E ---> (F = 1111)(1 = 0001)(E = 1110)---> 111100011110
0766 ---> (7 = 111)(6 = 110)(6 = 110)---> 111110110
1000 ---> ??? ---> 1111101000
然而,我的问题是我想为奇数基数做这个查找表方法,比如基数10.我知道我可以像atoi那样编写算法并做一堆乘法和加法,但对于这个特定的问题我试图看看我是否可以用查找表来完成它。但是,对于基数10来说,这绝对不是那么明显。我很好奇是否有人有任何聪明的方法来弄清楚如何为Base X生成通用的查找表 - >基础2.我知道对于基数10,你不能一次给它一个数字,所以解决方案可能必须一次查找一组数字。
我知道乘法和加法解,但由于这些是任意长度数,所以乘法和加法运算不是免费的,所以我想尽可能避免它们。
答案 0 :(得分:4)
您必须使用输入宽度为m
基本b
符号的查找表,返回n
位,以便
n = log2(b) * m
表示正整数b
,n
和m
。因此,如果b
不是2的幂,则不会有(简单的)查找表解决方案。
我认为没有解决方案。以下带有基数10的示例说明了原因。
65536 = 1 0000 0000 0000 0000
将最后一位数字从6更改为5将翻转所有位。
65535 = 0 1111 1111 1111 1111
如果从最后开始处理输入,几乎相同。将第一个数字从6更改为5会翻转大量的位。
55535 = 0 1101 1000 1111 0000
答案 1 :(得分:4)
这不可能在不是2的幂的基础上转换为base-2。基础8(和16)可能的原因是转换的工作方式如下:
octal ABC = 8^2*A + 8^1*B + 8^0*C (decimal) = 0b10000000*A + 0b1000*B + C (binary)
所以如果你有一个A =(0b000到0b111)的查找表,那么乘法总是1和一些尾随零,所以乘法很简单(只是左移)。
然而,考虑10的“奇数”基数。当你看10的权力时:
10^1 = 0b1010 10^2 = 0b1100100 10^3 = 0b1111101000 10^4 = 0b10011100010000 ..etc
你会注意到乘法永远不会变得简单,所以你不能拥有任何查找表并进行位移和ors,无论你将它们分组多大。它总是重叠的。您可以做的最好的是具有以下形式的查找表:(a,b)其中a是数字位置,b是数字(0..9)。然后,您只需减少添加n个数字,而不是乘以和添加n个数字(加上查找表的内存成本)
答案 2 :(得分:2)
算法非常简单。语言不可知是:
total = 0
base <- input_base
for each character in input:
total <- total*base + number(char)
在C ++中:
// Helper to convert a digit to a number
unsigned int number( char ch )
{
if ( ch >= '0' && ch <= '9' ) return ch-'0';
ch = toupper(ch);
if ( ch >= 'A' && ch <= 'F' ) return 10 + (ch-'A');
}
unsigned int parse( std::string const & input, unsigned int base )
{
unsigned int total = 0;
for ( int i = 0; i < input.size(); ++i )
{
total = total*base + number(input[i]);
}
return total;
}
当然,您应该注意可能的错误(不连贯的输入:基数2和输入字符串'af12')或任何其他异常情况。
答案 3 :(得分:2)
琴弦有多大?您可以通过执行以下操作将multiply-and-add转换为lookup-and-add:
当然我不确定这实际上会有多好,但这是一个想法。
答案 4 :(得分:0)
答案 5 :(得分:0)
您需要多准确?
如果你正在寻找完美,那么乘法和加法真的是你唯一的办法。如果它是您应用程序中最慢的部分,我会感到非常惊讶。
如果数量级足够好,请使用查找表来查找最接近2的幂。
示例1:1234,最接近2的幂是1024。 例2:98765,最接近的是65536
你也可以通过计算位数来驱动它,并将适当的2的幂乘以最左边的数字。这可以实现为左移:
示例3:98765具有5个数字,最接近2到10000的功率是8192(2 ^ 13),因此结果是9 <&lt;&lt; 13
答案 6 :(得分:0)
我在你的澄清评论之前写了这个,所以它可能不太适用。我不确定是否可以使用查找表方法。如果您确实不需要任意精度,那么请利用运行时。
如果C / C ++解决方案可以接受,我相信您正在寻找的是以下内容。它可能包含边缘情况中的错误,但它确实编译并按预期工作,至少对于正数。让它真正起作用是读者的一种练习。
/*
* NAME
* convert_num - convert a numerical string (str) of base (b) to
* a printable binary representation
* SYNOPSIS
* int convert_num(char const* s, int b, char** o)
* DESCRIPTION
* Generates a printable binary representation of an input number
* from an arbitrary base. The input number is passed as the ASCII
* character string `s'. The input string consists of characters
* from the ASCII character set {'0'..'9','A'..('A'+b-10)} where
* letter characters may be in either upper or lower case.
* RETURNS
* The number of characters from the input string `s' which were
* consumed by this operation. The output string is placed into
* newly allocated storage which is pointed to by `*o' upon successful
* completion. An error is signalled by returning `-1'.
*/
int
convert_num(char const *str, int b, char **out)
{
int rc = -1;
char *endp = NULL;
char *outp = NULL;
unsigned long num = strtoul(str, &endp, b);
if (endp != str) { /* then we have some numbers */
int numdig = -1;
rc = (endp - str); /* we have this many base `b' digits! */
frexp((double)num, &numdig); /* we need this many base 2 digits */
if ((outp=malloc(numdig+1)) == NULL) {
return -1;
}
*out = outp; /* return the buffer */
outp += numdig; /* make sure it is NUL terminated */
*outp-- = '\0';
while (numdig-- != 0) { /* fill it in from LSb to MSb */
*outp-- = ((num & 1) ? '1' : '0');
num >>= 1;
}
}
return rc;
}