我需要将浮点数转换为十进制(或其他基数)中的等效字符串。首先需要以xE+0
格式进行转换,其中x
是浮点数。
我的想法是首先将浮点数截断为临时整数,然后将该整数转换为字符串,然后考虑小数部分,将其与10
相乘,而小数部分不会变为{ {1}}。将小数部分转移到小数点的左侧后,再次将整数应用于字符串函数,并将小数部分转换为字符串。有没有更好的方法,哪个比这更快?这种方法会引起任何副作用吗?
要将浮点数转换为指数表示,我应该如上所述,然后调整功率吗?或直接对IEEE 754浮点表示进行位掩码,并将每个部分转换为字符串。
注意:没有其他功能可以使用,因为我可以访问绝对没有库函数。这段代码进入玩具内核。
答案 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的函数:
#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);
}