将double / float转换为字符串

时间:2011-08-29 09:37:38

标签: c string floating-point

我需要将浮点数转换为十进制(或其他基数)中的等效字符串。首先需要以xE+0格式进行转换,其中x是浮点数。

我的想法是首先将浮点数截断为临时整数,然后将该整数转换为字符串,然后考虑小数部分,将其与10相乘,而小数部分不会变为{ {1}}。将小数部分转移到小数点的左侧后,再次将整数应用于字符串函数,并将小数部分转换为字符串。有没有更好的方法,哪个比这更快?这种方法会引起任何副作用吗?

要将浮点数转换为指数表示,我应该如上所述,然后调整功率吗?或直接对IEEE 754浮点表示进行位掩码,并将每个部分转换为字符串。

注意:没有其他功能可以使用,因为我可以访问绝对没有库函数。这段代码进入玩具内核。

7 个答案:

答案 0 :(得分:23)

使用snprintf()中的stdlib.h。为我工作。

double num = 123412341234.123456789; 
char output[50];

snprintf(output, 50, "%f", num);

printf("%s", output);

答案 1 :(得分:18)

唯一确切的解决方案是对基本转换执行任意精度的十进制算术,因为精确值可以非常长 - 对于80位long double,最多大约10000小数位。幸运的是,对于IEEE double,它“仅”大约700个左右。

不是使用单个十进制数字,而是工作基数为10亿(10位的最高功率适合32位整数),然后将这些“基数为10亿的数字”转换为9计算结束时各自的十进制数字。

我有一个非常密集(相当难以阅读)但有效的实现,在 LGPL MIT许可下:

http://git.musl-libc.org/cgit/musl/blob/src/stdio/vfprintf.c?h=v1.1.6

如果你去掉所有的六边形浮动支撑,无限/南支撑,%g / %f / %e变异支持,四舍五入(如果你只想要精确的话,这将永远不需要答案),以及其他你可能不需要的东西,剩下的代码很简单。

答案 2 :(得分:6)

在某些C库中查看printf() "%f"实现。

答案 3 :(得分:4)

我知道也许这是不必要的,但我做了一个将float转换为string的函数:

CODE:

#include <stdio.h>

/** Number on countu **/

int n_tu(int number, int count)
{
    int result = 1;
    while(count-- > 0)
        result *= number;

    return result;
}

/*** Convert float to string ***/
void float_to_string(float f, char r[])
{
    long long int length, length2, i, number, position, sign;
    float number2;

    sign = -1;   // -1 == positive number
    if (f < 0)
    {
        sign = '-';
        f *= -1;
    }

    number2 = f;
    number = f;
    length = 0;  // Size of decimal part
    length2 = 0; // Size of tenth

    /* Calculate length2 tenth part */
    while( (number2 - (float)number) != 0.0 && !((number2 - (float)number) < 0.0) )
    {
         number2 = f * (n_tu(10.0, length2 + 1));
         number = number2;

         length2++;
    }

    /* Calculate length decimal part */
    for (length = (f > 1) ? 0 : 1; f > 1; length++)
        f /= 10;

    position = length;
    length = length + 1 + length2;
    number = number2;
    if (sign == '-')
    {
        length++;
        position++;
    }

    for (i = length; i >= 0 ; i--)
    {
        if (i == (length))
            r[i] = '\0';
        else if(i == (position))
            r[i] = '.';
        else if(sign == '-' && i == 0)
            r[i] = '-';
        else
        {
            r[i] = (number % 10) + '0';
            number /=10;
        }
    }
}

答案 4 :(得分:2)

查看BSD C标准库是否具有fcvt()。您可以从它的源代码开始,而不是从头开始编写代码。 UNIX 98标准fcvt()显然没有输出科学记数法,所以你必须自己实现它,但我认为这不会很难。

答案 5 :(得分:0)

或者,您可以使用 C99 输出格式,即:[-]0x1.<significand>p<biasied_exponent-bias>,对于双精度数字,偏差为 0x3ff。这也是序列化的首选格式,因为它是精确的,并且不依赖于浮点环境的当前设置(如四舍五入或将非正规数刷新为零)。有点普通,但可能仍然有用且速度非常快。

答案 6 :(得分:-2)

sprintf 可以做到这一点:

#include <stdio.h>
int main() {
  float w = 234.567;
  char x[__SIZEOF_FLOAT__];
  sprintf(x, "%g", w);
  puts(x);
}