бага в распечатке double
От: _Winnie Россия C++.freerun
Дата: 01.10.05 23:36
Оценка: :)
int main()
{

    //2^1000  
    double d1 = 
        10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.0;

    long long d_int =
        (1023LL + 1000LL) << 52; 
    double d2 = *(double*)&d_int; //тоже самое.

    assert(d1 == d2);

    {

        std::cout <<'[' <<std::fixed << d1 <<"]\n";
        printf("[%f]\n", d1);
        int dec, sign;
        printf("[%s]\n", _fcvt(d1, 10, &dec, &sign));    //MS-specific, the base primitive convertion function
    }
}


MSVC:

[10715086071862673000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000.000000]
[10715086071862673000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000.000000]
[10715086071862673000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000]


GCC(MinGW):

[


Вообще вырубает поток! Вот так бага Неправильный double выключает output программы

А должен печатать
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.000000

Вот такая вот бага. Не могут число перевести в десятичную систему счисления...
Правильно работающая программа — просто частный случай Undefined Behavior
Re: бага в распечатке double
От: __LP  
Дата: 01.10.05 23:50
Оценка: :)))
Здравствуйте, _Winnie, Вы писали:

Если бага, то может быть собственный класс написать вещественных чисел? А может такой уже есть?

P.S. А программа что делает? Выдает расстояние от Земли до Солнца в миллиметрах?
C++ можно выучить за 21 день! ...если дни — полярные.
Re: бага в распечатке double
От: __LP  
Дата: 02.10.05 00:05
Оценка:
Здравствуйте, _Winnie, Вы писали:


ИМХО это не бага. Просто в double не влезает столько цифр. std::numeric_limits<double>::digits10 вообще дает 15
C++ можно выучить за 21 день! ...если дни — полярные.
Re: IMHO, всё правильно.
От: ZAMUNDA Земля для жалоб и предложений
Дата: 02.10.05 00:32
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>
_W>int main()
_W>{

_W>    //2^1000  
_W>    double d1 = 
_W>        10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.0;

_W>    long long d_int =
_W>        (1023LL + 1000LL) << 52; 
_W>    double d2 = *(double*)&d_int; //тоже самое.

_W>    assert(d1 == d2);

_W>    {

_W>        std::cout <<'[' <<std::fixed << d1 <<"]\n";
_W>        printf("[%f]\n", d1);
_W>        int dec, sign;
_W>        printf("[%s]\n", _fcvt(d1, 10, &dec, &sign));    //MS-specific, the base primitive convertion function
_W>    }
_W>}
_W>


_W>MSVC:

Мой MSVC вообще такое не компилит. ;)

fatal error C1064: compiler limit : token overflowed internal buffer


_W>
_W>[10715086071862673000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
_W>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
_W>000.000000]
_W>


_W>А должен печатать

_W>10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376.000000
Погодите, почему должен? -- В стандарте IEEE прописано что на мантиссу отводится 52 бит = 1 (знак) + 51 (значение) таким образом максимальное положительное число выходит 14503599627370495. Порядок, в данном случае, больше нуля, значит мантисса нормализуется с единицей т.е. 14503599627370495 читается как 114503599627370495. Из определённого вами значения, в означенный диапазон вполне влезает 17 первых разрядов, т.е. 10715086071862673, а остальное, по стандарту, считается нулём. По-моему всё именно так... незнаю... поправьте если я не прав.

PS:IEEE format
PPS: Там, конечно, максимальное значение указано 7976931348623158, т.е. 17976931348623158 -- в своё время я знал откуда это значение берется, но сейчас не могу вспомнить, сорры.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[2]: бага в распечатке double
От: __LP  
Дата: 02.10.05 00:43
Оценка:
Может это поможет.

The data type bigfloat can be used to represent floating point numbers with arbitrary precision.

Звучит многообещающе, хотя дальше не смотрел.
C++ можно выучить за 21 день! ...если дни — полярные.
Re[2]: IMHO, всё правильно.
От: _Winnie Россия C++.freerun
Дата: 02.10.05 11:53
Оценка: :)
Здравствуйте, ZAMUNDA, Вы писали:

ZAM>Здравствуйте, _Winnie, Вы писали:


ZAM>Погодите, почему должен? -- В стандарте IEEE прописано что на мантиссу отводится 52 бит = 1 (знак) + 51 (значение) таким образом максимальное положительное число выходит 14503599627370495. Порядок, в данном случае, больше нуля, значит мантисса нормализуется с единицей т.е. 14503599627370495 читается как 114503599627370495. Из определённого вами значения, в означенный диапазон вполне влезает 17 первых разрядов, т.е. 10715086071862673, а остальное, по стандарту, считается нулём. По-моему всё именно так... незнаю... поправьте если я не прав.


