SIV*_*IVA 18 c c++ floating-point
如何在没有库函数的情况下将浮点整数转换为C/C++中的字符串sprintf
?
我正在寻找一个函数,例如char *ftoa(float num)
转换num
为字符串并返回它.
ftoa(3.1415)
应该回来"3.1415"
.
and*_*der 18
根据Sophy Pal的回答,这是一个稍微更完整的解决方案,它考虑了数字零,NaN,无限,负数和科学记数法.虽然sprintf仍然提供更准确的字符串表示.
/*
Double to ASCII Conversion without sprintf.
Roughly equivalent to: sprintf(s, "%.14g", n);
*/
#include <math.h>
#include <string.h>
// For printf
#include <stdio.h>
static double PRECISION = 0.00000000000001;
static int MAX_NUMBER_STRING_SIZE = 32;
/**
* Double to ASCII
*/
char * dtoa(char *s, double n) {
// handle special cases
if (isnan(n)) {
strcpy(s, "nan");
} else if (isinf(n)) {
strcpy(s, "inf");
} else if (n == 0.0) {
strcpy(s, "0");
} else {
int digit, m, m1;
char *c = s;
int neg = (n < 0);
if (neg)
n = -n;
// calculate magnitude
m = log10(n);
int useExp = (m >= 14 || (neg && m >= 9) || m <= -9);
if (neg)
*(c++) = '-';
// set up for scientific notation
if (useExp) {
if (m < 0)
m -= 1.0;
n = n / pow(10.0, m);
m1 = m;
m = 0;
}
if (m < 1.0) {
m = 0;
}
// convert the number
while (n > PRECISION || m >= 0) {
double weight = pow(10.0, m);
if (weight > 0 && !isinf(weight)) {
digit = floor(n / weight);
n -= (digit * weight);
*(c++) = '0' + digit;
}
if (m == 0 && n > 0)
*(c++) = '.';
m--;
}
if (useExp) {
// convert the exponent
int i, j;
*(c++) = 'e';
if (m1 > 0) {
*(c++) = '+';
} else {
*(c++) = '-';
m1 = -m1;
}
m = 0;
while (m1 > 0) {
*(c++) = '0' + m1 % 10;
m1 /= 10;
m++;
}
c -= m;
for (i = 0, j = m-1; i<j; i++, j--) {
// swap without temporary
c[i] ^= c[j];
c[j] ^= c[i];
c[i] ^= c[j];
}
c += m;
}
*(c) = '\0';
}
return s;
}
int main(int argc, char** argv) {
int i;
char s[MAX_NUMBER_STRING_SIZE];
double d[] = {
0.0,
42.0,
1234567.89012345,
0.000000000000018,
555555.55555555555555555,
-888888888888888.8888888,
111111111111111111111111.2222222222
};
for (i = 0; i < 7; i++) {
printf("%d: printf: %.14g, dtoa: %s\n", i+1, d[i], dtoa(s, d[i]));
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
小智 11
当你处理fp数字时,它可以得到非常复杂但算法简单,类似于edgar holleis的答案; 荣誉!它很复杂,因为当你处理浮点数时,根据你选择的精度,计算会略微偏离.这就是为什么将浮点数与零进行比较不是很好的编程习惯.
但是有一个答案,这是我尝试实现它.在这里,我使用了容差值,因此您最终不会计算太多小数位,从而导致无限循环.我相信可能会有更好的解决方案,但这应该有助于您更好地了解如何做到这一点.
char fstr[80];
float num = 2.55f;
int m = log10(num);
int digit;
float tolerance = .0001f;
while (num > 0 + precision)
{
float weight = pow(10.0f, m);
digit = floor(num / weight);
num -= (digit*weight);
*(fstr++)= '0' + digit;
if (m == 0)
*(fstr++) = '.';
m--;
}
*(fstr) = '\0';
Run Code Online (Sandbox Code Playgroud)
log
-function查找m
数字的大小.如果幅度是负打印"0."
和适当的零.10^m
并将结果转换为int以获取十进制数字.m--
为下一个数字.m==0
,不要忘记打印小数点"."
.m>0
你打破了,不要忘记打印"E"
和itoa(m)
.log
您也可以通过比特移位和校正指数的偏移量来直接提取指数,而不是函数(参见IEEE 754).Java有一个双位到函数来获得二进制表示.
您可以使用 C++20std::format
或基于的{fmt} 库std::format
将浮点数转换为字符串,例如:
std::string s = std::format("{}", M_PI);
Run Code Online (Sandbox Code Playgroud)
与此方法相比,此方法的优点sprintf
是为std::format
您提供最短的十进制表示形式并保证往返。