Но даже больше меня тревожит ход мыслей, который привёл к конструкции:
short const signed_left = *reinterpret_cast<short const*>(&left.second);
1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание?
Возможно, я что-то упускаю?
Простой C-style или static_cast недостаточны для подобной конвертации?
2. Код теоретически кроссплатформенный (x86 и ARM), в реальности — только ARM-
В этом может быть загвоздка?
VTT>Этот компаратор используется в качестве предиката алгоритма, а не контейнера, и к нему требование strict weak ordering вроде не предъявляется.
Отлично, но, например, max_element/min_element из std с ним выдают белиберду.
25.4 Sorting and related operations
...
3 For all algorithms that take Compare, there is a version that uses operator< instead. That is, comp(*i,
*j) != false defaults to *i < *j != false. For algorithms other than those described in 25.4.3 to work
correctly, comp has to induce a strict weak ordering on the values.
4 The term strict refers to the requirement of an irreflexive relation (!comp(x, x) for all x), and the term weak
to requirements that are not as strong as those for a total ordering, but stronger than those for a partial
ordering. If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp
and equiv both be transitive relations:
(4.1) — comp(a, b) && comp(b, c) implies comp(a, c)
(4.2) — equiv(a, b) && equiv(b, c) implies equiv(a, c) [Note: Under these conditions, it can be shown
that
(4.2.1) — equiv is an equivalence relation
(4.2.2) — comp induces a well-defined relation on the equivalence classes determined by equiv
(4.2.3) — The induced relation is a strict total ordering. —end note
VTT>Зачем вообще что-то кастовать, а не хранить сразу signed short — совершенно непонятно.
Хранить сразу нельзя.
Извне приходит unsigned.
Зачем делать через указатель я не понимаю.
DA>1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание? DA> Возможно, я что-то упускаю? DA> Простой C-style или static_cast недостаточны для подобной конвертации?
Реальной необходимости нет. Ход мыслей... Например, до этого писался код, где reinterpret_cast использовался для структур... Или просто померещилось что-то...
Здравствуйте, dr. Acula, Вы писали:
DA> Простой C-style или static_cast недостаточны для подобной конвертации?
static_cast проверяет возможность приведения и может не скомпилироваться. c-style будет приведён к одному из возможных приведений в c++ — const_cast, static_cast, reinterpret_cast. чел сразу явно написал к чему он хочет привести, это и есть с++ стиль.
DA>2. Код теоретически кроссплатформенный (x86 и ARM), в реальности — только ARM- DA> В этом может быть загвоздка?
код вообще может выдать шлак, если там в первых short const байтах объекта шлак.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, dr. Acula, Вы писали:
DA>Коллега с 20+ опыта породил следующий код.
Ордеринг поправь. Не делается сравнение TEMP_UNKNOWN c валидными значениями, вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно.
Если охота, чтобы невалидные элементы были наименьшими:
Здравствуйте, dr. Acula, Вы писали:
DA>1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание? DA> Возможно, я что-то упускаю? DA> Простой C-style или static_cast недостаточны для подобной конвертации?
я может чего не понял, но обе конструкции в 50% случаев дают ошибочный результат же?
более того, такой reinterpret_cast с нормальным int-ом вообще ошибочен
Здравствуйте, dr. Acula, Вы писали:
DA>Да, я в курсе, что подобный функтор использовать в качестве предиката в контейнерах нельзя, т.к. он не обеспечивает strict weak ordering.
это уже существенный аргумент, чтобы переработать код
DA>Но даже больше меня тревожит ход мыслей, который привёл к конструкции: DA>
действительно, странный код. предположу, что формально — это UB и этот код не равносилен коду
short const signed_left = static_cast<short>(left.second);
DA>1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание? DA> Возможно, я что-то упускаю?
зависит от того, как следует интерпретировать числа типа WORD.
в простейшем случае никаких кастов делать вообще не надо
DA>2. Код теоретически кроссплатформенный (x86 и ARM), в реальности — только ARM- DA> В этом может быть загвоздка?
x86 — little endian
ARM — big/little (bi-) endian
эти нюансы надо держать в голове
Здравствуйте, andyp, Вы писали:
A>Здравствуйте, dr. Acula, Вы писали:
DA>>Коллега с 20+ опыта породил следующий код.
A>Не делается сравнение TEMP_UNKNOWN c валидными значениями,
а можно поинтересоваться, почему?
A>вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно.
в каком смысле развалилась? в логическом смысле она в исходном варианте сравнения вроде как выполнена (а нарушена транзитивность по несравнимости)
Здравствуйте, _hum_, Вы писали:
A>>Не делается сравнение TEMP_UNKNOWN c валидными значениями,
__>а можно поинтересоваться, почему?
Да так уж написано было первом посте темы
A>>вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно.
__>в каком смысле развалилась? в логическом смысле она в исходном варианте сравнения вроде как выполнена (а нарушена транзитивность по несравнимости)
В смысле f(invalid, valid) == (!f(valid, invalid))
Здравствуйте, andyp, Вы писали:
A>Здравствуйте, _hum_, Вы писали:
A>>>Не делается сравнение TEMP_UNKNOWN c валидными значениями,
__>>а можно поинтересоваться, почему?
A>Да так уж написано было первом посте темы
что именно?
A>>>вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно.
__>>в каком смысле развалилась? в логическом смысле она в исходном варианте сравнения вроде как выполнена (а нарушена транзитивность по несравнимости)
A>В смысле f(invalid, valid) == (!f(valid, invalid))
A>должно выполняться (см. аксиома 2, https://www.sgi.com/tech/stl/StrictWeakOrdering.html)
там написано
Antisymmetry f(x, y) implies !f(y, x)
что, как я понимаю, означает следование в виде импликации: "когда f(x, y) == true, то !f(y, x) == true" . иными словами, никто не запрещает ситуацию, когда f(x, y) == false и f(y, x) == false.
Здравствуйте, _hum_, Вы писали:
__>Здравствуйте, andyp, Вы писали:
__>что именно?
код предиката в стартовом посте.
__>там написано __>
__>Antisymmetry f(x, y) implies !f(y, x)
__>что, как я понимаю, означает следование в виде импликации: "когда f(x, y) == true, то !f(y, x) == true" . иными словами, никто не запрещает ситуацию, когда f(x, y) == false и f(y, x) == false.
Implies переводится как предполагает. f(x, y) == false и f(y, x) == false для less бывает только когда x равно y. Если ты посмотришь на то, что писал я в педыдущем посте, то там присутствуют заведомо неравные valid (известная температура) и invalid (неизвестная температура). Именно это и нарушалось в коде предиката, который привел ТС:
less(unknown,100) == false, less(100,unknown) == false => 100 == unknown (WTF ???) и поиск минимума-максимума стал невозможен.
A>>Не делается сравнение TEMP_UNKNOWN c валидными значениями,
__>а можно поинтересоваться, почему?
такое требоваие спецификации.
A>>вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно. __>в каком смысле развалилась? в логическом смысле она в исходном варианте сравнения вроде как выполнена (а нарушена транзитивность по несравнимости)
нет, нарушена антисимметричность.
DA>1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание? DA> Возможно, я что-то упускаю? DA> Простой C-style или static_cast недостаточны для подобной конвертации?
Так как вопрос про "ход мыслей", то придётся использовать телепатические способности и прочее "лечение по фотографии". Как следствие — никаких гарантий.
Смотрите: left.second типа unsigned short, а мы хотим его в signed short перевести. Зачем — я не знаю, но думаю, что имеет место передача знаковых значений через беззнаковое. (Я бы предположил наличие в программе передачи сообщений или какую-нибудь коммуникацию и построение точно такого же map'а, как на другом конце) Нельзя просто так перевести unsigned short в signed short потому, что для положительных значений выходящих за пределы представления signed short результат то ли неспецифицирован, то ли implemented defined. Но! Если мы знаем, что представление чисел организовано в дополнительном коде (а это скорее всего так), то мы можем просто интерпретировать кусок памяти, как знаковое число, поэтому reinterpret_cast через указатели. Через указатели, потому что "никто" не помнит, можно ли делать прямой reinterpret_cast<short>(..). (Может и можно — RTFM, но лень — матушка).
DA>2. Код теоретически кроссплатформенный (x86 и ARM), в реальности — только ARM- DA> В этом может быть загвоздка?
Теоретически, этот код не кроссплатформенный, но на практике, почти везде будет работать.
В любом случае это плохой стиль и, минимум, необходим static_assert(sizeof(Values::value_type) == sizeof(short), "wrong implementation");
Здравствуйте, andyp, Вы писали:
A>Здравствуйте, _hum_, Вы писали:
__>>Здравствуйте, andyp, Вы писали:
__>>что именно?
A>код предиката в стартовом посте.
__>>там написано __>>
__>>Antisymmetry f(x, y) implies !f(y, x)
__>>что, как я понимаю, означает следование в виде импликации: "когда f(x, y) == true, то !f(y, x) == true" . иными словами, никто не запрещает ситуацию, когда f(x, y) == false и f(y, x) == false.
A>Implies переводится как предполагает. f(x, y) == false и f(y, x) == false для less бывает только когда x равно y. Если ты посмотришь на то, что писал я в педыдущем посте, то там присутствуют заведомо неравные valid (известная температура) и invalid (неизвестная температура). Именно это и нарушалось в коде предиката, который привел ТС: A>less(unknown,100) == false, less(100,unknown) == false => 100 == unknown (WTF ???) и поиск минимума-максимума стал невозможен.
A>PS Вика приводит более внятный вид аксиомы антисимметрии, но для отношения меньше-равно: A>if a ≤ b and b ≤ a, then a = b A>https://en.wikipedia.org/wiki/Total_order
это не совесм то. это антисимметричность, а надо асимметричность ака Asymmetric_relation
In mathematics an asymmetric relation is a binary relation on a set X where:
For all a and b in X, if a is related to b, then b is not related to a.[1]
помимо вариантов a < b, b < a есть еще вариант "a с b несравнимы", то есть, не выполняется ни "a < b", ни "b < a".
асимметричность говорит, что если элементы сравнимы, то выполняться должен только один вариант сравнения.
A>>>Не делается сравнение TEMP_UNKNOWN c валидными значениями,
__>>а можно поинтересоваться, почему? DA>такое требоваие спецификации.
чьей? вашей, или сишной (что максимальные по значению числа типов нельзя сравнивать)?
A>>>вот аксиома антисимметрии и развалилась. Остальное вроде бы вычурно, но безобидно. __>>в каком смысле развалилась? в логическом смысле она в исходном варианте сравнения вроде как выполнена (а нарушена транзитивность по несравнимости) DA>нет, нарушена антисимметричность.
DA>1. Есть ли реальная необходимость делать касте через указатель и его последующее разыменовывание? DA> Возможно, я что-то упускаю?
DA>2. Код теоретически кроссплатформенный (x86 и ARM), в реальности — только ARM-
И что GCC не ругается на такой код варнингами в стиле “dereferencing type-punned pointer will break strict aliasing”?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Здравствуйте, andyp, Вы писали:
A>Если охота, чтобы невалидные элементы были наименьшими:
bool operator() (optional a, optional b) const {
bool a_null = is_null(a);
bool b_null = is_null(b);
if(a_null != b_null) return a_null; // или b_null чтобы в конецreturn !a_null && value(a) < value(b);
}
Но здесь INVALID и так с краю, он же numeric_limits<short>::max(), можно тупо сравнивать, — какая разница, слева он или справа.
Только это же не поиск, судя по использованию min_element/max_element, добавление транзитивности компаратору ничего не даст.
Рискну предположить что тут не order нужен, а фильтрация INVALID элементов.
struct min_max_temperature {
void operator()(const pair<int, short>& t) {
if(t.second == INVALID)
return;
if(min == INVALID || min > t.second))
min = t.second;
if(max == INVALID || max < t.second))
max = t.second;
}
short min = INVALID;
short max = INVALID;
};
auto min_max = std::foreach(temperatures.begin(), temperatures.end(), min_max_temperature());