当我将无符号8位int转换为string时,我知道结果总是最多3个字符(对于255),对于带符号的8位int,我们需要4个字符,例如: “-128”。
现在我真正想知道的是浮点值是一回事。将任何“double”或“float”值表示为字符串所需的最大字符数是多少?
假设一个普通的C / C ++ double(IEEE 754)和正常的十进制扩展(即没有%e printf格式化)。
我甚至不确定真正的小数字(即0.234234)是否会长于真正庞大的数字(代表整数的双数)?
答案 0 :(得分:34)
C中的标准头<float.h>
或C ++中的<cfloat>
包含几个与浮点类型的范围和其他度量相关的常量。其中一个是DBL_MAX_10_EXP
,是表示所有double
值所需的最大10次幂指数。由于1eN
需要N+1
个数字来表示,并且可能还有一个负号,所以答案是
int max_digits = DBL_MAX_10_EXP + 2;
这假设指数大于表示最大可能尾数值所需的位数;否则,还会有一个小数点后跟更多数字。
<强> CORRECTION 强>
最长的数字实际上是最小的可表示的负数:它需要足够的数字来覆盖指数和尾数。此值为-pow(2, DBL_MIN_EXP - DBL_MANT_DIG)
,其中DBL_MIN_EXP
为负数。很容易看到(并通过归纳证明)-pow(2,-N)
需要3+N
个字符用于非科学十进制表示("-0."
,后跟N
个数字)。所以答案是
int max_digits = 3 + DBL_MANT_DIG - DBL_MIN_EXP
对于64位IEEE双,我们有
DBL_MANT_DIG = 53
DBL_MIN_EXP = -1023
max_digits = 3 + 53 - (-1023) = 1079
答案 1 :(得分:15)
答案 2 :(得分:4)
您可以使用snprintf()
来检查所需的字符数。
snprintf()
返回打印传递给它的内容所需的字符数。
/* NOT TESTED */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char dummy[1];
double value = 42.000042; /* or anything else */
int siz;
char *representation;
siz = snprintf(dummy, sizeof dummy, "%f", value);
printf("exact length needed to represent 'value' "
"(without the '\\0' terminator) is %d.\n", siz);
representation = malloc(siz + 1);
if (representation) {
sprintf(representation, "%f", value);
/* use `representation` */
free(representation);
} else {
/* no memory */
}
return 0;
}
注意:snprintf()
是C99功能。如果C89编译器将其作为扩展名提供,则可能无法执行上述程序所期望的操作。
修改的:
将指向snprintf()
的链接更改为实际描述C99标准所强加的功能的链接; original link中的描述是错误的
2013:将链接更改更改为POSIX网站,我更喜欢site of the first edit。
答案 3 :(得分:3)
第4页上的IEEE-754 Specification是比lecture notes from UC Berkely更详细的正确信息源,外加一些DIY计算。 These lecture slides也适合工程专业的学生。
| Single| Double | Extended | Quad |
|:-----:|:------:|:--------:|:-----:|
| 16 | 24 | 30 | 45 |
这些数字是基于以下计算得出的:
| Single| Double | Extended | Quad |
|:-----:|:------:|:--------:|:-----:|
| 9 | 17 | 21 | 36 |
* Quantities listed in decimals.
小数计数基于以下公式:最多Ceiling(1 + N Log_10(2))个小数,其中N是整数部分的位数*。
| Single| Double | Extended | Quad |
|:-----:|:------:|:--------:|:-----:|
| 5 | 5 | 7 | 7 |
* Standard format is `e-123`.
最快的打印浮点数的算法是研究论文Printing Floating-point Numbers Quickly and Accurately中详细介绍的Grisu2算法。我可以找到的最佳基准测试here。
答案 4 :(得分:2)
通过设置精度将float / double转换为字符串时,可以控制字符串表示中的位数。然后,最大位数将等于您指定精度的std::numeric_limits<double>::max()
字符串表示。
#include <iostream>
#include <limits>
#include <sstream>
#include <iomanip>
int main()
{
double x = std::numeric_limits<double>::max();
std::stringstream ss;
ss << std::setprecision(10) << std::fixed << x;
std::string double_as_string = ss.str();
std::cout << double_as_string.length() << std::endl;
}
因此,double
中精度为10的最大位数为320位。
答案 5 :(得分:1)
取决于“代表”的含义。小数部分没有精确的浮点表示。当您转换小数部分 - &gt;二元分数 - &gt;十进制,您没有精确的十进制表示,并且在二进制表示的末尾会有噪声位。
问题不涉及从十进制开始,但所有源代码(并且必须是用户输入)都是十进制的,并且涉及可能的截断问题。在这种情况下,“确切”是什么意思?
基本上,它取决于你的浮点表示。
如果您有48位尾数,则需要大约16位十进制数字。指数可能是剩余的14位(大约5位小数)。
经验法则是位数约为十进制数的3倍。
答案 6 :(得分:1)
1024是不够的,最小的负双值有1077个十进制数字。这是一些Java代码。
double x = Double.longBitsToDouble(0x8000000000000001L);
BigDecimal bd = new BigDecimal(x);
String s = bd.toPlainString();
System.out.println(s.length());
System.out.println(s);
以下是该计划的输出。
1077
-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625
答案 7 :(得分:1)
“表示任何双值所需的字符的最大长度是多少?”
这个问题的确切答案是:8个ASCII字符 - 采用十六进制格式,不包括'0x'前缀 - 100%准确度:)(但这不仅仅是一个玩笑)
IEEE-754 double的可用精度大约为16位十进制数 - 因此不包括教育目的,长于此的表示只是浪费资源和计算能力:
当他们在屏幕上看到一个700位数字时,用户没有得到更多信息。
以“更准确”的形式存储的配置变量是无用的 - 对这样的数字的每一次操作都会破坏准确性。 (不包括更改符号位)
如果有人需要更好的真实的精度,那么就有80位长的双精度,大约18位精度或f.e. libquadmath。
问候。
答案 8 :(得分:0)
打印任何小数double
值(即"%f"
格式)所需的最大字符数将为-DBL_MIN
的值(即-0x1p-1022,假设binary64 IEEE 754是您的double
)。为此,你需要325个字符。那是:DBL_DIG + abs(DBL_MIN_10_EXP) + strlen("-0.")
。这当然是因为log10(fabs(DBL_MIN))
是308,也是abs(DBL_MIN_10_EXP)+1
(+1是因为小数点左边的前导数字),而且是领先的数量有效数字左侧的零。
int lz; /* aka abs(DBL_MIN_10_EXP)+1 */
int dplaces;
int sigdig; /* aka DBL_DECIMAL_DIG - 1 */
double dbl = -DBL_MIN;
lz = abs((int) lrint(floor(log10(fabs(dbl)))));
sigdig = lrint(ceil(DBL_MANT_DIG * log10((double) FLT_RADIX)));
dplaces = sigdig + lz - 1;
printf("f = %.*f\n", dplaces, dbl);
答案 9 :(得分:0)
这根本不是模棱两可的答案。我正在寻找可以告诉 C#格式说明符的内容,以便执行我正在研究的解析器。我随机生成一些测试用例,包括双精度或浮点精度常量,并且需要保留往返行程。是的,我知道这是一个“往返”。但是我还需要支持 Fixed 和 Scientific 表示法。到目前为止,我喜欢1079
,但这对我来说似乎太过分了。或者至少我的“足够接近”的比较需要将这种差异纳入分析前/分析后的验证中。
答案 10 :(得分:-1)
&#34;为此你需要正好325个字符&#34;
显然(这是一个非常常见的情况)您不了解不同数字库之间的转换是如何工作的。
无论DBL_MIN的定义有多精确,它都受硬件精度的限制,通常高达80位或18位十进制数(x86和类似架构)
出于这个原因,已经发明了专门的任意精度算术库,如f.e. gmp或mpfr。