Ничего не понял. Размер экспоненты — 11. Значит, double может представлять конечные числа влоть до (2^53-1)/2^52 * 2^(2^(11-1)-1) ~= 2 * 2^1023 = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0. Почему ты ограничил число размером мантиссы?

ZAM>PS:IEEE format

ZAM>PPS: Там, конечно, максимальное значение указано 7976931348623158, т.е. 17976931348623158 -- в своё время я знал откуда это значение берется, но сейчас не могу вспомнить, сорры.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[2]: бага в распечатке double
От: _Winnie Россия C++.freerun
Дата: 02.10.05 11:54
Оценка: :)
Здравствуйте, __LP, Вы писали:

__L>Здравствуйте, _Winnie, Вы писали:



__L>ИМХО это не бага. Просто в double не влезает столько цифр. std::numeric_limits<double>::digits10 вообще дает 15


Return Value
The number of decimal digits that the type can represent without loss of precision.



Причем здесь это?
Мой 2^1000 double может представлять без всякого loss of precision.
Проблема не в точности double, numeric_limits относится только к этому, проблема в стандартной библиотеке вывода.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[2]: бага в распечатке double
От: _Winnie Россия C++.freerun
Дата: 02.10.05 11:55
Оценка:
Здравствуйте, __LP, Вы писали:

__L>Здравствуйте, _Winnie, Вы писали:


__L>Если бага, то может быть собственный класс написать вещественных чисел? А может такой уже есть?

Мне не надо другой класс вещественных чисел. Мне нужен стандартный double. И мне надо его распечатать.

__L>P.S. А программа что делает? Выдает расстояние от Земли до Солнца в миллиметрах?


Нет, до солнца всего навсего лишь примерно 149547836378187 миллиметров
Просто надо написать свою библиотеку вывода чисел.
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: бага в распечатке double
От: __LP  
Дата: 02.10.05 12:43
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Здравствуйте, __LP, Вы писали:


__L>>Здравствуйте, _Winnie, Вы писали:



__L>>ИМХО это не бага. Просто в double не влезает столько цифр. std::numeric_limits<double>::digits10 вообще дает 15


_W>

_W>Return Value
_W>The number of decimal digits that the type can represent without loss of precision.



_W>Причем здесь это?

_W>Мой 2^1000 double может представлять без всякого loss of precision.

Можно, но откуда библиотека вывода должна об этом знать? По внутреннему представлению чисел невозможно определить...

_W>Проблема не в точности double, numeric_limits относится только к этому, проблема в стандартной библиотеке вывода.
C++ можно выучить за 21 день! ...если дни — полярные.
Re: бага в распечатке double
От: Кодт Россия  
Дата: 02.10.05 21:19
Оценка: 1 (1)
Здравствуйте, _Winnie, Вы писали:

_W>Вот такая вот бага. Не могут число перевести в десятичную систему счисления...


А ты хотел, чтобы вместо тучи нулей вывелись все десятичные разряды? Дык вотще.
Числа с плавающей запятой суть приближённые значения. То есть, некоторому значению float или double соответствует диапазон вещественных чисел:
{m,p} -> (m±d)*2^p = m*2^p ± d*2^p = [m*2^p — d^2*p, m*2^p + d^2*p)
где m — мантисса, p — порядок, d — половина младшего разряда (т.е. 2^-52).

Так что при выводе в десятичном виде достаточно найти более-менее круглое десятичное число, попадающее в этот диапазон. Оно ничем не хуже твоей тучи цифр, а для программы — так даже лучше: его можно более компактно представить в десятичном плавающем виде: m'*10^p' (разрядность десятичной мантиссы тоже не резиновая).
Перекуём баги на фичи!
Re[3]: Я тебе один умный вещь скажу.... ;)
От: ZAMUNDA Земля для жалоб и предложений
Дата: 02.10.05 23:24
Оценка:
Здравствуйте, _Winnie, Вы писали:

ZAM>>Погодите, почему должен? -- В стандарте IEEE прописано что на мантиссу отводится 52 бит = 1 (знак) + 51 (значение) таким образом максимальное положительное число выходит 14503599627370495. Порядок, в данном случае, больше нуля, значит мантисса нормализуется с единицей т.е. 14503599627370495 читается как 114503599627370495. Из определённого вами значения, в означенный диапазон вполне влезает 17 первых разрядов, т.е. 10715086071862673, а остальное, по стандарту, считается нулём. По-моему всё именно так... незнаю... поправьте если я не прав.


