Итерация по всем значениям float
может быть выполнена с простым пониманием представления с плавающей точкой:
- Расстояние между последовательными субнормальными значениями - это минимальное нормальное значение, умноженное на «эпсилон».Просто переберите все субнормалы, используя это расстояние в качестве приращения.
- Расстояние между нормальными значениями наименьшего показателя равно.Пройдите через них с одинаковым шагом.
- Для каждого показателя расстояние увеличивается в соответствии с основанием с плавающей запятой.Просто умножьте приращение на основание и пройдитесь по всем значениям для следующего показателя степени.
- Повторяйте, пока не будет достигнута бесконечность.
Обратите внимание, что внутренний цикл в приведенном ниже коде просто:
for (; x < Limit; x += Increment)
Test(x);
Преимущество заключается в том, что используется только обычная арифметика с плавающей точкой.Внутренний цикл содержит только одно дополнение и одно сравнение (плюс любые тесты, которые вы хотите выполнить с каждым числом).Никакие библиотечные функции не вызываются в цикле, никакие представления не анализируются и не копируются в общие регистры, или иным образом не обрабатываются.Ничто не мешает производительности.
Этот код просматривает только неотрицательные числа.Отрицательные числа могут быть проверены отдельно таким же образом или могут разделить этот код, вставив вызов Test(-x)
.
#include <limits>
static void Test(float x)
{
// Insert unit test for value x here.
}
int main(void)
{
typedef float T;
static const int Radix = std::numeric_limits<T>::radix;
static const T Infinity = std::numeric_limits<T>::infinity();
/* Increment is the current distance between floating-point numbers. We
start it at distance between subnormal numbers.
*/
T Increment =
std::numeric_limits<T>::min() * std::numeric_limits<T>::epsilon();
/* Limit is the next boundary where the distance between floating-point
numbers changes. We will increment up to that limit and then adjust
the limit and increment. We start it at the top of the first set of
normals, which allows the first loop to increment first through the
subnormals and then through the normals with the lowest exponent.
(These two sets have the same step size between adjacent values.)
*/
T Limit = std::numeric_limits<T>::min() * Radix;
/* Start with zero and continue until we reach infinity.
We execute an inner loop that iterates through all the significands of
one floating-point exponent. Each time it completes, we step up the
limit and increment.
*/
for (T x = 0; x < Infinity; Limit *= Radix, Increment *= Radix)
// Increment x through all the significands with the current exponent.
for (; x < Limit; x += Increment)
// Test with the current value of x.
Test(x);
// Also test infinity.
Test(Infinity);
}
(Этот код предполагает, что тип с плавающей запятой имеет субнормалы, и что они не являютсясбрасывается в ноль. Код также может быть легко скорректирован для поддержки этих альтернатив.)