110

Is there a standard and/or portable way to represent the smallest negative value (e.g. to use negative infinity) in a C(++) program?

DBL_MIN in float.h is the smallest positive number.

Will
  • 73,905
  • 40
  • 169
  • 246
  • 4
    I'll go for -DBL_MAX, but I'm sure there is some technical reason why this isn't so :-) –  Jul 20 '09 at 13:27
  • 4
    @Neil, no there isn't, it's not like 2 Complement integers – fortran Jul 20 '09 at 13:33
  • I haven't seen anything yet in the standard to say that the range of the floating point types has to be symmetrical around zero. But the constants in limits.h and suggest that both the C and C++ standard are kind of expecting they will be. – Steve Jessop Jul 20 '09 at 20:03
  • @onebyone There is a sign bit (the 31st in float and the 63rd in double), so take any positive value and set the sign bit on, then you have the same magnitude, but negative, that's why it's symmetrical. In case you were wondering, yes, there's a positive zero and a negative zero. – fortran Jul 22 '09 at 19:55
  • 4
    Actually DBL_MIN in float.h is the smallest _positive_ **normalized** number. There are numbers that are even smaller. – fdermishin Mar 18 '13 at 18:34
  • 1
    @fortran: *IEEE 754* FP uses a sign bit, and certainly most FP hardware these days is IEEE 754. But C and C++ support non-IEEE 754 FP hardware, so the question is open as to whether the language makes the guarantee that -DBL_MAX must be equal to the minimum representable value. – j_random_hacker Aug 11 '13 at 22:58

10 Answers10

150

-DBL_MAX in ANSI C, which is defined in float.h.

James Bedford
  • 28,702
  • 8
  • 57
  • 64
dfa
  • 114,442
  • 31
  • 189
  • 228
  • this seems the most standard and portable – Will Jul 20 '09 at 13:50
  • Here's the explanation for my -1: who or what says that -DBL_MAX is guaranteed by the C or C++ language to be representable, let alone the minimum representable value? The fact that most FP hardware is IEEE 754-conformant, and it uses this representation, doesn't mean -DBL_MAX is guaranteed to work on any standard-conformant C platform. – j_random_hacker Aug 11 '13 at 23:01
  • @j_random_hacker: see fortran's answer 'below'. – JohnTortugo May 13 '14 at 21:07
  • @JohnTortugo: What if (as I tried to make clear in my comment) *the FP hardware is not IEEE 754*? Then there's no guarantee that `-DBL_MAX` is representable, or that it's the smallest representable number. – j_random_hacker May 13 '14 at 23:21
  • 3
    @j_random_hacker That's a very good point, but the C standard requires `-DBL_MAX` to be exactly representable, so if the FP hardware is not capable of that, the implementation just has to work around it. See the floating-point model in *5.2.4.2.2 Characteristics of floating types p2* of C99 (may have been moved elsewhere since then). –  Nov 10 '14 at 22:23
  • @hvd: A good suggestion, but after looking at the section you mention I didn't come away with the feeling that it implied this guarantee. It specifies a model that uses multiplication by a sign bit s, but about DBL_MAX says only that it is the "maximum representable floating-point number, (1-b^-p)b^(e_max)" – j_random_hacker Nov 10 '14 at 23:41
  • 3
    @j_random_hacker Yes, but p2 specifies e_min and e_max are independent of the sign bit, so `DBL_MAX` is exactly (1 − b^−p)b^e_max, which is exactly representable, the most-negative finite value is exactly -(1 − b^−p)b^e_max, and since that happens to be exactly `-DBL_MAX`, negating `DBL_MAX` cannot introduce any rounding errors either. –  Nov 11 '14 at 08:35
77

Floating point numbers (IEEE 754) are symmetrical, so if you can represent the greatest value (DBL_MAX or numeric_limits<double>::max()), just prepend a minus sign.

And then is the cool way:

