简体   繁体   English

使用<math.h>中的C / C ++ nextafter / nexttoward函数无法获得下一个32位浮点值

[英]Failure to get next 32 bit float value using the C/C++ nextafter/nexttoward function in <math.h>

Using C or C++, I want to increment over the range of all representable 32 bit floating point numbers in a loop, similarly to the way you might increment over all distinct values represented by a 32 bit integer. 使用C或C ++,我想在循环中递增所有可表示的32位浮点数的范围,类似于可以递增由32位整数表示的所有不同值的方式。

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

I think that I could use the "nexttoward" or "nextafter" functions in the standard math library to accomplish that task. 我认为我可以使用标准数学库中的“nexttoward”或“nextafter”函数来完成该任务。 See http://www.cplusplus.com/reference/cmath/nextafter/ http://www.cplusplus.com/reference/cmath/nextafter/

Now, when I test out the "nexttoward" or "nextafter" functions with doubles or long doubles and compiling with g++ 4.7 on Ubuntu 13.04, I don't run in to any problems. 现在,当我测试带有双打或长双打的“nexttoward”或“nextafter”函数并在Ubuntu 13.04上使用g ++ 4.7进行编译时,我没有遇到任何问题。 See test code: 查看测试代码:

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

The program's floating point output values increase steadily as expected: 该程序的浮点输出值按预期稳步增长:

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

ubuntu@ubuntu:~$ ./temp ubuntu @ ubuntu:〜$ ./temp

0.10000000000000001942890293094023945741355419158935546875 0.100000000000000033306690738754696212708950042724609375 0.100000000000000033306690738754696212708950042724609375 0.10000000000000004718447854656915296800434589385986328125 0.10000000000000004718447854656915296800434589385986328125 0.1000000000000000610622663543836097232997417449951171875 0.1000000000000000610622663543836097232997417449951171875 0.10000000000000007494005416219806647859513759613037109375 0.10000000000000007494005416219806647859513759613037109375 0.100000000000000088817841970012523233890533447265625 0.10000000000000001942890293094023945741355419158935546875 0.100000000000000033306690738754696212708950042724609375 0.100000000000000033306690738754696212708950042724609375 0.10000000000000004718447854656915296800434589385986328125 0.10000000000000004718447854656915296800434589385986328125 0.1000000000000000610622663543836097232997417449951171875 0.1000000000000000610622663543836097232997417449951171875 0.10000000000000007494005416219806647859513759613037109375 0.10000000000000007494005416219806647859513759613037109375 0.100000000000000088817841970012523233890533447265625

ubuntu@ubuntu:~$ Ubuntu的@ Ubuntu的:〜$

But when I try using floats instead of doubles, the "nexttoward" and "nextafter" functions fail me - the functions appear to return values of greater precision than 32 bit floats, and when I assign the return values to my 32-bit float, the float retain its original value rather than going up to the next higher value. 但是当我尝试使用浮点数而不是双精度数时,“nexttoward”和“nextafter”函数使我失败 - 函数似乎返回比32位浮点数更高精度的值,并且当我将返回值赋给我的32位浮点数时,浮动保持其原始值而不是上升到下一个更高的值。 See example code and output: 请参阅示例代码和输出:

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

Notice that the second output value from "nexttoward" is of greater precision and that f maintains the same value: 请注意,“nexttoward”的第二个输出值具有更高的精度,并且f保持相同的值:

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

ubuntu@ubuntu:~$ ./temp 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 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

I want to increment over all 32-bit floating point values, not all 64-bit double precision values - the time to increment over all the double precision values would be too long. 我想增加所有32位浮点值,而不是所有64位双精度值 - 增加所有双精度值的时间太长。

How do I fix this problem and achieve an efficient, convenient, and portable way to iterate over the range of a 32-bit floating point variable? 如何解决此问题并实现高效,方便,可移植的方式迭代32位浮点变量的范围?

The nextafter and nexttoward functions take arguments of type double and return results of type double . nextafternexttoward函数接受double类型的参数并返回double类型的结果。

For float , use the corresponding nextafterf and nexttowardf functions. 对于float ,使用相应的nextafterfnexttowardf函数。

This is a general rule for almost all math functions declared in <math.h> . 这是<math.h>声明的几乎所有数学函数的一般规则。 For example, there are three square root functions: 例如,有三个平方根函数:

  • sqrtf (for float ) sqrtffloat
  • sqrt (for double ) sqrtdouble
  • sqrtl (for long double ) sqrtllong double

(The float and long double versions were added by C99, and may not be supported by all implementations.) floatlong double版本由C99添加,并且可能不受所有实现的支持。)

If you use the wrong function for a type, the compiler won't complain; 如果对类型使用了错误的函数,编译器就不会抱怨; it will quietly convert the argument to the expected type, and convert the result depending on what you do with it. 它会悄悄地将参数转换为预期的类型,并根据您对它的处理方式转换结果。

That's for C. If you use #include <cmath> , C++ adds overloaded versions of the math functions (without the f or l suffix) for types float and long double . 这是针对C.如果使用#include <cmath> ,C ++会为floatlong double类型添加数学函数的重载版本(不带fl后缀)。 So if you compile your code as C++, then these functions should behave as you expect. 因此,如果您将代码编译为C ++,那么这些函数应该按照您的预期运行。 (There may be a difference between <math.h> and <cmath> ; in any case, you should use the latter for C++.) <math.h><cmath>之间可能存在差异;在任何情况下,您都应该将后者用于C ++。)

Your question is tagged both C and C++, which have significant differences in this area. 您的问题被标记为C和C ++,这在这方面有显着差异。

(C99 also adds a <tgmath.h> header that provides type-specific macros that behave similarly to C++'s overloaded functions.) (C99还添加了一个<tgmath.h>标头,它提供了与C ++重载函数类似的特定于类型的宏。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM