Не удалось получить следующее 32-битное значение с плавающей запятой, используя функцию nextafter / nexttoward в C / C ++ в & lt; math.h & gt;

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

Что-то вроде:
for (float f = FLOAT_MIN; f < МАКСИМУМ; f = Next_Float (f))
{…}

Я думаю, что я мог бы использовать функции «nexttoward» или «nextafter» в стандартной математической библиотеке для выполнения этой задачи. Увидеть http://www.cplusplus.com/reference/cmath/nextafter/

Теперь, когда я тестирую функции «nexttoward» или «nextafter» с double или long double и компилирую с g ++ 4.7 в Ubuntu 13.04, я не сталкиваюсь с какими-либо проблемами. Смотрите тестовый код:

#include <math.h>
#include <iostream>
#include <iomanip>

int main ()
{
double f = 0.1;
for(int i = 0; i < 5; ++i)
{
//Marginally increment f in the upper direction.
f = nexttoward(f,999.999);
std::cout << std::setprecision(70) << f << std::endl;
std::cout << nexttoward(f,999.999) << std::endl;
}
return 0;
}

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

ubuntu @ ubuntu: ~ $ g ++ -o temp ~ / temp.cpp

Ubuntu @ Ubuntu: ~ $ ./temp

0,10000000000000001942890293094023945741355419158935546875
0,100000000000000033306690738754696212708950042724609375
0,100000000000000033306690738754696212708950042724609375
0,10000000000000004718447854656915296800434589385986328125
0,10000000000000004718447854656915296800434589385986328125
0,1000000000000000610622663543836097232997417449951171875
0,1000000000000000610622663543836097232997417449951171875
0,10000000000000007494005416219806647859513759613037109375
0,10000000000000007494005416219806647859513759613037109375
0,100000000000000088817841970012523233890533447265625

убунту @ убунт: ~ $

Но когда я пытаюсь использовать числа с плавающей точкой вместо двойных, функции «nexttoward» и «nextafter» меня не устраивают — функции, как представляется, возвращают значения с большей точностью, чем 32-разрядные числа с плавающей запятой, и когда я присваиваю возвращаемые значения моему 32-разрядному числу с плавающей запятой, float сохраняет свое первоначальное значение, а не поднимается до следующего более высокого значения. Смотрите пример кода и вывод:

#include <math.h>
#include <iostream>
#include <iomanip>

int main ()
{
float f = 0.1f;
for(int i = 0; i < 10; ++i)
{
//Marginally increment f in the upper direction.
f = nexttoward(f,999.999f);
std::cout << std::setprecision(70) << f << std::endl;
std::cout << nexttoward(f,999.999f) << std::endl;
}
return 0;
}

Обратите внимание, что второе выходное значение из «nexttoward» имеет большую точность и что f поддерживает то же значение:

ubuntu @ ubuntu: ~ $ g ++ -o temp ~ / temp.cpp

Ubuntu @ Ubuntu: ~ $ ./temp

+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625
+0,100000001490116119384765625
0,10000000149011613326255343281445675529539585113525390625

Я хочу увеличить все 32-разрядные значения с плавающей запятой, а не все 64-разрядные значения двойной точности — время увеличения всех значений двойной точности будет слишком длинным.

Как исправить эту проблему и добиться эффективного, удобного и переносимого способа итерации по диапазону 32-битной переменной с плавающей запятой?

3

Решение

nextafter а также nexttoward функции принимают аргументы типа double и вернуть результаты типа double,

За floatиспользуйте соответствующие nextafterf а также nexttowardf функции.

Это общее правило почти для всех математических функций, объявленных в <math.h>, Например, есть три функции квадратного корня:

  • sqrtf (за float)
  • sqrt (за double)
  • sqrtl (за long double)

(The float а также long double версии были добавлены C99 и могут поддерживаться не всеми реализациями.)

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

Это для C. Если вы используете #include <cmath>, C ++ добавляет перегруженные версии математических функций (без f или же l суффикс) для типов float а также long double, Так что если вы компилируете свой код как C ++, то эти функции должен ведите себя так, как вы ожидаете. (Может быть разница между <math.h> а также <cmath>; в любом случае вы должны использовать последний для C ++.)

Ваш вопрос помечен как C, так и C ++, которые имеют существенные различия в этой области.

(C99 также добавляет <tgmath.h> заголовок, который предоставляет специфичные для типа макросы, которые ведут себя подобно перегруженным функциям C ++.)

7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]