Все ли операции с фиксированной точкой C ++ детерминированы?

Я пишу небольшой движок RTS на C ++ и хочу использовать синхронизацию с блокировкой.

Поскольку детерминизм с плавающей запятой - это то, чего я даже не могу надеяться достичь, я должен использовать математику с фиксированной запятой.

Насколько детерминированно (в разных компиляторах и процессорах) определены типичные операции с целыми числами без знака?

Меня особенно интересует деление, так как оно повлечет за собой округление.


person lines    schedule 05.05.2015    source источник
comment
100% детерминированный, или, по крайней мере, они должны быть, если нет, вероятно, ЦП может быть сломан   -  person Raxvan    schedule 05.05.2015
comment
@ Раксван прав. Это то, что банки используют для денег. Обычно они масштабируются на 1000, так что у них есть десятые доли цента для округления в большую и меньшую сторону. Помните, что операции будут усекаться в конце int.   -  person J. A. Streich    schedule 05.05.2015
comment
Разве существующие rts-игры не используют для этой цели математику с плавающей запятой?   -  person Karl    schedule 05.05.2015
comment
На самом деле нет никаких причин использовать числа с фиксированной запятой, вы просто тратите свое драгоценное время на это. Если вам нужно сохранить действительное число с высокой точностью, просто используйте double, он наверняка сможет сохранить любое значение, которое вы ему укажете.   -  person zoran404    schedule 05.05.2015
comment
@ zoran404 конечно, двойник мог бы сохранить его, но тогда, если вы сделаете с ним математику, компилятор не обязательно обеспечит 100% переносимые результаты. Например, он может использовать 80-битную расширенную точность x87 и, таким образом, давать разные результаты. Или он может выполнять незаконную повторную ассоциацию операций, a + (b + c) == (a + b) + c не обязательно верно, но некоторые компиляторы делают вид, что могут это делать (ICC по умолчанию, GCC, если вы используете небезопасную математику, которая, очевидно, небезопасна)   -  person harold    schedule 05.05.2015
comment
Этот вопрос не имеет смысла, если используется плавающая точка IEEE, результаты также детерминированы. Ошибка всегда одна и та же. Что именно вас беспокоит? Эта плавающая точка недостаточно точна? Также я не понимаю, какое отношение имеет lockstep к плавающей запятой и фиксированной запятой ...   -  person RedX    schedule 05.05.2015
comment
На 100% детерминированно, все время, все они. Это в основном верно и для чисел с плавающей запятой, если вы примете некоторые меры предосторожности.   -  person n. 1.8e9-where's-my-share m.    schedule 05.05.2015
comment
@RedX - см. randomascii.wordpress.com/2013/07/16 / детерминизм с плавающей запятой.   -  person Josh Kelley    schedule 05.05.2015
comment
Банки @ J.A.Streich обычно используют стандартизированное оборудование.   -  person lines    schedule 05.05.2015
comment
@ Карл, насколько я знаю, нет.   -  person lines    schedule 05.05.2015
comment
при использовании с плавающей запятой IEEE результаты также детерминированы - не в реальном мире, особенно если задействовано несколько платформ. Различные компиляторы будут по-разному оптимизировать поток управления и выполнять различные сокращения силы, и как только порядок операций изменится хотя бы немного, все ставки отключены. Также я не знаю, есть ли гарантии относительно сложных операций, таких как трансцендентальные, на разных платформах.   -  person StilesCrisis    schedule 05.05.2015
comment
Не говоря уже о том, что если вы работаете над игрой, будут проявляться полезные действия, такие как DirectX, незаметно меняющий на вас режимы округления ЦП.   -  person StilesCrisis    schedule 05.05.2015
comment
@JoshKelley Спасибо за эту статью, я немного узнал, и это было очень интересно.   -  person RedX    schedule 05.05.2015
comment
Я думал, что для многих функций стандарты обычно не требуют, чтобы младший бит был правильным? По общему признанию, я мало изучаю подобные вещи.   -  person    schedule 05.05.2015
comment
Да, но это не гарантируется для нескольких операций.   -  person lines    schedule 06.05.2015
comment
Вычисления с плавающей запятой на разных сборках игры, на разных машинах, разных компиляторах и настройках, а также на разных архитектурах потенциально будут «правильными», но не «бит-идентичными». Рекомендуемые настройки для VS - /fp:fast, что может привести к различиям в оптимизации. Использование /arch:SSE2 для x86 (что также рекомендуется сегодня и используется по умолчанию для VS 2012+) сделает ваш 32-битный код намного ближе к генерации собственного кода x64 (который никогда не использует x87). Всегда лучше использовать эпсилон-сравнение для чисел с плавающей запятой.   -  person Chuck Walbourn    schedule 27.05.2015
comment
Но, к сожалению, он должен быть бит-идентичным (раздражает хаос). Я знаю об эпсилон-сравнении и т. Д., Но это полезно только в том случае, если вам не нужны синхронизированные данные.   -  person lines    schedule 03.06.2015


Ответы (1)


Размер основных целочисленных типов варьируется на разных платформах. Вы можете избежать этой проблемы, используя uint32_t и подобные типы.

Знаковое целочисленное переполнение является неопределенным поведением, хотя переполнение хорошо определено для целочисленных типов без знака (вы выполняете арифметические операции по модулю 2^N). Тем не менее, вы должны остерегаться этого, потому что модульная арифметика обычно не то, что вы пытались сделать.

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

Но вы можете использовать numeric_limits для проверки. Если верить этой документации, стандарт действительно гарантирует округление до нуля. .

person Community    schedule 05.05.2015
comment
в C ++ 03 было открыто округление деления. В C ++ 11 он теперь стандартизирован, и я думаю настраиваемый, но я не помню наверняка. - person Mooing Duck; 15.05.2015