Std:: numeric_limits:: is_exact... что такое полезное определение?

Как я его интерпретирую, определение MSDN numeric_limits::is_exact почти всегда ложно:

[все] вычисления, выполненные на этом типе, не имеют ошибок округления.

И определение IBM почти всегда верно: (Или круговое определение, в зависимости от того, как вы его читаете)

тип, который имеет точные представления для всех его значений

Я уверен, что я мог хранить 2 как в double, так и в long, и они оба были бы представлены точно.

Затем я мог бы разделить их как на 10, так и на результат математического результата.

Для любого числового типа данных T, какой правильный способ определить std::numeric_limits<T>::is_exact?

Изменить: Я отправил то, что я думаю, является точным ответом на этот вопрос из деталей, представленных во многих ответах. Этот ответ не является претендентом на награду.

Ответ 1

Определение в стандарте (см. ответ NPE) не очень точное, не так ли? Вместо этого она круглая и неопределенная.

Учитывая, что стандарт с плавающей запятой IEC имеет понятие "неточные" числа (и неточное исключение, когда вычисление дает неточное число), я подозреваю, что это источник имени is_exact. Обратите внимание, что для стандартных типов is_exact false только для float, double и long double.

Цель состоит в том, чтобы указать, точно ли тип представляет все числа базового математического типа. Для интегральных типов основным математическим типом является некоторое конечное подмножество целых чисел. Поскольку каждый тип интеграла точно представляет каждый из элементов подмножества целых чисел, предназначенных для этого типа, is_exact истинно для всех интегральных типов. Для типов с плавающей точкой основной математический тип представляет собой некоторое подмножество конечного диапазона действительных чисел. (Примером подмножества конечного диапазона является "все действительные числа от 0 до 1".) Невозможно точно представлять даже конечное подмножество конечных чисел; почти все неоспоримы. Формат IEC/IEEE еще более усугубляет ситуацию. В этом формате компьютеры не могут даже точно представлять конечное подмножество рациональных чисел (не говоря уже о конечном подмножестве конечных чисел вычислимых чисел).

Я подозреваю, что начало термина is_exact является давней концепцией "неточных" чисел в различных моделях представления с плавающей запятой. Возможно, лучшим именем было бы is_complete.

Добавление
Числовые типы, определенные языком, не являются "все-все" и "конец" всех представлений "чисел". Представление с фиксированной точкой - это, по сути, целые числа, поэтому они тоже были бы точными (в представлении не было отверстий). Представление рациональности как пары стандартных интегральных типов (например, int/int) было бы неточным, но класс, который представлял бы рациональность как пара Bignum, по крайней мере теоретически был бы "точным".

Как насчет реалов? Невозможно представить реалты именно потому, что почти все реалы не являются вычислимыми. Самое лучшее, что мы могли бы сделать с компьютерами, это вычислимые числа. Это потребует представления числа как некоторого алгоритма. Хотя это может быть полезно теоретически, с практической точки зрения, это не так полезно вообще.

Второе добавление
Место для начала - со стандартом. Оба С++ 03 и С++ 11 определяют is_exact как

Истинно, если тип использует точное представление.

Это и неопределенное, и круговое. Это бессмысленно. Не совсем бессмысленно то, что целые типы (char, short, int, long и т.д.) Являются "точными" по fiat:

Все целые типы являются точными,...

Как насчет других арифметических типов? Первое, что нужно отметить, это то, что единственными другими арифметическими типами являются типы с плавающей точкой float, double и long double (3.9.1/8):

Существует три типа с плавающей запятой: float, double и long double.... Представление значений типов с плавающей запятой определяется реализацией. Интегральные и плавающие типы совместно называются арифметическими типами.

Значение типов с плавающей запятой в С++ заметно мутное. Сравните с Fortran:

Реальная дата - это приближение процессора к значению действительного числа.

Сравнение с ISO/IEC 10967-1, независимая от языка арифметика (которая ссылается на стандарты С++ в сносках, но никогда не является нормативной ссылкой):

Тип с плавающей запятой F должен быть конечным подмножеством в ℝ.

C++ с другой стороны является спорным в отношении того, что должны представлять типы с плавающей запятой. Насколько я могу судить, реализация может уйти, сделав float синонимом для int, double синонимом long и long double синонимом long long.

Еще раз из стандартов is_exact:

... но не все точные типы являются целыми. Например, рациональные и фиксированные экспоненциальные представления являются точными, но не целыми.

Это явно не распространяется на разработанные пользователем расширения по той простой причине, что пользователям не разрешено определять std::whatever<MyType>. Сделайте это, и вы вызываете поведение undefined. Это заключительное предложение может относиться только к реализациям, которые

  • Определить float, double и long double каким-то особым образом или
  • Предоставьте некоторый нестандартный рациональный или фиксированный тип точки как арифметический тип и решите предоставить std::numeric_limits<non_standard_type> для этих нестандартных расширений.

Ответ 2

Я полагаю, что is_exact истинно, если все литералы такого типа имеют точное значение. Таким образом is_exact является ложным для плавающих типов, потому что значение буква 0,1 не равно 0,1.

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

Ответ 3

Проблема точных не ограничена C, поэтому давайте посмотрим дальше.

