Как стать автором
Обновить

Комментарии 21

Я создал для Rust крейт num-ord, позволяющий корректно сравнивать два любых встроенных числовых типа.

Вот так вот люди стараются, наводят строгости, чтобы помочь программистам устранить путаницу в типах и проистекающие из этого ошибки разной степени катастрофичности, а потом приходит эдакий мистер Секонд: "Го сравнивать всё со всем, я создал!"

(рекомендация врача: комментарий следует принимать с немножечком несерьёзности)

Статья так то про частный случай интеграции интерфейсов

возможно, точность сравнения сильно преувеличена. Кому нужна точность до 15го знака с плавающей запятой?

в радио измерениях обычно 5 значащих оставляют, остальные шум/мусор. Если этого не хватает, значит базу измерений выбрана неправильно.

Но что если мы хотим строгого неравенства? Теперь наш трюк с floor/ceil добавляет проблемы, связанные с равенством. Решить их можно отдельной проверкой на равенство в области определения целых чисел, а затем проверкой на неравенство в области определения чисел с плавающей запятой

Ага, сразу видно кто не читал Кнута :-)


Можно же воспользоваться тем, что x < f эквивалентно x < ceil(f), а x > f эквивалентно x > floor(f)

Downloads all time: 193

Интересно, но за год не так много людей захотело посравнивать числа таким образом. И зависимостью, по крайней мере на crates.io, тоже никто не стал делать.

Наверно, потому что есть сильно более старый num-cmp у которого загрузок 838 327 и аж 1 зависимость, зато какая — довольно популярная jsonschema.

Только не зависимость, а потребитель.

Ох ты ж… Извиняюсь, напутал термины пока оформлял мысль.
Ой. C++ автоматически преобразовал -1 в unsigned int, из-за чего значение превратилось в максимальное значение типа (которое очевидно больше 1). Но, по крайней мере, современный компилятор по умолчанию ведь предупреждает о таких вещах? [...] Ну, по крайней мере, он не выполняет втихомолку ошибочную компиляцию…
Type promotion полностью определен в стандарте, что не делает его менее популярным способом стрельбы по ногам.

в дополнение еще на уроках информатики в советской школе рассказывали, что вещественные числа нельзя сравнивать напрямую оператором равенства. Как минимум должна использоваться конструкция если (a-b)<epsilon то тогда значения считаются условно равными. Эпсилон задавался уже под конкретную задачу.

По тому в статье рассматривается не строгое равенство, а "меньше либо равно"

Не подскажете, в каких языках есть удобная реализация fixed point? Обычно float не нужен, если не измеряем расстояние между атомами и между звездами в одной задаче, но постоянно держать в голове, сколько бит отвели на дробную часть лениво.

На любом языке, где есть перегрузка соответствующих операторов. А на плюсах наверняка можно получить и около нулевой оверхед.

Fixed point от неявных округлений вас не спасёт. Чтобы не переживать по этому поводу, обычно используются рациональные числа над BigInteger. В расте вроде есть, в других не менее популярных языках наверняка тоже готовые реализации можно найти.

На счёт fixed point не уверен, но в том же C# из коробки есть decimal, с которым удобно с десятичными дробями работать с достаточно высокой для денег точностью.

А Delphi прекрасно справился со сравнением Signed и Unsigned переменных.

writeln((-1) <= Cardinal(1)); //TRUE

И вывел предупреждение
W1022 Comparison always evaluates to True
и
W1023 Comparing signed and unsigned types - widened both operands

предлагаемое решение ужасно. Нет никаких причин для паники. Наиболее эффективное решение здесь — преобразовать оба значения

Конечно, глупо спорить с переводом, тем не менее автор оригинальной статьи слишком категоричен в своих суждениях. Если бы существовало одно единственное лучшее решение — оно бы и было реализовано в большинстве ЯП, вытеснив все остальные. На практике мы видим, что это не так.

Rust умышленно следует парадигме т.н. сильной типизации, при которой неявное конвертирование типов запрещено. В этом есть своя логика — ведь далеко не все операции со значениями разных типов имеют смысл. Например, нельзя сравнивать количество часов и количество километров, или прибавлять одно к другому (а вот делить — можно).

Rust идёт дальше и вводит понятие единиц измерения (measurements), позволяя добавить ограничения даже на значения одного и того же типа. Что уж говорить про разные типы: когда в программе встречается сравнение знакового и беззнакового целого — это с большой вероятностью ошибка программиста. Если же это делается умышленно, то это должно быть отражено в коде через явное приведение типов.

Rust идёт дальше и вводит понятие единиц измерения (measurements)

А где он это вводит? Гугл по запросу Rust measurements выдаёт, только один крейт. Или вы про возможность обернуть число в new type?

Rust идёт дальше и вводит понятие единиц измерения (measurements)

Мне кажется, вы либо имеете в виду newtype, которые всё-таки являются прозрачной обёрткой, а не "ограничениями для одного и того же типа", либо имеете в виду F#, у которого такая фича и правда есть (и даже делить километры на часы можно)

> "Компилятор должен сам делать всё правильно, а не заставлять людей выполнять вручную преобразования, которые могут быть и ошибочными, или, хуже того, втихомолку генерировать неверный код."

Например, компилятор Delphi делает это настолько педантично, что иногда приходится сильно поприседать, чтобы исключить генерацию в коде этих специальных преобразований, когда заранее известно, что коллизий при несовпадении типов не будет. Приходится аккуратно и точно использовать типы данных, чтобы код не содержал лишнего.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории