Здравствуйте, LaptevVV, Вы писали:
LVV>Как реализована арифметика c long double в gcc ? LVV>Размер пишет 16 байт, но в интел такого аппаратного размера нет. LVV>Или в современных уже есть ?
В документации, как в той Греции, есть всё:
'-m96bit-long-double'
'-m128bit-long-double'
These switches control the size of 'long double' type. The x86-32
application binary interface specifies the size to be 96 bits, so
'-m96bit-long-double' is the default in 32-bit mode.
Modern architectures (Pentium and newer) prefer 'long double' to be
aligned to an 8- or 16-byte boundary. In arrays or structures
conforming to the ABI, this is not possible. So specifying
'-m128bit-long-double' aligns 'long double' to a 16-byte boundary
by padding the 'long double' with an additional 32-bit zero.
In the x86-64 compiler, '-m128bit-long-double' is the default
choice as its ABI specifies that 'long double' is aligned on
16-byte boundary.
Notice that neither of these options enable any extra precision
over the x87 standard of 80 bits for a 'long double'.
В стандарте есть рекомендации на формат для любого размера числа, кратного 32 битам. Но 256 там явно не выделяется — это инициатива "на местах" от авторов википедии.
LVV>Но насколько они реализованы в железе ?
Эта проблема присуща не только long double.
Каждый компилятор даже на одной платформе может использовать разные размеры для примитивных типов.
Например, wchar_t 4 байта в GCC но 2 байта в MSVC.
А может быть, что и long double всего 8 байт в MSVC.
Или ещё упрощенней 32 битный компилятор с размеров указателя 32 бит.
Резьмирая, если вы хотите записать в файл прямо из памяти и также читать, то тут надо хорошо заранее продумать кто будет читать и кто писать.
А лучше всего сериализовать так, чтобы не нужно было думать о таких нюансах.
AD>>>Выравнивание. LVV>>И что ? AD>Что и что? long double занимает 16 байт, из них используется 10.
1. Это я и хотел услышать
Но выравнивание здесь причем ?
Тут происходит усечение мантиссы. LVV>>Еще в i386 проблема выравнивания как-то была сильно сглажена. LVV>>И вообще-то размер параграфа был еще в 16-битной адресации равен 16 байтам. AD>Чо?
Это к 1 строке или к последней.
Если к последней, то параграф — это 16 байт.
Сегментный регистр, когда участвовал в вычислении адреса, сдвигался на 4 бита влево (становился 20 бит) и таким образом выравнивался на границу параграфа.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
AD>>Что и что? long double занимает 16 байт, из них используется 10. LVV>1. Это я и хотел услышать LVV>Но выравнивание здесь причем ?
Чтобы ровно и четко все было, а не эти ваши 10 байт, которые и в массив не положишь.
LVV>Тут происходит усечение мантиссы.
А экспоненты нет? Чтобы что-то усеч, надо чтобы это что-то было. А его не было.
Ты смотришь на это как на то, что раз 16 байт, значит все они под значение использоваться должны. Тогда как по факту поддержали 80 битные числа, а потом добили их до приемлемого выравнивания в 128 бит.
Здравствуйте, andrey.desman, Вы писали:
M>>Получается, из двоичного файла я не смогу прочитать long double в gcc простым memcpy sizeof(long double)?
AD>Почему нет? Если сам же и писал.
Ну, то есть, конечно можно, но тогда уже использовать sizeof(long double) не получится, надо магическую константу 10 использовать. И, видимо, структуру, где есть long double, одним махом не считать.
Когда сам писал, то всё просто, но двоичные форматы обычно даются нам свыше
Как реализована арифметика c long double в gcc ?
Размер пишет 16 байт, но в интел такого аппаратного размера нет.
Или в современных уже есть ?
Регистры сопроцессора были по 80 бит.
Но последняя версия стандарта ieee-754 включает 128-битные дробные
Кто знает, оно уже в аппаратуре есть или нет ?
Версия gcc jn 8.1 до 11.0
С++17 по любому есть (хотя в 8.1 не совсем полный).
Здравствуйте, LaptevVV, Вы писали:
LVV>Как реализована арифметика c long double в gcc ? LVV>Размер пишет 16 байт, но в интел такого аппаратного размера нет.
LVV>>Как реализована арифметика c long double в gcc ? LVV>>Размер пишет 16 байт, но в интел такого аппаратного размера нет. AD>Выравнивание.
И что ?
Еще в i386 проблема выравнивания как-то была сильно сглажена.
И вообще-то размер параграфа был еще в 16-битной адресации равен 16 байтам.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
AD>>Выравнивание. LVV>И что ?
Что и что? long double занимает 16 байт, из них используется 10.
LVV>Еще в i386 проблема выравнивания как-то была сильно сглажена. LVV>И вообще-то размер параграфа был еще в 16-битной адресации равен 16 байтам.
LVV>>Как реализована арифметика c long double в gcc ? PD>Написать программу из 3 строчек, откомпилировать в режиме создания ассемблерного текста и посмотреть ?
Да, спасибо. Чего-то в голову как-то не пришло — редко до до ассемблера спускаться приходится.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
И в intel x64 смешивать использование FPU, SSE и AVX не благославляется. При это 80bit регистры FPU чуть ли не depricated. Прямо большими буквами написано или то или другое иначе пи%&ец.
Здравствуйте, andrey.desman, Вы писали:
AD>Ты смотришь на это как на то, что раз 16 байт, значит все они под значение использоваться должны. Тогда как по факту поддержали 80 битные числа, а потом добили их до приемлемого выравнивания в 128 бит.
Получается, из двоичного файла я не смогу прочитать long double в gcc простым memcpy sizeof(long double)?
Здравствуйте, Marty, Вы писали:
M>Ну, то есть, конечно можно, но тогда уже использовать sizeof(long double) не получится, надо магическую константу 10 использовать. И, видимо, структуру, где есть long double, одним махом не считать.
Почему? Что там в паддинге пофиг вообще. Как читать зависит исключительно от формата, 10 там байт или 16.
Здравствуйте, Marty, Вы писали:
M>Ну, то есть, конечно можно, но тогда уже использовать sizeof(long double) не получится, надо магическую константу 10 использовать. И, видимо, структуру, где есть long double, одним махом не считать.
Всё же проще записывать и считывать по 16 байт — особенно, если это массив, а не единичное значение. То, что из них значащих 80 бит — никак не помешает (если не заморачиваться упаковкой по размеру).
А вот разбивать массив long double на 10-байтные отрезки и сериализовать это — геморрой на ровном месте без практической пользы.
Здравствуйте, andrey.desman, Вы писали:
M>>Ну, то есть, конечно можно, но тогда уже использовать sizeof(long double) не получится, надо магическую константу 10 использовать. И, видимо, структуру, где есть long double, одним махом не считать.
AD>Почему? Что там в паддинге пофиг вообще. Как читать зависит исключительно от формата, 10 там байт или 16.
Не понял. Записали компилятором, у которого нет паддинга. Читаем компилятором с паддингом. Как я понимаю, какие опции pragma pack не используй, а в структуре это поле всегда 16 байт будет. Итого — структуру целиком не прочитать, только поля по отдельности. Ну и когда по отдельности long double читаешь, нельзя использовать sizeof(long double), а надо константу 10 использовать
Здравствуйте, flаt, Вы писали:
F>Всё же проще записывать и считывать по 16 байт — особенно, если это массив, а не единичное значение. То, что из них значащих 80 бит — никак не помешает (если не заморачиваться упаковкой по размеру).
F>А вот разбивать массив long double на 10-байтные отрезки и сериализовать это — геморрой на ровном месте без практической пользы.
В памяти — безусловно, там размер пофигу. А при обмене двоичными данными — по другому никак не получится, другие компиляторы имеют свой размер long double
Здравствуйте, Marty, Вы писали:
M>Не понял. Записали компилятором, у которого нет паддинга. Читаем компилятором с паддингом. Как я понимаю, какие опции pragma pack не используй, а в структуре это поле всегда 16 байт будет. Итого — структуру целиком не прочитать, только поля по отдельности. Ну и когда по отдельности long double читаешь, нельзя использовать sizeof(long double), а надо константу 10 использовать
Я б так сериализацию не делал, но если уж так хочется, то union {long double; char padding[16];} stuctMember;
Здравствуйте, andrey.desman, Вы писали:
M>>Не понял. Записали компилятором, у которого нет паддинга. Читаем компилятором с паддингом. Как я понимаю, какие опции pragma pack не используй, а в структуре это поле всегда 16 байт будет. Итого — структуру целиком не прочитать, только поля по отдельности. Ну и когда по отдельности long double читаешь, нельзя использовать sizeof(long double), а надо константу 10 использовать
AD>Я б так сериализацию не делал, но если уж так хочется, то union {long double; char padding[16];} stuctMember;
И как это решит проблему с данными, которые формирует кто-то другой?
Здравствуйте, Marty, Вы писали:
M>И как это решит проблему с данными, которые формирует кто-то другой?
По-хорошему, и сериализацию, и десериализацию должна выполнять одна и та же софтина, которая и обеспечивает портабельность, версионность, обратную совместимось и пр. (в том объеме, в котором это требуется).
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, LaptevVV, Вы писали:
LVV>Как реализована арифметика c long double в gcc ? LVV>Размер пишет 16 байт, но в интел такого аппаратного размера нет.
Если ты про long double, то не знаю
Если про __float128, то эмуляция, причём в десятки раз медленнее нативных типов
Здравствуйте, _NN_, Вы писали:
_NN>Эта проблема присуща не только long double. _NN>Каждый компилятор даже на одной платформе может использовать разные размеры для примитивных типов. _NN>Например, wchar_t 4 байта в GCC но 2 байта в MSVC. _NN>А может быть, что и long double всего 8 байт в MSVC. _NN>Или ещё упрощенней 32 битный компилятор с размеров указателя 32 бит.
Есть всякие std::int/uintXX_t.
wchar обычно в двоичном виде не читают, особенно линуксовый 4х-байтный, там это никто так не хранит
С целыми это всегда можно настроить тайпдефами
_NN>Резьмирая, если вы хотите записать в файл прямо из памяти и также читать, то тут надо хорошо заранее продумать кто будет читать и кто писать. _NN>А лучше всего сериализовать так, чтобы не нужно было думать о таких нюансах.
Конечно, лучше всего сдялат сразу без ошибок, кто бы спорил
Здравствуйте, Marty, Вы писали:
M>Есть всякие std::int/uintXX_t.
Ну дык, это ж нужно еще не забывать при сериализации/десериализации делать доп. преобразования. Потому как в объектных моделях, помимо этих типов, в полный рост используются всякие int, long, size_t и т.п. У нас на протяжении многих лет, пока поддерживали 32-битные конфигурации (одновременно с 64-битными) это было прямо болячкой. Хоть и знали все об этом, но, как какое-нибудь расширение модели, так обязательно кто-нибудь прощелкает этот момент.
--
Не можешь достичь желаемого — пожелай достигнутого.
_NN>Каждый компилятор даже на одной платформе может использовать разные размеры для примитивных типов. _NN>Например, wchar_t 4 байта в GCC но 2 байта в MSVC. _NN>А может быть, что и long double всего 8 байт в MSVC.
Совершенно верно.
Именно так у них и сделано с незапямятных времен.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, _NN_, Вы писали:
_NN>>Эта проблема присуща не только long double. _NN>>Каждый компилятор даже на одной платформе может использовать разные размеры для примитивных типов. _NN>>Например, wchar_t 4 байта в GCC но 2 байта в MSVC. _NN>>А может быть, что и long double всего 8 байт в MSVC. _NN>>Или ещё упрощенней 32 битный компилятор с размеров указателя 32 бит.
M>Есть всякие std::int/uintXX_t. M>wchar обычно в двоичном виде не читают, особенно линуксовый 4х-байтный, там это никто так не хранит M>С целыми это всегда можно настроить тайпдефами
_NN>>Резьмирая, если вы хотите записать в файл прямо из памяти и также читать, то тут надо хорошо заранее продумать кто будет читать и кто писать. _NN>>А лучше всего сериализовать так, чтобы не нужно было думать о таких нюансах.
M>Конечно, лучше всего сдялат сразу без ошибок, кто бы спорил
А что мешает взять простое готовое решение, скажем Protobuf, а не создавать своё полуработающее поделие.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, andrey.desman, Вы писали:
M>>>Ну, то есть, конечно можно, но тогда уже использовать sizeof(long double) не получится, надо магическую константу 10 использовать. И, видимо, структуру, где есть long double, одним махом не считать.
AD>>Почему? Что там в паддинге пофиг вообще. Как читать зависит исключительно от формата, 10 там байт или 16.
M>Не понял. Записали компилятором, у которого нет паддинга. Читаем компилятором с паддингом. Как я понимаю, какие опции pragma pack не используй, а в структуре это поле всегда 16 байт будет. Итого — структуру целиком не прочитать, только поля по отдельности. Ну и когда по отдельности long double читаешь, нельзя использовать sizeof(long double), а надо константу 10 использовать
Следующим открытием для вас будут понятия low endian/big endian. Лучше берите готовый сериализатор.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, _NN_, Вы писали:
_NN>>А что мешает взять простое готовое решение, скажем Protobuf, а не создавать своё полуработающее поделие.
M>Потому что в 90% случаев данные приходят и уходят от/в сторонный софт
А как этот сторонний софт решил проблему сериализации?
Вряд ли записывает данные которые невозможно прочитать будет на другой платформе.
Здравствуйте, _NN_, Вы писали:
M>>Потому что в 90% случаев данные приходят и уходят от/в сторонный софт
_NN>А как этот сторонний софт решил проблему сериализации? _NN>Вряд ли записывает данные которые невозможно прочитать будет на другой платформе.
Сериализовали тупо структурами. Просто компилятор был другой. Вот тебе простой пример
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, _NN_, Вы писали:
M>>>Потому что в 90% случаев данные приходят и уходят от/в сторонный софт
_NN>>А как этот сторонний софт решил проблему сериализации? _NN>>Вряд ли записывает данные которые невозможно прочитать будет на другой платформе.
M>Сериализовали тупо структурами. Просто компилятор был другой. Вот тебе простой пример
В таком случае это конечно боль.
Надо в своём коде определить всё в точности как в другом.
Даже при одном компиляторе с разным порядком заголовочных файлов и разных флагов можно получить неправильную сериализацию.
Здравствуйте, SaZ, Вы писали:
SaZ>Следующим открытием для вас будут понятия low endian/big endian. Лучше берите готовый сериализатор.
Ага. Только big endian мертв на всех популярных десктопных и серверных платформах если мы про передачу файлов говорим. Даже IBM Power на их собственных процессорах и ОС перешли на little endian.
У Лаптева контекста кроме x86 не бывает (покамест)
А на POWER много хитрого есть, даже десятичная плавучка в железе.
_>И в intel x64 смешивать использование FPU, SSE и AVX не благославляется. При это 80bit регистры FPU чуть ли не depricated. Прямо большими буквами написано или то или другое иначе пи%&ец.
Тем не менее их тоже лечат. Например, примерно с 2008 стали лечить старые проблемы с непредсказуемо большим временем работы с денормализованными. Видимо, кто-то из крупных клиентов додавил.
Здравствуйте, LaptevVV, Вы писали:
LVV>Но насколько они реализованы в железе ?
А зачем обязательно в железе-то? В железе есть хотя бы float и все остальные операции
можно свести к нему. Ну и что, что в 10 раз медленее. Зачем вообще long double -- ещё вопрос.
Числа с плавающей точкой затем и придуманы, чтоб не нужны были очень длинные целочисленные.
Здравствуйте, fk0, Вы писали:
LVV>>Но насколько они реализованы в железе ?
fk0> А зачем обязательно в железе-то? В железе есть хотя бы float и все остальные операции fk0>можно свести к нему. Ну и что, что в 10 раз медленее. Зачем вообще long double -- ещё вопрос.
Если вы уж хотите эмулировать double, например, на float... легче на целых эмулировать.
fk0>Числа с плавающей точкой затем и придуманы, чтоб не нужны были очень длинные целочисленные.
Здравствуйте, LaptevVV, Вы писали:
LVV>Еще в i386 проблема выравнивания как-то была сильно сглажена. LVV>И вообще-то размер параграфа был еще в 16-битной адресации равен 16 байтам.
В SSE/AVX часть команд толерантно относятся к выравниванию, а часть прям требуют выравнивание на размер соответствующего регистра (т.е., 128/256/512 бит, в зависимости от команды).
Здравствуйте, Marty, Вы писали:
M>Получается, из двоичного файла я не смогу прочитать long double в gcc простым memcpy sizeof(long double)?
Не надо так вообще делать, оставлять чтение-запись в файл на усмотрение компилятора. Чиселки в файле должны в каком-то стандарте быть (IEEE 754 с выбранной тобой, а не компилятором, битностью и byte ordering — хороший вариант), но никто тебе не обещал, что в памяти на хосте они у тебя будут в таком же виде.
Здравствуйте, TheBeginner, Вы писали:
TB>Ага. Только big endian мертв на всех популярных десктопных и серверных платформах если мы про передачу файлов говорим. Даже IBM Power на их собственных процессорах и ОС перешли на little endian.
Вроде как у вполне живых ARM-ов бывает BE. MIPS, кажется, бывает BE, и MIPS иногда ставят во всякие там роутеры. И китайцы MIPS любят, они умеют его делать сами. IBM/390 — он не BE разве?