Используя 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-битной переменной с плавающей запятой?
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 ++.)
Других решений пока нет …