it-swarm.com.ru

Какова максимальная длина в символах, необходимая для представления любого двойного значения?

Когда я преобразую 8-разрядное целое число без знака в строку, я знаю, что результат всегда будет не более 3-х символов (для 255), а для 8-разрядного целого со знаком нам понадобится 4 символа, например. "-128".

Теперь то, что мне действительно интересно, это то же самое для значений с плавающей точкой. Какое максимальное число символов требуется для представления любого значения типа "double" или "float" в виде строки?

Предположим, что в C/C++ используется двойное (IEEE 754) и нормальное десятичное расширение (т. Е. Нет% e printf-форматирования).

Я даже не уверен, будет ли действительно маленькое число (то есть 0,234234) длиннее, чем действительно огромные числа (двойные числа, представляющие целые числа)?

44
martin

Стандартный заголовок <float.h> в C или <cfloat> в C++ содержит несколько констант для диапазона и других метрик типов с плавающей запятой. Одним из них является DBL_MAX_10_EXP, самый большой показатель степени 10, необходимый для представления всех значений double. Так как для представления 1eN нужны цифры N+1, а также может присутствовать отрицательный знак, то ответ

int max_digits = DBL_MAX_10_EXP + 2;

Это предполагает, что показатель степени больше, чем число цифр, необходимое для представления максимально возможного значения мантиссы; в противном случае также будет десятичная точка, за которой следуют дополнительные цифры.

ИСПРАВЛЕНИЕ

Самое длинное число на самом деле является наименьшим представимым отрицательным числом: ему нужно достаточно цифр, чтобы охватить как экспоненту, так и мантиссу. Это значение -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
34
Mike Seymour

Согласно IEEE 754-1985, самая длинная нотация для значения представлена ​​двойным типом, т.е.

-2.2250738585072020E-308

имеет 24 символа.

13
Vitaliy Ulantikov

Вы можете использовать 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 предоставляет его как расширение, он может не выполнить то, что ожидает вышеуказанная программа.

Edit: Изменена ссылка на snprintf() на ссылку, которая фактически описывает функциональность, налагаемую стандартом C99; описание в оригинальная ссылка неверно.
2013: изменена ссылка назад на сайт POSIX, который я предпочитаю над сайтом первого редактирования .

4
pmg

Вы можете контролировать количество цифр в строковом представлении, когда вы конвертируете число с плавающей запятой/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 цифр.

2
Charles Salvia

Правильный источник информации, который описывается более подробно, чем спецификация IEEE-754 это примечания к лекциям UC Berkely на стр. 4, плюс небольшая часть расчетов DIY. Эти слайды лекций также хороши для студентов инженерных специальностей.

Рекомендуемые размеры буфера

| 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`.

Самый быстрый алгоритм

Самым быстрым алгоритмом печати чисел с плавающей запятой является алгоритм Grisu2, подробно описанный в исследовательской работе Быстрая и точная печать чисел с плавающей запятой . Лучший эталонный тест, который я смог найти, можно найти здесь .

2
user2356685

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
1
Fred

Зависит от того, что вы подразумеваете под «представлять». Десятичная дробь не имеет точных представлений с плавающей точкой. При преобразовании десятичной дроби -> двоичной дроби -> десятичной дроби у вас нет точных десятичных представлений, и в конце двоичного представления будут биты шума.

Вопрос не предполагал начинать с десятичного числа, но весь исходный код (и должен вводиться пользователем) является десятичным и включает возможную проблему усечения. Что означает «точное» в этих обстоятельствах?

В основном, это зависит от вашего представления с плавающей запятой.

Если у вас есть 48 бит мантиссы, это займет около 16 десятичных цифр. Показателем степени могут быть оставшиеся 14 бит (около 5 десятичных цифр).

Эмпирическое правило заключается в том, что количество битов примерно в 3 раза превышает количество десятичных цифр.

1
S.Lott

«Какова максимальная длина в символах, необходимая для представления любого двойного значения?»

Точный ответ на этот вопрос: 8 ASCII символов - в шестнадцатеричном формате, исключая префикс «0x» - точность 100% :) (но это не просто шутка)

Используемая точность двойного стандарта IEEE-754 составляет около 16 десятичных цифр, поэтому исключая образовательные цели, представления длиннее, чем просто трата ресурсов и вычислительной мощности:

  • Пользователи не получают больше информации, когда видят 700-значный номер на экране.

  • Переменные конфигурации, хранящиеся в этой «более точной» форме, бесполезны - каждая отдельная операция с таким числом будет нарушать точность. (исключая изменение знакового бита)

Если кому-то нужна лучшая реальная точность, то есть 80-битный двойной дубль с точностью около 18 цифр или т. Е. libquadmath.

С уважением.

1
vtomazzi

Максимальное количество символов, которое потребуется для печати любого десятичного значения 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);
0
Greg A. Woods

Это совсем не неоднозначный набор ответов. Я ищу что-то, чтобы сказать C # спецификатор формата для того, чтобы использовать синтаксический анализатор, над которым я работаю. Я случайным образом генерирую несколько тестовых случаев, в том числе константы точности с двойной или плавающей запятой, и мне нужно сохранить круговую передачу. Да, я знаю, что есть «круговорот», это один аспект. Но мне также нужно поддерживать Fixed , а также Scientific нотации. Пока мне нравится 1079, но это кажется мне чрезмерным. Или, по крайней мере, мое «достаточно близкое» сравнение должно учитывать эту разницу во время проверки до/после анализа.

0
mwpowellhtx