使用C或C++,我想在循环中递增所有可表示的32位浮点数的范围,类似于可以递增由32位整数表示的所有不同值的方式.
类似于:for(float f = FLOAT_MIN; f <MAX; f = Next_Float(f)){...}
我认为我可以使用标准数学库中的"nexttoward"或"nextafter"函数来完成该任务.见http://www.cplusplus.com/reference/cmath/nextafter/
现在,当我测试带有双打或长双打的"nexttoward"或"nextafter"函数并在Ubuntu 13.04上使用g ++ 4.7进行编译时,我没有遇到任何问题.查看测试代码:
#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;
}
Run Code Online (Sandbox Code Playgroud)
该程序的浮点输出值按预期稳步增长:
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
Ubuntu的@ Ubuntu的:〜$
但是当我尝试使用浮点数而不是双精度数时,"nexttoward"和"nextafter"函数使我失败 - 函数似乎返回比32位浮点数更高精度的值,并且当我将返回值赋给我的32位浮点数时,浮动保持其原始值而不是上升到下一个更高的值.请参阅示例代码和输出:
#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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,"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)(这些float和long double版本是由C99添加的,并非所有实现都支持.)
如果对类型使用了错误的函数,编译器就不会抱怨; 它会悄悄地将参数转换为预期的类型,并根据您对它的处理方式转换结果.
这是针对C.如果使用#include <cmath>,C++会为类型和类型添加数学函数的重载版本(不带f或l后缀).因此,如果您将代码编译为C++,那么这些函数应该按照您的预期运行.(和之间可能存在差异;在任何情况下,您都应该将后者用于C++.)floatlong double<math.h><cmath>
您的问题被标记为C和C++,这在这方面有显着差异.
(C99还添加了一个<tgmath.h>标头,提供特定于类型的宏,其行为类似于C++的重载函数.)