3

使用 C 或 C++,我想在循环中递增所有可表示的 32 位浮点数的范围,类似于您可能递增由 32 位整数表示的所有不同值的方式。

类似于: for(float f = FLOAT_MIN; f < MAX; f = Next_Float(f)) {...}

我认为我可以使用标准数学库中的“nexttoward”或“nextafter”函数来完成该任务。见http://www.cplusplus.com/reference/cmath/nextafter/

现在,当我在 Ubuntu 13.04 上使用双精度或长双精度测试“nexttoward”或“nextafter”函数并使用 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;
}

程序的浮点输出值按预期稳步增加:

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;
}

请注意,“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 位浮点变量的范围?

4

1 回答 1

7

nextafterandnexttoward函数接受 type 的参数并double返回 type 的结果double

对于float,使用相应的nextafterfnexttowardf函数。

这是 . 中声明的几乎所有数学函数的一般规则<math.h>。例如,有三个平方根函数:

  • sqrtf(对于float
  • sqrt(对于double
  • sqrtl(对于long double

floatlong double版本是由 C99 添加的,可能并非所有实现都支持。)

如果你对一个类型使用了错误的函数,编译器不会抱怨;它会悄悄地将参数转换为预期的类型,并根据您使用它的方式转换结果。

那是针对 C 的。如果您使用,#include <cmath>C++ 会为类型f和. 因此,如果您将代码编译为 C++,那么这些函数的行为应该符合您的预期。(和之间可能存在差异;无论如何,对于 C++,您应该使用后者。)lfloatlong double<math.h><cmath>

您的问题被标记为 C 和 C++,它们在这方面有很大的不同。

(C99 还添加了一个<tgmath.h>头文件,该头文件提供特定于类型的宏,其行为类似于 C++ 的重载函数。)

于 2013-11-10T02:37:50.287 回答