代码之家  ›  专栏  ›  技术社区  ›  Fire Lancer

将数字转换为字符串并返回

  •  0
  • Fire Lancer  · 技术社区  · 14 年前

    我一直使用流、printf、string(x)或任何相关语言将数字类型转换为字符串或返回。然而,我从未真正考虑过这是如何做到的。我在google上搜索过,但是所有的结果都只是使用那些不同的方法,而不是在幕后如何进行转换:(

    对于使用二进制的整数,八进制和十六进制看起来相当直接,因为字符串中的每个“数字”代表一组位(例如,对于2个十六进制数字,我知道它的XXXYYYY),所以我可以使用位移位,一次取一个数字,例如对于十六进制字符串0xFA20,值是“(15<<12)(10<<8)(2<<4)|(0<<0)”。

    十进制整数比较困难,因为基数10不能像那样映射到基数2,因此一个位可能影响多个十进制数字,从而使转换变得更加复杂…

    至于浮点数,我真的不知道。我想整个部分和部分可以分开考虑还是别的?作为一个指数,一组有效数字或一组小数点后几位呢?

    3 回复  |  直到 14 年前
        1
  •  1
  •   Jerry Coffin    14 年前

    十进制转换有点慢,但实际上并不复杂。让我们看一下十六进制转换,更像我们可能会用真正的代码编写它。例如,在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
  •  1
  •   John Feminella    14 年前

    我在google上搜索过,但是所有的结果都只是使用那些不同的方法,而不是在幕后如何进行转换:(

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

    这在信号处理世界中尤其常见,例如,您希望获取波形并将其转换为某个范围内的离散整数值。

        3
  •  0
  •   Nickolay Olshevsky    14 年前

    对于整数,您可以找到除法余数,这是最后一个数字,除以10,找到模余数-这是最后一个数字,依此类推。 浮点数由两部分组成-有效数字和指数,即 数字=有效。数字*(基数^指数),其中基数可以是10、2或其他数字。