What's the least possible denominator/divisor value? - c++

I'm writing a code to prevent the zero denominator/divisor to avoid NaN value as a result of the division.
I wonder what could be the least possible denominator value in double in C++ and how to find or what's the reason for that?

Well, the smallest positive(a) normalised double in C++ can be obtained with std::numeric_limits<double>::min() (from the <limits> header).
However, while you may be able to use that to prevent NaN values(b), it probably won't help with overflows. For example:
std::numeric_limits<double>::max() / 1.0 => ok
std::numeric_limits<double>::max() / 0.5 => overflow
Preventing that will depend on both the denominator and the numerator.
As for why that is the case, it's because C++ uses IEEE-754 double-precision format for its double types - it's a limitation of that format.
(a) I've chosen positive values here, the smallest value could be interpreted as the most negative, in which case it would be read as -std::numeric_limits<double>::max(). But, given your intent is to avoid NaN, I suspect my assumption is correct.
(b) I'm not entirely sure how you intend to do this, which is why I also discuss overflows - you may want to make it clearer in your question.

The smallest possible float is 1.17549e-38. To expand upon It's coming home's comment, see the answer from here:
#include <limits>
//...
std::numeric_limits<float>::max(); // 3.40282e+38
std::numeric_limits<float>::min(); // 1.17549e-38
std::numeric_limits<float>::infinity();
The float in the above code can be replaced by any data type you want, ie:
std::numeric_limits<int>::min();

Related

how could minimal value of float number smaller than precision? [duplicate]

I was solving an equation using double precision and I got -7.07649e-17 as a solution instead of 0.
I agree it's close enough that I can say it's equal but I've read that the machine epsilon for the C++ double type is 2^-52 which is larger than the value I get.
So why do I have an inferior value than the machine epsilon?
Why isn't the value rounded to zero?
It's not a big deal but when I do a logical test it appears that my value is not zero...
There are two different constants in this story. One is epsilon, which is a minimal value that when added to 1.0 produces a value different from 1.0. If you add a smaller value to 1.0 you will again get a 1.0, because there are physical limits to the representation of a number in a computer. But there are values that are less than epsilon and greater than zero. Smallest such number for a double you get with std::numeric_limits<double>::min.
For reference, you get epsilon with std::numeric_limits<double>::epsilon.
You are not guaranteed that rounding will take place at any particular time. The C++ standard permits the implementation to use additional precision pretty much anywhere it wants to and many real-world implementations do exactly that.
A common solution for the floating point precision problem is to define an epsilon value yourself and compare to that instead of zero.
e.g.
double epsilon = 0.00001;
if (abs(value) < epsilon) // treat value as 0 in your code

Why my double can contain a value below the machine epsilon?

I was solving an equation using double precision and I got -7.07649e-17 as a solution instead of 0.
I agree it's close enough that I can say it's equal but I've read that the machine epsilon for the C++ double type is 2^-52 which is larger than the value I get.
So why do I have an inferior value than the machine epsilon?
Why isn't the value rounded to zero?
It's not a big deal but when I do a logical test it appears that my value is not zero...
There are two different constants in this story. One is epsilon, which is a minimal value that when added to 1.0 produces a value different from 1.0. If you add a smaller value to 1.0 you will again get a 1.0, because there are physical limits to the representation of a number in a computer. But there are values that are less than epsilon and greater than zero. Smallest such number for a double you get with std::numeric_limits<double>::min.
For reference, you get epsilon with std::numeric_limits<double>::epsilon.
You are not guaranteed that rounding will take place at any particular time. The C++ standard permits the implementation to use additional precision pretty much anywhere it wants to and many real-world implementations do exactly that.
A common solution for the floating point precision problem is to define an epsilon value yourself and compare to that instead of zero.
e.g.
double epsilon = 0.00001;
if (abs(value) < epsilon) // treat value as 0 in your code

Issue with std::numeric_limits<T>::min() with float/double values

While writing some code to ensure user input is valid I came across an issue with std::numeric_limits<T>::min(); where T is a floating point type i.e double/float etc.
Using -std::numeric_limits<double>::max(); allows me to get the real minimum value but you would expect std::numeric_limits<double>::min(); to return that.
Why does std::numeric_limits<double>::min(); not return the smallest possible value of these types and instead force us to use std::numeric_limits::lowest or -std::numeric_limits<double>::max();?
Yes, using -max() will give lowest value.
In C++11 there is also std::numeric_limits::lowest that is consistent for reals and ints.
http://en.cppreference.com/w/cpp/types/numeric_limits/lowest
See also How to workaround the inconsistent definition of numeric_limits<T>::min()?
Why is this?
This is because std::numeric_limits<>::min() returns implementation defined FLT_MIN, DBL_MIN or INT_MIN. In this regard behavior of this method is consistent. But the return value ofstd::numeric_limits<double>::min(): DBL_MIN has slightly different meaning than INT_MIN. This is the smallest value that double can represent. There might be value greater than 0 but double can't represent it.
why does using min() not do the same thing in this instance?
The rationale behind this is that you can query <limits> for this value to check for this possible underflow specific to floating point arithmetic.
You can use
std::numeric_limits<double>::lowest()
to query for a lowest negative value.

How do I check and handle numbers very close to zero

