我一直使用stream,printf,string(x)或者提供的任何语言来将数字类型转换为字符串或返回。但是我从未真正考虑过这是如何实际完成的。我在Google上搜索过,但所有结果只是使用这些不同的方法,而不是如何在幕后真正完成转换:(
对于使用二进制,八进制和十六进制的整数似乎相当直接,因为字符串中的每个“数字”代表一组位(例如,对于2个十六进制数字,我知道它的xxxxyyyy),所以我可以用位移做并且一次取一个数字,例如对于十六进制串0xFA20,该值是“(15 <&lt; 12)|(10 <&lt; 8)|(2 <&lt; 4)|(0 <&lt;&lt; ; 0)“。
十进制整数更加困难,因为基数10不像那样映射到基数2,因此一位可能会影响一个以上的十进制数字,使得转换更加复杂......
至于浮点数我真的不知道。我想整个和小数部分可以单独考虑或者什么?如果是指数,一组有效数字或设定的小数位数呢?
答案 0 :(得分:1)
我在Google上搜索过,但所有结果只是使用这些不同的方法,而不是如何在幕后真正完成转换:(
出于性能原因,从一种表示转换为另一种表示(特别是浮点/整数转换)通常是低级CPU指令,并在处理器级别实现。这就是为什么你通常不会在图书馆或语言层面看到它重新实现的原因。
这在信号处理领域尤为常见,例如,您想要获取波形并将其转换为某个范围内的离散整数值。
答案 1 :(得分:1)
十进制转换速度稍慢,但实际上并不复杂得多。让我们看看十六进制转换更像我们可能在实际代码中编写它。例如,在C ++中,您可以执行以下转换:
char digits[] = "0123456789abcdef";
std::string result;
int input = 0xFA20;
while (input) {
int digit = input & 0xf; // or: digit = input % 0xf;
input >>= 4; // or: input /= 16;
result.push_front(digits[digit]);
}
然而,现在,它有一些神奇的数字。让我们摆脱它们:
const int base = 16;
while (input) {
int digit = input % (base - 1);
input /= base;
result.push_front(digits[digit]);
}
在摆脱那些神奇数字的过程中,我们也使例程几乎是通用的 - 如果我们改变'base'的值,其余的例程仍然有效,并将输入转换为指定的基础。基本上我们需要做的唯一其他改变是如果我们想要支持大于16的基数,则向“数字”数组添加更多。
为简单起见,这也忽略了一些事情。最明显的是,如果数字为负数,通常设置一个标志,转换为正数,最后如果设置了标志,则在字符串中加上“ - ”。使用2的补码时,最大负数的角点情况不能转换为正数(不转换为具有更大范围的类型)。通常,您通过推广大多数类型来处理这个问题对于您最大的整数类型(您无法推广),通常最简单的方法就是对这一个值进行硬编码。
原则上浮点并不是完全不同的 - 你仍然基本上做数学操作来一次生成一个数字。实际上,它变得更加复杂,因为您通常需要处理几种不同的格式(至少是“基本”浮点和某种“科学”格式),以及字段宽度和精度的变量。当你处理这个问题时,你最终会得到几百行代码 - 这不是一个特别令人难以置信的数量,但在这里包含它可能有点意义。
答案 2 :(得分:0)
对于整数,你可以找到除数余数,这是最后一位数,除以10,找到模数残差 - 这是一个但最后一个数字,依此类推。 浮点数由两部分构成 - 有效数字和指数,即 number = significant.digits *(base ^ exponent),其中base可以是10,2或其他数字。