платформонезависимая (де-/)сериализация вещественных чисел
От: _hum_ Беларусь  
Дата: 05.01.17 15:53
Оценка:
Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?
Тут как минимум имеются следующие проблемы:
1) как бороться с разной "endianess";
2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).

Попадающийся при гуглении вариант writing-endian-independent-code-in-c смущает кодом
float FloatSwap( float f )
{
  union
  {
    float f;
    unsigned char b[4];
  } dat1, dat2;

  dat1.f = f;
  dat2.b[0] = dat1.b[3];
  dat2.b[1] = dat1.b[2];
  dat2.b[2] = dat1.b[1];
  dat2.b[3] = dat1.b[0];
  return dat2.f;
}

и тем, что никак не решает проблемы 2).

Спасибо.
Re: платформонезависимая (де-/)сериализация вещественных чисел
От: lpd Черногория  
Дата: 05.01.17 16:27
Оценка: -1
Здравствуйте, _hum_, Вы писали:

__>Тут как минимум имеются следующие проблемы:

__>1) как бороться с разной "endianess";
__>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).

Как я понимаю, float определяется не платформой, а стандартом IEEE(single precisio, double, quad), т.е. переносим.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re: платформонезависимая (де-/)сериализация вещественных чисел
От: uzhas Ниоткуда  
Дата: 05.01.17 16:46
Оценка:
Здравствуйте, _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]: платформонезависимая (де-/)сериализация вещественных чисел
От: uzhas Ниоткуда  
Дата: 05.01.17 16:52
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Как я понимаю, float определяется не платформой, а стандартом IEEE(single precisio, double, quad), т.е. переносим.


это не гарантируется, несмотря на упоминание IEEE 754 (или IEEE 60559) в сишном стандарте
можно почитать тут: http://stackoverflow.com/questions/34294938/does-the-c-standard-specify-anything-on-the-representation-of-floating-point-n
Re: платформонезависимая (де-/)сериализация вещественных чисел
От: PM  
Дата: 05.01.17 17:14
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?

__>Тут как минимум имеются следующие проблемы:
__>1) как бороться с разной "endianess";
__>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).

Получить значения мантиссы и экспоненты, сериализовать с требуемой endianess. Типа такого: http://stackoverflow.com/a/14955046/1355844
Re[2]: платформонезависимая (де-/)сериализация вещественных чисел
От: _hum_ Беларусь  
Дата: 05.01.17 17:55
Оценка:
Здравствуйте, 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]: платформонезависимая (де-/)сериализация вещественных чисел
От: _hum_ Беларусь  
Дата: 05.01.17 18:04
Оценка:
Здравствуйте, PM, Вы писали:

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


__>>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?

__>>Тут как минимум имеются следующие проблемы:
__>>1) как бороться с разной "endianess";
__>>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).

PM>Получить значения мантиссы и экспоненты, сериализовать с требуемой endianess. Типа такого: http://stackoverflow.com/a/14955046/1355844


а почему в приведенной ссылке такой сложный код? неужели и мне такой придется писать (со всякими "магическими числами")?
Re[3]: платформонезависимая (де-/)сериализация вещественных чисел
От: PM  
Дата: 05.01.17 22:55
Оценка:
Здравствуйте, _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: платформонезависимая (де-/)сериализация вещественных чисел
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 07.01.17 21:19
Оценка:
Здравствуйте, _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]: платформонезависимая (де-/)сериализация вещественных чисел
От: _hum_ Беларусь  
Дата: 08.01.17 09:47
Оценка:
Здравствуйте, netch80, Вы писали:

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


__>>Есть две программы на разных платформах, сообщающихся друг с другом посредством бинарного файла (одна пишет, другая потом читает). Как на данном этапе развития языка правильнее всего (в рамках стандартного c++ без привлечения библиотек) решается проблема независимой от платформы работы через файл с вещественными данными?

__>>Тут как минимум имеются следующие проблемы:
__>>1) как бороться с разной "endianess";
__>>2) как сериализовать float (ведь могут быть разные стандарты представления вещественных чисел на разных платформах).

N>Сейчас уже крайне сложно найти платформу, где не IEEE754. Поэтому проблема сокращается только до endianness, а её уже можно доработать просто инверсией порядка байт.


если так, можете ответить на вопрос: why-is-ieee-754-floating-point-not-exchangable-between-platforms?
[и привести, как там просят, хотя бы набросок кода]

__>>Попадающийся при гуглении вариант writing-endian-independent-code-in-c смущает кодом


N>Ну туповато написано, но по идее будет хорошо оптимизироваться.


а как корректно делать инверсию для float (без union)?

__>>и тем, что никак не решает проблемы 2).


N>Потому что этой проблемы в реальном мире нет.


см. выше про трудности непереносимости даже в рамках IEEE754.



п.с. я тут задумался — ведь и обычные знаковые целые в бинарных файлах тоже непереносимы, потому как представление отрицательных чисел могут быть в разных форматах — как с битом знака, так и в дополнительном коде. ведь так?
Re[3]: платформонезависимая (де-/)сериализация вещественных чисел
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 08.01.17 21:07
Оценка:
Здравствуйте, _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 упирается — я в недоумении.
The God is real, unless declared integer.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.