Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?
Тут как минимум имеются следующие проблемы:
1) как бороться с разной "endianess";
2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
Здравствуйте, _hum_, Вы писали:
__>Тут как минимум имеются следующие проблемы: __>1) как бороться с разной "endianess"; __>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
Как я понимаю, float определяется не платформой, а стандартом IEEE(single precisio, double, quad), т.е. переносим.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, _hum_, Вы писали:
__>Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?
тут без плясок не обойтись, поэтому методов море и чаще всего они неуниверсальны (могут потерять часть информации)
1) можно в строковом представлении гонять. нужно зафиксировать формат (число знаков после запятой, разделитель, возможность использования экспоненциальной записи, представление спец значений типа signalling NAN, inf, etc)
2) можно за основу взять IEEE 754 и научиться выделять из float / строить float из тех самых компоненты, которые легко маршалятся: знак, мантисса, экспонента (их можно целыми числами передавать). за базу можно взять двойку или десятку
3) можно делать какую-нибудь нормализацию типа домножать на 10^6 и округлять до целого. 6 либо зафиксировать, либо передавать частью данных. пример: 123.4567 передаем как {4, 1234567}; 123.4567891 передаем как {7, 1234567891}; 0.000123 передаем как {-6, 123}
4) можно упаковать в формат IEEE 754 (зафиксировать endianess), но и распаковку придется делать на тех системах, где этот формат неродной. зато на системах, где это родной формат, запись и чтение данных будет простым memcpy (неродной endianness тут почти никак не усложняет чтение, нужно просто правильно байтики переставить)
Re[2]: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, _hum_, Вы писали:
__>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными? __>Тут как минимум имеются следующие проблемы: __>1) как бороться с разной "endianess"; __>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, _hum_, Вы писали:
__>>Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?
U>тут без плясок не обойтись, поэтому методов море и чаще всего они неуниверсальны (могут потерять часть информации) U>1) можно в строковом представлении гонять. нужно зафиксировать формат (число знаков после запятой, разделитель, возможность использования экспоненциальной записи, представление спец значений типа signalling NAN, inf, etc)
вы имеете в виду в строковом представлении сами числа? у меня поначалу так и было, но заказчик засомневался в скорости, ведь приходится выполнять конвертации из числовой в строковую и обратно [реально же проверить быстродействие пока нет возможности]
U>2) можно за основу взять IEEE 754 и научиться выделять из float / строить float из тех самых компоненты, которые легко маршалятся: знак, мантисса, экспонента (их можно целыми числами передавать). за базу можно взять двойку или десятку
да, пока тоже, думаю, это самый хороший вариант — использовать предположение о наличии поддержки IEEE 754 (я ж так понимаю, современные компы его поддерживают?) и, отталкиваясь от него, разлагать число на мантиссу, порядок (по идее, это должны быть быстрые операции), после чего через умножение на (2<< std::numeric_limits::digits()) приводить мантиссу к целочисленному значению. получится представление — целочисленная мантисса и порядок
U>3) можно делать какую-нибудь нормализацию типа домножать на 10^6 и округлять до целого.
это дробную часть переведет в целое, но результирующее число может получится не вмесщающимся в диапазон целочсиселнного типа, поэтому нужно будет как-то порядок выделять и убирать
U>6 либо зафиксировать, либо передавать частью данных. пример: 123.4567 передаем как {4, 1234567}; 123.4567891 передаем как {7, 1234567891}; 0.000123 передаем как {-6, 123}
опять же, насколько быстрый по сравнению с конвертацией в строку алгоритм нормализации и обратно, "сборки"?
U>4) можно упаковать в формат IEEE 754 (зафиксировать endianess), но и распаковку придется делать на тех системах, где этот формат неродной. зато на системах, где это родной формат, запись и чтение данных будет простым memcpy (неродной endianness тут почти никак не усложняет чтение, нужно просто правильно байтики переставить)
так а упаковка в IEEE 754 разве быстрое дело (по сравнению с конвертацией в строковое)?
Re[2]: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, PM, Вы писали:
PM>Здравствуйте, _hum_, Вы писали:
__>>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными? __>>Тут как минимум имеются следующие проблемы: __>>1) как бороться с разной "endianess"; __>>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
PM>Получить значения мантиссы и экспоненты, сериализовать с требуемой endianess. Типа такого: http://stackoverflow.com/a/14955046/1355844
а почему в приведенной ссылке такой сложный код? неужели и мне такой придется писать (со всякими "магическими числами")?
Re[3]: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, _hum_, Вы писали:
__>Здравствуйте, PM, Вы писали:
PM>>Здравствуйте, _hum_, Вы писали:
__>>>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными? __>>>Тут как минимум имеются следующие проблемы: __>>>1) как бороться с разной "endianess"; __>>>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
PM>>Получить значения мантиссы и экспоненты, сериализовать с требуемой endianess. Типа такого: http://stackoverflow.com/a/14955046/1355844
__>а почему в приведенной ссылке такой сложный код? неужели и мне такой придется писать (со всякими "магическими числами")?
Вам решать как писать , но если вы хотите кроссплатформенный код, то функции std::frexp и std::ldexp как раз позволяют получить значения экспоненты и мантиссы соответственно. Я бы ещё добавил static_assert(std::numeric_limits<float>::is_iec559 && std::numeric_limits<float>::radix == 2), так как не уверен что сработает для других представлений вещественных чисел.
Код по ссылке написан для double и подробно прокомментирован, за исключением магического числа 53, это numeric_limits<double>::digits
Re: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, _hum_, Вы писали:
__>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными? __>Тут как минимум имеются следующие проблемы: __>1) как бороться с разной "endianess"; __>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
Сейчас уже крайне сложно найти платформу, где не IEEE754. Поэтому проблема сокращается только до endianness, а её уже можно доработать просто инверсией порядка байт.
__>Попадающийся при гуглении вариант writing-endian-independent-code-in-c смущает кодом
Ну туповато написано, но по идее будет хорошо оптимизироваться.
__>и тем, что никак не решает проблемы 2).
Потому что этой проблемы в реальном мире нет.
Реальном — в том смысле, что тебе наверняка не придётся работать с VAX, PDP-11, или S/360 (с поправкой на то, что у zSeries есть команды и для IEEE, и для родных старых форматов). Ну и не надо использовать long double на x86 и m68k, конечно.
The God is real, unless declared integer.
Re[2]: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, _hum_, Вы писали:
__>>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными? __>>Тут как минимум имеются следующие проблемы: __>>1) как бороться с разной "endianess"; __>>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).
N>Сейчас уже крайне сложно найти платформу, где не IEEE754. Поэтому проблема сокращается только до endianness, а её уже можно доработать просто инверсией порядка байт.
а как корректно делать инверсию для float (без union)?
__>>и тем, что никак не решает проблемы 2).
N>Потому что этой проблемы в реальном мире нет.
см. выше про трудности непереносимости даже в рамках IEEE754.
п.с. я тут задумался — ведь и обычные знаковые целые в бинарных файлах тоже непереносимы, потому как представление отрицательных чисел могут быть в разных форматах — как с битом знака, так и в дополнительном коде. ведь так?
Re[3]: платформонезависимая (де-/)сериализация вещественных чисел
Здравствуйте, _hum_, Вы писали:
N>>Сейчас уже крайне сложно найти платформу, где не IEEE754. Поэтому проблема сокращается только до endianness, а её уже можно доработать просто инверсией порядка байт.
__>если так, можете ответить на вопрос: why-is-ieee-754-floating-point-not-exchangable-between-platforms? __>[и привести, как там просят, хотя бы набросок кода]
Всерьёз ответить там — это надо думать над рядом обстоятельств, которые я тут постараюсь расписать. Проблема не в float или IEEE754 как таковом. Проблемы скорее на уровне C.
Дело в том, что в принципе все методы, которые используются в нём для таких действий, как переразобрать представление одного типа в другом, в чём-то проблемны. Стандарт C слишком много повтыкал в него всяких undefined behavior, implementation defined и тому подобного.
Если же это обойти, убрав компилятору неестественный интеллект, то годится любой вариант, и union с charʼом тут далеко не худший вариант, но при этом предельно простой.
(Есть ряд других мелких тонкостей. Например, IEEE754-2008 зафиксировал представления SNAN и QNAN. В IEEE754-1985 этого ещё не было. Ряд платформ использовал их противоположным образом — сейчас с ходу не помню, какие — и они пострадали. Но вряд ли они сейчас встречаются.)
__>>>Попадающийся при гуглении вариант writing-endian-independent-code-in-c смущает кодом
N>>Ну туповато написано, но по идее будет хорошо оптимизироваться. __>а как корректно делать инверсию для float (без union)?
Возможно, и никак. По крайней мере переносимо. Можно отточить метод для каждой платформы отдельно, но union + защита от оптимизации доступа (самое жёсткое — volatile, но где-то сработает и no-strict-aliasing) — хватит для реально практически любой современной платформы. Я не считаю тут, конечно, всякие 22-битные DSP и прочие ужасы особого ранга.
__>>>и тем, что никак не решает проблемы 2). N>>Потому что этой проблемы в реальном мире нет. __>см. выше про трудности непереносимости даже в рамках IEEE754.
Я прочитал, но так и не понял, в чём собственно видится трудность. Повторюсь — она не в IEEE. Она на уровне C. Или же я чего-то не увидел — тогда прошу процитировать конкретное место.
__>п.с. я тут задумался — ведь и обычные знаковые целые в бинарных файлах тоже непереносимы, потому как представление отрицательных чисел могут быть в разных форматах — как с битом знака, так и в дополнительном коде. ведь так?
Да. Могут. Более того, в C это отражено в нескольких местах — начиная с того, что явно говорится, что представление в дополнительном коде это не единственно возможное. Всё, что требует стандарт, это что знаковые неотрицательные представляются так же, как равные им беззнаковые — это допускает и прямой, и обратный, и дополнительный код. Но опять-таки, есть стандарт, а есть реальный мир. Насколько он реальный — видно по тому, что всякие Java уже настаивают на дополнительном коде, а ведь Java планировалась по принципу "мы можем работать на любой электронике, даже если это ручка чашки кофе"
Я до сих в полном недоумении, почему в каком-нибудь stdint.h не ввели дефайны со значениями "платформа имеет отрицательные в дополнительном коде", чтобы можно было по его отсутствию генерировать #error "я не знаю, как тут быть, дорабатывайте этот код". Сюда же полезен проверяемый дефайн для реального наличия {,u}intN_t. Я не знаю ни одной современной платформы, где не дополнительный код. Ну вот не встречал, считаем, последние лет 25, и всё тут. Почему C упирается — я в недоумении.