How to compare two different floats, to a certain degree of accuracy. I know that there are very slight imprecisions while using floats or doubles in any programming language, but which may however, be enough to cause this comparison of floats a < b to return a different value than it actually should.
I was solving a problem from the UVa Online Judge which gave me a Wrong Answer many times. It took few float values as input, albeit, to 2 decimal places. I figured out the makeshift solution, which was by splitting the input and converting it to ints, but I wouldn't prefer to use that always.
So my question is, what's the best way to compare whether a float a is lesser (or greater) than a float b, provided that the inputs of a and b are given correct to n decimal places, in this case, 2?
The language I prefer is C++.
Use std::numeric_limits<T>::epsilon() to check whether two numbers are almost equal. If you want to know whether one is greater/less you should also take into account the relative tolerance.
#include <cmath>
#include <limits>
template < typename T >
bool fuzzy_compare(T a, T b)
{
return std::abs(a - b) < std::numeric_limits<T>::epsilon();
};
Just use math:
#define PREC 0.01 //(1/pow(10,n)), n = 2
float c = a-b;
if (abs(c) < PREC) {
printf("a equals b");
} else if(c < 0){
printf("b is grater than a");
} else
printf("a is grater than b");
}
Use the setprecison() operator. The number you put in between the parentheses will determine how many numbers pass the decimal will be included in the output. Be sure to include the iomanip library.
Comparing floats is alway a tricky Here is a more complicated example, showing why you should use std::numeric_limits<T>::epsilon().
The first line returns true, but the second returns false (on my machine).
float64_t CalculateEpsilon ()
{
float64_t l_AllowedInaccuray = 1; // 1.1, 0.9
int32_t significantDecimalPlaces = 2;
return ( l_AllowedInaccuray * pow ( 0.1, significantDecimalPlaces ) );
}
bool IsEqual ( float64_t lhs, float64_t rhs )
{
float64_t l_Epsilon = CalculateEpsilon ();
float64_t l_Delta = std::abs ( lhs - rhs );
return l_Delta <= l_Epsilon;
}
int32_t main ()
{
std::cout << IsEqual ( 107.35999999999999, 107.350 ); //returns true
std::cout << IsEqual ( 107.359999999999999, 107.350 ); //returns false
return 0;
}
Related
The RooFit package allows me to import some TTree branches, but it constrains values included in those branches between the min and max value set by a RooRealVar. For instance:
RooRealVar t1("t1", "Some variable", 0.0, 1.0);
RooDataSet data("data", "My Dataset", RooArgSet(t1), Import(*myttree));
so long as the TTree myttree contains a branch called t1. This is all fine and good, until you start getting close to floating point values in the range. My particular problem occurs because I have a variable like t1 which maps to some variable with an exponential distribution. I'm trying to fit this distribution, but the fits fail for values of t1 ~ 0.0. My solution was to just change the range a bit to cut off potential events where the stored value of t1 in the tree is actually zero or close to it (all the following code is run in the ROOT interpreter, but I have confirmed it works in compiled code as well):
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
However, note the following annoying behavior:
root[1] t1 = 0.000998;
root[2] t1.getVal();
(double) 0.0010000000
// this is correct, as 0.000998 < 0.001 so RooFit set it as the lower limit
root[3] t1 = 0.000999;
root[4] t1.getVal();
(double) 0.00099900000
// this is incorrect.
Yes, the extra zero is printed in the second case, which I also don't understand, but I'm mostly concerned with the failure to recognize that 0.000999 < 0.001. When I compare these values later in an if-statement, I find that C++ can tell the difference. Everything appears to be double precision here, and I've been tracing through the code to see where the precision error seems to crop up. Correct me if I'm wrong, but a float should still hold these numbers up to comparison precision, right? What's going on here? If this is some floating point error problem, what's the best way to resolve it? I have several events with values like t1 = 0.000999874, and changing the bounds to something like 0.0001 doesn't really help either, there are still events which live on this edge.
Edit: I want to emphasize that while this is probably a floating point problem, it really shouldn't be. For instance, the following code works:
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
root[1] t1 = 0.000999;
root[2] t1.getVal() < 0.001;
(bool) true
Well everyone, I found the answer (and I hate it). It actually has very little to do with floating point arithmetic, and I'm honestly not sure why the code was written this way. From the source code that determines if a value is "in range":
bool RooAbsRealLValue::inRange(double value, const char* rangeName, double* clippedValPtr) const
{
// double range = getMax() - getMin() ; // ok for +/-INIFINITY
double clippedValue(value);
bool isInRange(true) ;
const RooAbsBinning& binning = getBinning(rangeName) ;
double min = binning.lowBound() ;
double max = binning.highBound() ;
// test this value against our upper fit limit
if(!RooNumber::isInfinite(max) && value > (max+1e-6)) {
clippedValue = max;
isInRange = false ;
}
// test this value against our lower fit limit
if(!RooNumber::isInfinite(min) && value < min-1e-6) {
clippedValue = min ;
isInRange = false ;
}
if (clippedValPtr) *clippedValPtr=clippedValue ;
return isInRange ;
}
As we can see here, RooFit doesn't actually check if min < val < max or even min <= val <= max but rather min - 1e-6 < value < max + 1e-6! I couldn't find a single place where this was documented explicitly, but I'm even more concerned that there is a separate implementation of inRange which takes a variable name (or comma separated list of variable names) and returns a result which is incompatible with the prior implementation:
bool RooAbsRealLValue::inRange(const char* name) const
{
const double val = getVal() ;
const double epsilon = 1e-8 * fabs(val) ;
if (!name || name[0] == '\0') {
const auto minMax = getRange(nullptr);
return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
}
const auto& ranges = ROOT::Split(name, ",");
return std::any_of(ranges.begin(), ranges.end(), [val,epsilon,this](const std::string& range){
const auto minMax = this->getRange(range.c_str());
return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
});
}
Here, we can see the creation of an epsilon = 1e-8 * fabs(val) rather than the arbitrary 1e-6 given in the first definition. This comparison uses a <= rather than a < also. It should be noted that the method used to filter trees when imported in this way uses the first implementation (source here).
Somewhere along the way (I'm not entirely sure where actually), some of these arbitrary comparisons lead to the following paradoxical behavior:
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
root[1] t1 = 0.001 - 1e-6;
(RooAbsArg &) RooRealVar::t1 = 0.000999 L(0.001 - 1)
root[2] t1 = 0.001 - 1e-8 * 0.001;
(RooAbsArg &) RooRealVar::t1 = 0.001 L(0.001 - 1)
root[3] t1 = 0.00099999999;
(RooAbsArg &) RooRealVar::t1 = 0.001 L(0.001 - 1)
I would classify this as a bug. Under no circumstances should 0.00099900000 be classified as within the range of (0.001 - 1) where 0.00099999999 is not!
I want to compare determinant, but i write it like this it gets error and is not executing. How can I compare complex no with real no for using if else condition.
I am using that if condition because I want that if roots are real then answer will not be in imaginary form like x+0i or (x,0). I simply want answer to be x.
#include <iostream>
#include <complex>
#include <cmath>
#include <iomanip>
using namespace std;
int main()
{
complex <double> a,b,c;
complex <double> x1,x2;
cout<<setprecision(3);
cout<<"Coefficient of square term: "; cin>>a;
cout<<"Coefficient of linear term: "; cin>>b;
cout<<"Coefficient of constant term: "; cin>>c;
complex <double> det=(b*b)-(4.0*a*c);
if (det>=0.0)
{
x1=(-b+sqrt(det))/(2.0*a);
x2=(-b-sqrt(det))/(2.0*a);
cout<<x1<<" "<<x2;
}
else
{
x1=(-b+sqrt(det))/(2.0*a);
x2=(-b-sqrt(det))/(2.0*a);
cout<<showpos;
cout<<x1.real()<<x1.imag()<<"i \n"<<x2.real()<<x2.imag()<<"i";
}
}
As discussed, it's questionable whether you really want to have an operator to do this. The operator compares modulae, and it will probably be clearer in the code to do that explicitly.
However, operators can be overridden as top level functions, do if you really want to, here' the code:
template<typename T>
bool operator >= (const complex<T>& l, const T& r)
{
return (l.imag() * l.imag() + l.real() * l.real()) >= r * r;
}
Though of course here you're doing a comparison with zero, and the modulus can never be negative, so I think your logic may be at fault somewhere.
It's more of a math misunderstanding, I guess.
The standard quadratic equation would have real coefficients a, b, c. Then det is also real and it can easily be checked for det >= 0. Which you have to do if you want to restrict to real solutions. But you don't have to check if you use complex x1, x2, because the complex numbers will handle sqrt(-1) automatically.
If you really want to have complex a, b, c, the formulae are also fine. There is no mathematical meaning in det >= 0 for complex det. The only interesting case you might want to check is det == 0 resulting in x1 and x2 being equal.
Aha, now I finally get what you want to check. Case one is for real solutions! To get that right, you have to check that det is real and not negative. I would write this as
if ( ( det - conj(det) == 0.0 ) && ( real(det) >= 0.0 ) ) { ... }
Note that you have to write 0.0 to clarify that it is a double. Also note that the simpler imag(det) == 0.0 for checking if it is real might run into 'the usual' problems with comparing floating point numbers directly.
// Read about the complex number comparison
// how on earth you can compare imaginary number with a real number
if (det.real() >= 0)
{
x1 = (-b+sqrt(det))/(2.0*a);
x2 = (-b-sqrt(det))/(2.0*a);
cout<<x1<<" "<<x2;
}
A complex number is a combination of both real and imaginary numbers, how can you compare a complex number with an imaginary number?
If you want to compare, then you need to compare the real part with real part and complex with complex.
Basically, how it works is it converts a number into a string, and if it finds any even in the string then it gives foundEven variable a positive value. The same goes for odd numbers.
(One thing I don't get is why if I switch the '>' sign with an '<' in if (FoundEvenSignedInt < FoundOddSignedInt) it gives you the correct result of an odd number.)
Are there any ways I could improve the code? Are there any bugs in it? I'm fairly new at C++ programing.
#include <string>
#include <cstddef>
int IsPrime(long double a)
{
int var;
long double AVar = a;
signed int FoundEvenSignedInt, FoundOddSignedInt;
std::string str = std::to_string(a);
std::size_t foundEven = str.find_last_of("2468");
std::size_t foundOdd = str.find_last_of("3579");
FoundEvenSignedInt = foundEven;
FoundOddSignedInt = foundOdd;
if (FoundEvenSignedInt < FoundOddSignedInt)
{
var = 1;
goto EndOfIsPrimeFunction;
}
if (FoundEvenSignedInt > FoundOddSignedInt)
{
var = 2;
goto EndOfIsPrimeFunction;
}
// This if statement kept giving me this weird warning so I made it like this
if (FoundEvenSignedInt == -1)
{
if (FoundOddSignedInt == -1)
{
if (AVar == 10 || 100 || 1000 || 10000 || 100000 || 1000000)
{
var = 2;
goto EndOfIsPrimeFunction;
}
}
}
EndOfIsPrimeFunction:
return var;
}
Here are some ways to improve the code.
The Collatz conjecture is about integers. long double is a data type of floating point numbers. It is unsuitable for checking the conjecture. You need to work with an integral data type such as unsigned long long. If this doesn't have enough range for you, you need to work with some kind of Bignum dat atype. There isn't any in the standard C library, you need to find a third party one.
The Collatz conjecture has nothing to do with being prime. It is about even and odd integers. It is true that all prime numbers except 2 are odd, but this fact doesn't help you.
The data type to answer yes/no questions in C++ is bool. By convention. for any other numeric data type zero means "no" and all other values mean "yes" (technically, when converted to bool, zero is converted to false and other values to true, so you can do things like if (a % 2). A function that returns 1 and 2 for yes and no is highly unconventional.
A natural method of checking whether a number is odd is this:
bool isOdd (unsigned long long a)
{
return a % 2;
}
It is somewhat faster than your code (by a factor of about 400 on my computer), gives correct results every time, is readable, and has zero goto statements.
Instead of the if(AVar == 10 || 100 || ..., you can say if(!(AVar % 10)).
I'm new to Visual C++, i have two double variables, let say AA = 10.650406 while b = 10.65040606439, how can i make them equal?
here is an example
AA = 10.650406;
if (a == tempfunc(zz))
execute TRUEFUNCTION
else
exceute FALSEFUNCTION
the variable AA is a double while the function tempfunc return double, if the value AA is 10.650406, while the return value of tempfunc is 10.65040606439. the question is how can make these value equal so i can execute the function TRUEFUNCTION
The typical solution is to compare the difference, using an "epsilon value". Something like
const double eps = 0.000001; // Adjust this to match the "perecision" you need.
if (abs(a-b) < eps)
{
// Values are almost equal
}
I guess your question is: how to have a check that would be true for these two numbers, but not for all..:
10.123 == 10.1234 (TRUE)
10.123 == 11.123 (FALSE)
if you have a fixed number of digits after the decimal separator (6 in your example), you could do this:
int a2 = a * 10e6;
int b2 = b * 10e6; // (conversion to integers; so the digits smaller than the 6th digit will be removed)
Now you can check:
if (a2 == b2)
{
//do your thing
}
in short:
if ( ((int) a*10e6) == ((int) b*10e6))
{
//do your thing
}
I have a function that deals with arbitrarily large grids. I need to compute if a grid to the power of another number will fit into a double due to using std::pow. If it cannot, I want to take a different branch and use gnu multiprecision library instead of normal.
Is there a quick way to see if:
int a = 1024;
int b = 0-10;
if(checkPowFitsDouble(a, b)) {
long c = static_cast<long>(std::pow(a, b)); //this will only work if b < 6
} else {
mpz_t c; //yada yada gmp
}
I am completely stumped on checkPowFitsDouble; perhaps there is some math trick I don't know of.
A common trick to check whether exponentiations will overflow uses logarithms. The idea is based on these relationships:
a^b <= m <=> log(a^b) <= log(m) <=> b * log(a) <= log(m) <=> b <= log(m) / log(a)
For instance,
int a = 1024;
for (int b = 0; b < 10; ++b) {
if (b * std::log(a) < std::log(std::numeric_limits<long>::max())) {
long c = std::pow(a, b);
std::cout << c << '\n';
}
else
std::cout << "overflow\n";
}
This gives the idea. I hope this helps.
Unless it's particularly performance-critical, the suggestion would be to try it and see. If it overflows a double, std::pow will return HUGE_VAL. Hence something like:
double val = std::pow(a, b);
if(val != HUGE_VAL) {
...
} else {
mpz_t c;
//...
}
You can easily use the reverse functions in the test:
if ( std::log( DBL_MAX ) / std::log( a ) < b ) {
// std::pow( a, b ) will not overflow...
} else {
}
It might be just as good to just do the pow, and see if it
succeeds:
errno = 0;
double powab = std::pow( a, b );
if ( errno == 0 ) {
// std::pow succeeded (without overflow)
} else {
// some error (probably overflow) with std::pow.
}
You won't gain much time by just calculating std::log( a ).
(std::log( DBL_MAX ) is, of course, a constant, so only needs
to be calculated once.)
With a logarithm base 10, you can deduce that std:pow(a, b) has log(a^b) = b log a digits. You can then trivially see if it fits a double, which can fit values up to DBL_MAX.
However, this method performs additional computation than just computing a^b once. Measure a version with GMP first and see if checking for overflow actually provides any measurable and reproducible benefits.
EDIT: Ignore this, std::pow already returns an appropriate value in case an overflow occurs, so use that.