Was ist die maximale Länge in Zeichen, die benötigt wird, um einen doppelten Wert darzustellen?

Was ist die maximale Länge in Zeichen, die benötigt wird, um einen doppelten Wert darzustellen?


Wenn ich ein vorzeichenloses 8-Bit-Int in einen String konvertiere, weiß ich, dass das Ergebnis immer höchstens 3 Zeichen (für 255) sein wird, und für ein vorzeichenbehaftetes 8-Bit-Int benötigen wir 4 Zeichen für z. "-128".


Was ich mich jetzt eigentlich frage, ist dasselbe für Gleitkommawerte. Was ist die maximale Anzahl an Zeichen, die erforderlich ist, um einen "Double"- oder "Float"-Wert als String darzustellen?


Gehen Sie von einem regulären C/C++ Double (IEEE 754) und normaler Dezimalerweiterung aus (d. h. keine %e printf-Formatierung).


Ich bin mir nicht einmal sicher, ob die wirklich kleine Zahl (z. B. 0,234234) länger sein wird als die wirklich großen Zahlen (Double, die ganze Zahlen darstellen)?


Antworten:


Der Standard-Header <float.h> in C oder <cfloat> in C++ enthält mehrere Konstanten, die mit dem Bereich und anderen Metriken der Gleitkommatypen zu tun haben. Einer davon ist DBL_MAX_10_EXP , der größte Potenz-von-10-Exponent, der benötigt wird, um alle double darzustellen Werte. Seit 1eN benötigt N+1 Ziffern darzustellen, und es könnte auch ein negatives Vorzeichen geben, dann lautet die Antwort


int max_digits = DBL_MAX_10_EXP + 2;

Dies setzt voraus, dass der Exponent größer ist als die Anzahl der Stellen, die benötigt werden, um den größtmöglichen Mantissenwert darzustellen; andernfalls gibt es auch einen Dezimalpunkt, gefolgt von weiteren Ziffern.


KORREKTUR


Die längste Zahl ist eigentlich die kleinste darstellbare negative Zahl:Sie benötigt genügend Ziffern, um sowohl den Exponenten als auch die Mantisse abzudecken. Dieser Wert ist -pow(2, DBL_MIN_EXP - DBL_MANT_DIG) , wobei DBL_MIN_EXP ist negativ. Es ist ziemlich einfach zu sehen (und per Induktion zu beweisen), dass -pow(2,-N) benötigt 3+N Zeichen für eine nicht-wissenschaftliche Dezimaldarstellung ("-0." , gefolgt von N Ziffern). Die Antwort lautet also


int max_digits = 3 + DBL_MANT_DIG - DBL_MIN_EXP

Für ein 64-Bit-IEEE-Double haben wir


DBL_MANT_DIG = 53
DBL_MIN_EXP = -1023
max_digits = 3 + 53 - (-1023) = 1079

Einige Code-Antworten


int max_digits = DBL_MAX_10_EXP + 2;
int max_digits = 3 + DBL_MANT_DIG - DBL_MIN_EXP 
DBL_MANT_DIG = 53 DBL_MIN_EXP = -1023 max_digits = 3 + 53 - (-1023) = 1079 
| Single| Double | Extended | Quad  | |:-----:|:------:|:--------:|:-----:| |   16  |  24    |    30    |  45   | 
| Single| Double | Extended | Quad  | |:-----:|:------:|:--------:|:-----:| |   9   |   17   |    21    |  36   |  * Quantities listed in decimals. 
| Single| Double | Extended | Quad  | |:-----:|:------:|:--------:|:-----:| |   5   |   5    |
7 | 7 | * Standard format is `e-123`.
/* 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;
}
#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 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 
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);
#include <limits.h>
char buffer[4 + DBL_DIG + -DBL_MIN_10_EXP];
#include <limits>
char buffer[4 + std::numeric_limits<double>::digits10 + -std::numeric_limits<double>::min_exponent10];