_W>Ничего не понял. Размер экспоненты — 11. Значит, double может представлять конечные числа влоть до (2^53-1)/2^52 * 2^(2^(11-1)-1) ~= 2 * 2^1023 = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0. Почему ты ограничил число размером мантиссы?

Я не ЧИСЛО, а значение мантиссы ограничил. В представлении с плавающей точкой, сохраняются значения разрядов (РАЗРЯДОВ!!! ну циферек), "влезающих" в мантиссу, а остальные (в данном случае младшие) разряды считаются нулями. Это даже не вопрос программирования, а вопрос здравого смысла -- НУ КАК ВЫ ПРЕДСТАВЛЯЕТЕ 308 ЦИФР В 52 БИТАХ ЗАКОДИРОВАТЬ???
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[2]: бага в распечатке double
От: _Winnie Россия C++.freerun
Дата: 03.10.05 18:12
Оценка:
А моя либа (в зачаточном состоянии) уже правильно выводит целую часть чисел, даже самых больших. Вот так вот. Потратил на это 300 строчек и полтора дня...

#define TEST(e, msg) do { if (!(e)) { printf msg; /*{ __asm int 3 }*/}  } while(0);
int main()
{
    for (int j = 1; j<10; ++j)
    {
        large_int_t i_pow2(j);
        double d_pow2(j);
        for (int i=0; i<1000; ++i)
        {
            std::string s;
            print_double_int_part(std::back_inserter(s), d_pow2);
            if (1) for (int i=0, i_end = s.size(); i<i_end; ++i)
                s[i]-='0';
            TEST(std::equal(s.rbegin(), s.rend(), i_pow2.m_data), ("i = %d, j = %d\n", i, j));
            i_pow2 *= 2;
            d_pow2 *= 2;
        }
    }

    return 526;
}
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: бага в распечатке double
От: Alex Alexandrov США  
Дата: 03.10.05 19:28
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>А моя либа (в зачаточном состоянии) уже правильно выводит целую часть чисел, даже самых больших. Вот так вот. Потратил на это 300 строчек и полтора дня...


_W>
_W>#define TEST(e, msg) do { if (!(e)) { printf msg; /*{ __asm int 3 }*/}  } while(0);
_W>int main()
_W>{
_W>    for (int j = 1; j<10; ++j)
_W>    {
_W>        large_int_t i_pow2(j);
_W>        double d_pow2(j);
_W>        for (int i=0; i<1000; ++i)
_W>        {
_W>            std::string s;
_W>            print_double_int_part(std::back_inserter(s), d_pow2);
_W>            if (1) for (int i=0, i_end = s.size(); i<i_end; ++i)
_W>                s[i]-='0';
_W>            TEST(std::equal(s.rbegin(), s.rend(), i_pow2.m_data), ("i = %d, j = %d\n", i, j));
_W>            i_pow2 *= 2;
_W>            d_pow2 *= 2;
_W>        }
_W>    }

_W>    return 526;
_W>}
_W>


Ну да, ты их всех уделал. Осталось только определиться, ставишь ты пробелы вокруг '=' или нет.

По сути вопроса: размер double — 8 байт. Размер твоего вмещающего-что-угодно large_int_t — наверное, больше. Так что не очень ты их уделал. Советую почитать что-нибудь по floating point и fixed point форматах.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
It's kind of fun to do the impossible (Walt Disney)
Re[4]: бага в распечатке double
От: _Winnie Россия C++.freerun
Дата: 03.10.05 21:11
Оценка: :)
Здравствуйте, Alex Alexandrov, Вы писали:

AA>Здравствуйте, _Winnie, Вы писали:


AA>Ну да, ты их всех уделал. Осталось только определиться, ставишь ты пробелы вокруг '=' или нет.

Корпоративный стиль поломал мой стиль А сейчас еще с товарищами фигню мутим, там третий стить Тяжело мне.

>По сути вопроса: размер double — 8 байт.

+1. Согласен
>Размер твоего вмещающего-что-угодно large_int_t — наверное, больше.
+1. Угадал
>Так что не очень ты их уделал.
Не понял. Ну, больше, и что? Здесь он используется для тестирования.

>Советую почитать что-нибудь по floating point и fixed point форматах.

Хм. А как бы я потвому распечатал бы double, если бы не знал его формат
    struct double_t
    {
        explicit double_t(double in_d)
        {
            STATIC_ASSERT(sizeof(*this) == sizeof(double), _);
            *(double*)this = in_d;
        }

        uint64_t m_mantiss : double_mant_size;
        uint64_t m_exponent : double_exp_size;
        uint64_t m_sign : 1;
    };


PS. Со сверхмаленькими числами у стандартной библиотеки тоже хреново...
Правильно работающая программа — просто частный случай Undefined Behavior
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.