2017-02-23 2 views
3

Рассмотримточно создать значение с плавающей запятой в диапазоне [а, Ь)

auto x = a + (b-a)*v; 

, который предназначен для создания значения в диапазоне [a,b) фактором v в [0,1.0). С чисто математической точки зрения, x>=a и x<b. Но как мы можем доказать или убедиться, что это верно для с плавающей запятой? a, b, v неотрицательные и конечные значения с плавающей точкой одного и того же типа (double или float) и b>a (первоначально сказал b>=a что, очевидно, несовместимо с моими требованиями к x) и v<=netxtafter(1.0,0) (то есть, это просто ниже 1.0).

Это кажется очевидным, что b-a >0, и поэтому (b-a)*v >=0, так что нам не нужно, чтобы проверить:

if (x<a) return a; 

Но это также излишним?

if (x>=b) return std::nextafter(b,a); 

Может ли компилятор (оптимизация) переписать выражения, чтобы повлиять на эти вопросы? Введите тип представления с плавающей запятой? (Я в основном заинтересованы в наиболее распространенных (iec559/IEEE 754).

+1

Я не понимаю беспокойства. Если ваше равенство имеет место для любого (положительного) Реального, оно также выполняется для любых чисел с плавающей запятой, так как Q (рациональные) является подмножеством R (реалов) и чисел с плавающей запятой являются подмножество Q ... –

+0

Я думаю, худшее, что может произойти, это когда ваши цифры, например, либо v, b или a (или все из них) чрезвычайно малы или близки к границам, и в этом случае усечение может быть проблемой .. однако усечение всегда в сторону более низкого значения, и все ваши цифры положительны ... –

+0

@CedricDruck , Положите это так: если нет никакого беспокойства, это должно быть легко доказать. Позаботьтесь, чтобы написать ответ? –

ответ

5

Это кажется очевидным, что ба> 0, и, следовательно, (ба) * v> = 0, так что нам не нужно проверить: if (x<a) return a;

свойство b - a > 0 является правильным в IEEE 754, но я бы не сказал, что это очевидно во время операций с плавающей точкой стандартизации, Kahan fought for this property resulting from “gradual underflow” to be true Другие предложения не имеют субнормальные числа и сделали.. не могли бы быть правдой. Вы могли бы иметь и b - a == 0 в этих других предложениях, например, беря a наименьшее положительное число и b его преемник.

Даже без постепенного опустошения, в системе, которая неправильно реализует IEEE 754 промывки subnormals к нулю, b > a означает b - a >= 0, так что нет необходимости беспокоиться о x быть ниже a.

Но неужели это также избыточно? if (x>=b) return std::nextafter(b,a);

Этот тест не является избыточным даже в IEEE 754. Для примера принять b, чтобы быть преемником a. Для всех значений v выше 0.5, в режиме по умолчанию от ближайшего к ближайшему, результатом a + (b-a)*v является b, которого вы пытались избежать.


Мои примеры построены с необычными значениями для a и b, потому что спасает меня от написания программы, чтобы найти контрпримеры с помощью грубой силы, но не думайте, что другие, более вероятно, пары значений a и b не проявляют этой проблемы.Если бы я искал дополнительные встречные примеры, я бы, в частности, искал пары значений, для которых округляется вычитание с плавающей запятой b - a.


EDIT: Да ладно вот еще контрпример:

Возьмите a быть преемником преемника -1.0 (то есть, в двойной точности, используя шестнадцатеричное C99, в -0x1.ffffffffffffep-1) и b будет 3.0. Затем b - a округляет до 4,0 и принимает v как предшественника 1.0, a + (b - a) * vrounds up до 3.0.

с плавающей запятой вычитания b - a округления не является необходимым для некоторых значений a и b решений контр-пример, как показано here: принимать a в качестве преемника 1.0 и b, как 2.0 также работает.

Смежные вопросы