double f;
(*((uint64_t*)&f))= ~(1LL<<52);
fortran
  • 74,053
  • 25
  • 135
  • 175
  • 9
    +1 For pointing out the symmetry of of floating point numbers :) – Andrew Hare Jul 20 '09 at 13:35
  • 6
    What about C/C++ implementations which do not use IEEE 754 floats? – Steve Jessop Jul 20 '09 at 20:03
  • @onebyone, tell me one that doesn't... I think you cannot, because all C/C++ compilers use the native processor format for floating point numbers, and now I cannot think about any FPU that doesn't adhere to the IEEE 754 standard (maybe in the dark ages of computing, when everybody had his own in house formats...) – fortran Jul 20 '09 at 21:12
  • 2
    gcc's manual for -ffast-math says "Sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and -fcx-limited-range This option is not turned on by any -O option since it can result in incorrect output for programs which depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications." Fast math is a common setting, and the Intel ICC for example defaults to it. All in all, not sure what this means for me :-) – Will Jul 20 '09 at 22:30
  • 4
    It means implementations don't use IEEE 754 arithmetic, but to be fair those options do still use IEEE representation. You might find some emulation libraries using non-IEEE representation, since not all processors have a native float format (although they may publish a C ABI that includes a format, corresponding to emulation libs supplied by the manufacturer). Hence not all compilers can use one. Just depends what you mean when you ask for "standard and/or portable", there's portable in principle and portable in practice. – Steve Jessop Jul 20 '09 at 22:59
  • @Will If you read carefully, it says math functions, not mentions anything about number format representation. I think you can tell apart those two very different things... The IEEE semantics specify that the approximation of the result of an floating point operation must be the same as if the operation was done with inifinite precission and then truncated (maybe there were some more implications, but my numerical analysis lessons seem very far away now)... I'm sure you could find more about this fascinating theme on the web ;-) – fortran Jul 20 '09 at 23:18
  • can you be a bit more detailed please as to why you used all the casts in the cool way ? thanks! – Ciprian Tomoiagă Feb 18 '15 at 18:38
  • 1
    @CiprianTomoiaga because if you assign a long (with the desired bit pattern) to a float/double, the compiler will make an arithmetic casting (converting that integer number to the closest approximation). You need to convince the compiler that you are assigning to an *lvalue* that is an integer too to avoid the number conversion. Other way to achieve it would be copying memory (memcpy), but that wouldn't work with an immediate literal (you would need to assign the bit pattern to an addressable variable). – fortran Feb 18 '15 at 19:25
  • 3
    What you say is true for IEEE 754, but the standard doesn't require the use of this encoding (as @SteveJessop points out, portable in practice is not the same as portable in principle). – Christophe Sep 22 '16 at 20:51
  • `long long` is not specified as the same size nor alignment as `double`. `(long long*)&some_double` sets up for UB when their differences are more common. – chux - Reinstate Monica Mar 19 '22 at 16:48
  • @chux-ReinstateMonica I thought it was obvious that _the cool way_ was meant to be sarcastic :D I would never encourage anybody to do that when the options above are clearly more readable and portable; it was just to show the bit layout of the IEE754 minimum value. I'm changing it to `uint64_t` anyway :-p – fortran Mar 21 '22 at 10:57
  • fortran, `double` as 64-bit is a maybe safe bet, `double` and `uint64_t` having the same endian is less so. `(*((uint64_t*)&f))= ~(1LL<<52);` also unnecessarily mixes integer types of different sign-ness & potentially different widths. Use of un-cool `UINT64_C()` from `` solves the latter 2 of those 3 problems. To solve the 1st, best to not assume knowledge of `double` encoding. I too, like to do such cool tricks BITD, yet to write code that lasts years, I avoid such. [Aliasing](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) concerns may also apply here. – chux - Reinstate Monica Mar 21 '22 at 14:22
53

In C, use

#include <float.h>

const double lowest_double = -DBL_MAX;

In C++pre-11, use

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

In C++11 and onwards, use

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();
rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • Wasn't the `min()` function available before C++11? Or is that a different value than `-max()`? http://en.cppreference.com/w/cpp/types/numeric_limits – Alexis Wilke Oct 23 '14 at 03:12
  • 6
    @Alexis: if you look at the lowest three rows in the table on the page you linked, you'll see that `min` gets you the smallest positive value in magnitude, and `lowest` the largest negative value in magnitude. Yes, it's terrible. Welcome to brilliant world of the C++ standard library `:-P`. – rubenvb Oct 23 '14 at 07:08
  • for C it is defined in `float.h`. `limits.h` is for integers – Ciprian Tomoiagă Feb 18 '15 at 18:46
34

Try this:

-1 * numeric_limits<double>::max()

Reference: numeric_limits

This class is specialized for each of the fundamental types, with its members returning or set to the different values that define the properties that type has in the specific platform in which it compiles.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • 1
    Why not just `-numeric_limits::max()`? – k06a May 11 '16 at 17:45
  • 4
    @k06a having the negation represented by a single character in such a long expression, where the string even says "max", is sure to get someone sooner or later. Either it's stored in a descriptive variable, or use `-1 * ...` to make it a bit clearer. – Filip Haglund Jan 02 '17 at 23:34
22

Are you looking for actual infinity or the minimal finite value? If the former, use

-numeric_limits<double>::infinity()

which only works if

numeric_limits<double>::has_infinity

Otherwise, you should use

