0

我一直使用流、printf、string(x) 或任何相关语言将数字类型转换为字符串或返回。但是,我从来没有真正考虑过这实际上是如何完成的。我在谷歌上搜索,但所有结果都只是使用这些不同的方法,而不是如何在幕后真正完成转换:(

对于使用二进制的整数,八进制和十六进制似乎相当简单,因为字符串中的每个“数字”都代表一组位(例如,对于我知道它的 xxxxyyyy 的 2 个十六进制数字),所以我可以通过位移来实现并取一个一次一个数字,例如对于十六进制字符串 0xFA20,其值为“(15 << 12) | (10 << 8) | (2 << 4) | (0 << 0)”。

十进制整数更困难,因为基数 10 不会像那样映射到基数 2,因此一位可能会影响多于一位的十进制数字,从而使两种方式的转换更加复杂......

至于浮点数我真的不知道。我想整体和小数部分可以分开考虑还是什么?作为指数,一组有效数字或一组小数位数怎么样?

4

3 回答 3

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 的碱基,我们需要做的唯一其他更改就是在“digits”数组中添加更多内容。

为了简单起见,这也忽略了一些事情。最明显的是,如果数字是负数,您通常设置一个标志,转换为一个正数,最后如果设置了标志,则在字符串中放入一个“-”)。对于 2 的补码,最大负数有一个极端情况,它不能转换为正数(不转换为具有更大范围的类型)。通常,您通过提升大多数类型来处理这个问题。对于您最大的整数类型(您无法提升),通常最容易硬编码该值。

原则上,浮点数并没有太大的不同——你基本上仍然会进行数学运算来一次生成一个数字。事实上,它变得更加复杂仅仅是因为您通常必须处理几种不同的格式(至少是“基本”浮点和某种“科学”格式),以及字段宽度和精度的变量。当你处理完这个问题时,你最终会得到大约几百行代码——这不是一个特别离谱的数量,但在这里包含可能有点超出了意义。

于 2010-08-23T15:52:48.343 回答
1

我在谷歌上搜索,但所有结果都只是使用这些不同的方法,而不是如何在幕后真正完成转换:(

出于性能原因,从一种表示转换为另一种表示(特别是浮点/整数转换)通常是低级 CPU 指令,并且在处理器级别实现。这就是为什么您通常不会在库或语言级别看到它重新实现的原因。

这在信号处理领域尤其常见,例如,您想要获取波形并将其转换为某个范围内的离散整数值。

于 2010-08-23T15:18:52.213 回答
0

对于整数,您可以找到除法余数,这是最后一位,除以 10,找到模残差 - 这是最后一位,等等。浮点数由两部分构成——有效数字和指数,即数字 = 有效数字 *(基数 ^ 指数),其中基数可以是 10、2 或其他数字。

于 2010-08-23T15:20:48.483 回答