I have some math (in C++) which seems to be generating some very small, near zero, numbers (I suspect the trig function calls are my real problem), but I'd like to detect these cases so that I can study them in more detail.
I'm currently trying out the following, is it correct?
if ( std::abs(x) < DBL_MIN ) {
log_debug("detected small num, %Le, %Le", x, y);
}
Second, the nature of the mathematics is trigonometric in nature (aka using a lot of radian/degree conversions and sin/cos/tan calls, etc), what sort of transformations can I do to avoid mathematical errors?
Obviously for multiplications I can use a log transform - what else?
Contrary to widespread belief, DBL_MIN is not the smallest positive double value but the smallest positive normalized double value. Typically - for 64-bit ieee754 doubles - it's 2-1022, while the smallest positive double value is 2-1074. Therefore
I'm currently trying out the following, is it correct?
if ( std::abs(x) < DBL_MIN ) {
log_debug("detected small num, %Le, %Le", x, y);
}
may have an affirmative answer. The condition checks whether x is a denormalized (also called subnormal) number or ±0.0. Without knowing more about your specific situation, I cannot tell if that test is appropriate. Denormalized numbers can be legitimate results of calculations or the consequence of rounding where the correct result would be 0. It is also possible that rounding produces numbers of far greater magnitude than DBL_MIN when the mathematically correct result would be 0, so a much larger threshold could be sensible.
If x is a double, then one problem with this approach is that you can't distinguish between x being legitimately zero, and x being a positive value smaller than DBL_MIN. So this will work if you know x can never be legitimately zero, and you want to see when underflow occurs.
You could also try catching the SIGFPE signal, which will fire on a POSIX-compliant system any time there's a math error including floating-point underflow. See: http://en.wikipedia.org/wiki/SIGFPE
EDIT: To be clear, DBL_MIN is NOT the largest negative value that a double can hold, it is the smallest positive normalized value that a double can hold. So your approach is fine as long as the value can't be zero.
Another useful constant is DBL_EPSILON which is the smallest double value that can be added to 1.0 without getting 1.0 back. Note that this is a much larger value than DBL_MIN. But it may be useful to you since you're doing trigonometric functions that may tend toward 1 instead of tending toward 0.
Since you are using C++, the most idiomatic is to use std::numeric_limits from header <limits>.
For instance:
template <typename T>
bool is_close_to_zero(T x)
{
return std::abs(x) < std::numeric_limits<T>::epsilon();
}
The actual tolerance to be used heavily depends on your problem. Please complete your question with a concrete use case so that I can enhance my answer.
There is also std::numeric_limits<T>::min() and std::numeric_limits<T>::denorm_min() that may be useful. The first one is the smallest positive non-denormalized value of type T (equal to FLT/DBL/LDBL_MIN from <cfloat>), the second one is the smallest positive value of type T (no <cfloat> equivalent).
[You may find this document useful to read if you aren't at ease with floating point numbers representation.]
The first if check will actually only be true when your value is zero.
For your second question, you imply lots of conversions. Instead, pick one unit (deg or rad) and do all your computational operations in that unit. Then at the very end do a single conversion to the other value if you need to.

C++ float number to nan

I want to know what makes a float number nan in c++. I am using a large dataset and it is really hard to trace. I want to know the ways of changing a float number to nan to reduce bug possibilities.
I found the code that causes the nan problem. I found that s/m is nan in some cases. But I don't know how to solve it.
float gp(float x){
float e = 2.71828183;
x *= -1;
float s = pow(e,x);
float m = (1 + pow(e,x)) * (1 + pow(e,x));
return s / m;}
Taken from wikipedia -> special values -> nan
0/0
∞×0
sqrt(−1)
in general "invalid operations" (I am not sure wether there are not more than the three above)
Looking at you code: infinity times 0 is possible, is it?
edit:
0 <= s <= +inf
1 <= m <= +inf
s / m:
+inf / +inf does indeed make minus NaN (I tested it)
I think that's the only thing that makes a NaN.
If you can keep x between 0 and FLT_MAX (3.40E+38 in my case), your gp function will not return NaN.
You say in a comment that you only use *, +, -.
[Edit: you've since said that you also use pow and division, which introduce some extra ways to get NaN. For example if the parameter x is a large negative value then pow(e,-x) is infinity, so you can easily end up computing infinity/infinity, which is another NaN]
So, if you have IEEE floating-point then assuming this summary is correct, the only ways you can generate NaN are:
Generate a positive or negative infinity by going out of range,
Multiply it by zero.
or:
Generate a positive and a negative infinity,
Add them (or equivalently, subtract two infinities of the same sign).
So if you check for and catch infinities, you don't have to worry about NaNs as well. That said, the usual way is to let such values propagate as quiet NaNs, and check at the end.
For C++ implementations using non-IEEE arithmetic, I'm not sure what the rules are when a NaN is permitted. I could look them up in the standard, but then again so could you ;-)
sqrt(-1)
give you NaN, for example.
http://www.gnu.org/s/libc/manual/html_node/Infinity-and-NaN.html
EDIT Try use double instead of float.
Probably it depends to compiler you using but general option is:
variable is too small
variable is too big
divide by 0 (zero)
This is exactly the use case for enabling and trapping floating-point exceptions. That way you can detect exactly where the NaN (or other exception value) first appears.
However, that's a platform-dependant feature, so you may have to look into the documentation of your compiler and/or hardware.