Германский вопрос о редактировании стандартов отдельно, неточный должен применяться к математическим операциям, которые требуют округления для представления результата с одним и тем же типом. Например, схема имеет такое определение точности/неточности посредством точных операций и точных констант литерала, см. R5RS §6. стандартные процедуры из http://www.schemers.org/Documents/Standards/R5RS/HTML

В случае double x=0.1 мы считаем, что 0,1 - это хорошо определенный двойной литерал или, как на схеме, что буква - это неточная константа, образованная неточной операцией времени компиляции (округление до ближайшего двойного результата операции 1/10, который хорошо определен в Q). Поэтому мы всегда работаем.

Пусть сосредоточиться на +, другие могут быть математически определены средним значением + и групповым свойством.

Возможное определение неточности могло бы быть:

If there exists any pair of values (a,b) of a type such that a+b-a-b != 0,
then this type is inexact (in the sense that + operation is inexact).

Для каждого представления с плавающей запятой мы знаем (тривиальный случай нанок и inf отдельно), очевидно, существует такая пара, поэтому мы можем сказать, что float (операции) неточны.

Для хорошо определенной беззнаковой арифметической модели + является точной.

Для подписанного int у нас есть проблема UB в случае переполнения, поэтому нет гарантии точности... Если мы не уточним правило, чтобы справиться с этой сломанной арифметической моделью:

If there exists any pair (a,b) such that (a+b) is well defined
and a+b-a-b != 0,
then the + operation is inexact.

Выше четкости может помочь нам распространиться и на другие операции, но это не обязательно. Тогда нам пришлось бы рассматривать случай/как ложный полиморфизм, а не неточность (/определяется как фактор евклидова деления для int).

Конечно, это не официальное правило, справедливость этого ответа ограничена усилиями рационального мышления

Ответ 4

Определение, данное в стандарте С++, кажется довольно однозначным:

static constexpr bool is_exact;

Истинно, если тип использует точное представление. Все целые типы являются точными, но не все точные типы целое число. Например, рациональные и фиксированные-экспоненциальные представления являются точными, но не целыми.

Значение для всех специализаций.

Ответ 5

В С++ тип int используется для представления математического целочисленного типа (т.е. одного из множества {..., -1, 0, 1,...}). Из-за практического ограничения реализации язык определяет минимальный диапазон значений, который должен быть сохранен этим типом, и все допустимые значения в этом диапазоне должны быть представлены без двусмысленности на всех известных архитектурах.

Стандарт также определяет типы, которые используются для хранения чисел с плавающей запятой, каждый со своим диапазоном допустимых значений. То, что вы не найдете, - это список допустимых чисел с плавающей запятой. Опять же, из-за практических ограничений стандарт допускает аппроксимации этих типов. Многие люди пытаются сказать, что только цифры, которые могут быть представлены стандартом с плавающей точкой IEEE, являются точными значениями для этих типов, но это не является частью стандарта. Хотя верно, что реализация языка на двоичных компьютерах имеет стандарт для представления double и float, на языке, который говорит, что он должен быть реализован на двоичном компьютере, нет ничего. Другими словами, float не определен стандартом IEEE, стандарт IEEE является только приемлемой реализацией. Таким образом, если бы существовала реализация, которая могла бы содержать любое значение в диапазоне значений, которые определяют double и float без правил округления или оценки, вы могли бы сказать, что is_exact верен для этой платформы.

Строго говоря, T не может быть вашим единственным аргументом, чтобы определить, является ли тип "is_exact", но мы можем вывести некоторые из других аргументов. Поскольку вы, вероятно, используете двоичный компьютер со стандартным оборудованием и любым общедоступным компилятором С++, когда вы назначаете двойное значение .1 (которое находится в допустимом диапазоне для типов с плавающей точкой), это не тот номер, на котором компьютер использовать в вычислениях с этой переменной. Он использует самое близкое приближение, как определено стандартом IEEE. Разумеется, если вы сравните литерал с самим собой, ваш компилятор должен вернуть true, потому что стандарт IEEE довольно явный. Мы знаем, что компьютеры не имеют бесконечной точности, и поэтому вычисления, которые мы ожидаем иметь значение .1, не обязательно окажутся в том же приближенном представлении, что и в литеральном значении. Введите сравнение страшного эпсилона.

Чтобы ответить на ваш вопрос, я бы сказал, что для любого типа, для которого требуется сравнение epsilon для проверки приблизительного равенства, is_exact должен возвращать false. Если для этого типа достаточно строгого сравнения, оно должно возвращать true.

Ответ 6

std::numeric_limits<T>::is_exact должен быть false тогда и только тогда, когда определение T допускает недопустимые значения.

С++ считает, что любой литерал с плавающей точкой является допустимым значением для его типа. И реализациям разрешено определять, какие значения имеют точное сохраненное представление.

Итак, для каждого действительного числа в разрешенном диапазоне (например, 2.0 или 0.2), С++ всегда promises, что число является допустимым double и никогда promises, что значение может быть сохранено точно.

Это означает, что два предположения, сделанные в вопросе - хотя это верно для вездесущего стандарта IEEE с плавающей запятой - неверны для С++ определение:

Я уверен, что я мог бы хранить 2 в двойном точно.

Затем я мог бы делить [it] на 10, а [double - не] удерживать математический результат точно.