Один пример из многих: шаблонное метапрограммирование. Никто в комитете по стандартам не намеревался там быть полным по Тьюрингу подъязыком, который выполняется во время компиляции.
Шаблонное метапрограммирование является едва скрытой функцией. Это находится даже в библиотеке повышения. См. MPL. Но если "почти скрытый" достаточно хорошо, то смотрите на библиотеки повышения . Это содержит много конфет, которые не являются легки доступный без поддержки сильной библиотеки.
Один пример библиотека boost.lambda , которая интересна, так как C++ не имеет функций лямбды в текущем стандарте.
Другой пример Loki, который "делает широкое применение шаблонного метапрограммирования C++ и реализует несколько наиболее часто используемых инструментов: список типов, функтор, одиночный элемент, интеллектуальный указатель, возражает фабрике, посетителю и мультиметодам". [ Википедия ]
Один из способов ответить на ваш вопрос - найти размер ULP или U нит в L ast P lace, вашего числа с плавающей запятой. Немного упрощая, это расстояние между заданным числом с плавающей запятой и следующим большим числом. Опять же, немного упрощая, учитывая представимое значение x с плавающей запятой, любая десятичная строка, значение которой находится между (x - 1/2 ulp) и (x + 1/2 ulp), будет округлено до x при преобразовании в плавающее -point.
Хитрость заключается в том, что (x +/- 1/2 ulp) не является представимым числом с плавающей запятой, поэтому для фактического вычисления его значения требуется, чтобы вы использовали более широкий тип с плавающей запятой (если он доступен ) или большой десятичной дроби произвольной ширины или аналогичный тип для выполнения вычислений.
Как определить размер язвы? Один относительно простой способ примерно соответствует тому, что вы предложили, здесь написан псевдокод C-ish, потому что я не знаю C #:
float absX = absoluteValue(x);
uint32_t bitPattern = getRepresentationOfFloat(absx);
bitPattern++;
float nextFloatNumber = getFloatFromRepresentation(bitPattern);
float ulpOfX = (nextFloatNumber - absX);
Это работает, потому что добавление единицы к битовому шаблону x в точности соответствует добавлению одного ulp к значению x . При вычитании не происходит округления с плавающей запятой, потому что задействованные значения настолько близки (в частности, есть теорема арифметики с плавающей запятой ieee-754, что если два числа x и y удовлетворяют условию y / 2 <= x <= 2y, тогда x - y
вычисляется точно). Единственное предостережение:
inf
, что явно неверно). Похоже, вы вряд ли попадете ни в одну из этих ситуаций, поэтому для ваших целей это должно работать.
Теперь, когда вы знаете, что такое ulp of x есть, вы можете найти интервал значений, который округляется до x. Вы можете вычислить ulp (x) / 2 точно с плавающей запятой, потому что деление с плавающей запятой на 2 является точным (опять же, без потери значимости). Затем вам нужно только вычислить значение x +/- ulp (x) / 2 подходящего большего типа с плавающей запятой ( double
будет работать, если вас интересует float
) или тип Big Decimal, и у вас есть свой интервал.
Я сделал несколько упрощающих предположений в этом объяснении. Если вам нужно, чтобы это действительно было изложено точно, оставьте комментарий, и я расширю разделы, которые немного нечеткие, когда у меня будет возможность. десятичное число, которое представлено с таким же битовым шаблоном
неверен. Вы просто случайно смотрели неверные значения (0,999999 ... вместо 0,099999 ... - простая опечатка).
Python 3.1 только что реализовал что-то вроде этого: см. журнал изменений (прокрутите немного вниз) , отчет об ошибке .