numeric_limits<double>::lowest()

which was introduces in C++11.

If lowest() is not available, you can fall back to

-numeric_limits<double>::max()

which may differ from lowest() in principle, but normally doesn't in practice.

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • +1 for the difference between finite and infinite value ! But the standard doesn't guarantee a symetric floating point encoding. So `-numeric_limits::max()` even if it works in practice is not fully portable in theory. – Christophe Sep 22 '16 at 20:53
  • @Christophe: [x] fixed – Christoph Sep 22 '16 at 21:45
11

A truly portable C++ solution

As from C++11 you can use numeric_limits<double>::lowest(). According to the standard, it returns exactly what you're looking for:

A finite value x such that there is no other finite value y where y < x.
Meaningful for all specializations in which is_bounded != false.

Online demo


Lots of non portable C++ answers here !

There are many answers going for -std::numeric_limits<double>::max().

Fortunately, they will work well in most of the cases. Floating point encoding schemes decompose a number in a mantissa and an exponent and most of them (e.g. the popular IEEE-754) use a distinct sign bit, which doesn't belong to the mantissa. This allows to transform the largest positive in the smallest negative just by flipping the sign:

enter image description here

Why aren't these portable ?

The standard doesn't impose any floating point standard.

I agree that my argument is a little bit theoretic, but suppose that some excentric compiler maker would use a revolutionary encoding scheme with a mantissa encoded in some variations of a two's complement. Two's complement encoding are not symmetric. for example for a signed 8 bit char the maximum positive is 127, but the minimum negative is -128. So we could imagine some floating point encoding show similar asymmetric behavior.

I'm not aware of any encoding scheme like that, but the point is that the standard doesn't guarantee that the sign flipping yields the intended result. So this popular answer (sorry guys !) can't be considered as fully portable standard solution ! /* at least not if you didn't assert that numeric_limits<double>::is_iec559 is true */

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
7
- std::numeric_limits<double>::max()

should work just fine

Numeric limits

MadH
  • 1,498
  • 4
  • 21
  • 29
2

Is there a standard and/or portable way to represent the smallest negative value (e.g. to use negative infinity) in a C(++) program?

C approach.

Many implementations support +/- infinities, so the most negative double value is -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

Is there a standard and/or portable way ....?

Now we need to also consider other cases:

  • No infinities

Simply -DBL_MAX.

  • Only an unsigned infinity.

I'd expect in this case, OP would prefer -DBL_MAX.

  • De-normal values greater in magnitude than DBL_MAX.

This is an unusual case, likely outside OP's concern. When double is encoded as a pair of a floating points to achieve desired range/precession, (see double-double) there exist a maximum normal double and perhaps a greater de-normal one. I have seen debate if DBL_MAX should refer to the greatest normal, of the greatest of both.

Fortunately this paired approach usually includes an -infinity, so the most negative value remains -INFINITY.


For more portability, code can go down the route

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The original question concerns infinity. So, why not use

#define Infinity  ((double)(42 / 0.0))

according to the IEEE definition? You can negate that of course.

melpomene
  • 84,125
  • 8
  • 85
  • 148
Norbert
  • 91
  • 1
  • 3
  • Nice idea ! And [it works](https://ideone.com/LHuXA4). But only if `numeric_limits::has_infinity && ! numeric_limits::traps` – Christophe Sep 22 '16 at 21:01
-1

If you do not have float exceptions enabled (which you shouldn't imho), you can simply say:

double neg_inf = -1/0.0;

This yields negative infinity. If you need a float, you can either cast the result

float neg_inf = (float)-1/0.0;

or use single precision arithmetic

float neg_inf = -1.0f/0.0f;

The result is always the same, there is exactly one representation of negative infinity in both single and double precision, and they convert to each other as you would expect.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106
  • Why would you do this instead of just writing `-INFINITY` – M.M Sep 14 '19 at 00:24
  • Also, infinity may or may not exist, and if it does exist then positive and negative might not be distinguishable (in Standard C). – M.M Sep 14 '19 at 00:25
  • In many compilers and/or architectures your C/C++ code will slow down a lot of you propagate infinity and NaN values. – markgalassi Jul 05 '20 at 04:11
  • @markgalassi Please take a closer look: You will notice that `neg_inf` is initialized to a *constant value*. The compiler will take care of computing the `inf` value. And when you use it as null-value for computing a max, the first iteration will generally overwrite it with a larger value. I.e. the performance is hardly a problem. And the OP asks specifically about "e.g. to use negative infinity", and `-inf` is indeed the only correct answer to this. You have downvoted a correct and useful answer. – cmaster - reinstate monica Jul 05 '20 at 10:18