10

Actually I am working on range expression in c++. So what I want is if I have any expression like

x<1

Then my

double getMax(...);

should return a double value that is just before 1.000 (double precision) on a number line.

I tried doing this

double getMax(double& a)
{
    return (a-numeric_limits<double>::min());
}

But I am still getting same value as a in return statement.

I think C++ is converting it to nearest double in cout statement.

int main()
{
    double a = 32;
    cout<<scientific<<getMax(a)<<endl;
    return 0;
}

output:

3.200000e+001
Apoorva sahay
  • 1,900
  • 3
  • 28
  • 45
  • All that below said, `getMax` does not make sense for open intervals and [`getSup`](http://en.wikipedia.org/wiki/Supremum) should return 1 exactly. – Jan Hudec Feb 26 '13 at 07:32

2 Answers2

10

First of all, you need to ensure that you actually print sufficiently many digits to ensure all representable values of double are displayed. You can do this as follows (make sure you #include <iomanip> for this):

    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << getMax(a) << std::endl;

Secondly, numeric_limits<>::min is not appropriate for this. If your starting value is 1.0, you can use numeric_limits<double>::epsilon, which is the smallest difference from 1.0 that is representable.

However, in your code example, the starting value is 32. Epsilon does not necessarily work for that. Calculating the right epsilon in this case is difficult.

However, if you can use C++11(*), there is a function in the cmath header that does what you need std::nextafter:

#include <iostream>
#include <limits>
#include <iomanip>
#include <cmath>

double getMax(double a)
{
  return std::nextafter(a,std::numeric_limits<double>::lowest());
}

int main()
{
    double a = 32;
    std::cout << std::scientific
              << std::setprecision(std::numeric_limits<double>::max_digits10)
              << getMax(a)
              << std::endl;
    return 0;
}

I've also put it on liveworkspace.

To explain:

double nextafter(double from, double to);

returns the next representable value of from in the direction of to. So I specified std::numeric_limits<double>::lowest() in my call to ensure you get the next representable value less than the argument.

(*)See Tony D's comment below. You may have access to nextafter() without C++11.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
  • 1
    Shouldn't the commented line be simply `a - a * ...::epsilon()`? – Jan Hudec Feb 26 '13 at 07:34
  • Oh, well, it will round towards zero. And `2 * a * ...::epsilon()` will be correct value if rounded, but twice bigger when not. Ouch ouch. – Jan Hudec Feb 26 '13 at 07:37
  • @JanHudec The `10` was a leftover from a test I ran before submitting the code. I've removed it. Whether multiplying with `a` is correct I don't know. Choosing the correct factor is beyond my knowledge -- my main point was to use `nextafter` in C++11. For correct calculation of epsilon, somebody else may craft an answer. – jogojapan Feb 26 '13 at 07:37
  • @JanHudec yeah you are right it should be a-a*...::epsilon(). – Apoorva sahay Feb 26 '13 at 07:47
  • The correct factor is a. The next representable value always differs in lowest bit of mantissa. So if next representable value after 1 is 1+ε, next representable value after 2 is 2+2ε. What I am not sure is rounding. It *should* work out, because 1.5 has the same exponent as 1, so after 1.5 the next representable value should be 1.5+1ε and that's exactly what 1.5+1.5ε happens to round to, but I am not sure there are no corner cases. – Jan Hudec Feb 26 '13 at 07:47
  • @JanHudec Sounds like it's time for your own answer. I'll definitely not add anything about epsilon calculation to mine because it's to easy to make mistakes, esp. when it comes to denormal values (which 32 certainly isn't, but still). In C++11, `nextafter()` is the answer, that's the only point I can make with confidence. – jogojapan Feb 26 '13 at 07:49
  • 1
    The other thing is I suspect ε does not work correctly for previous representable value. Because before 1 the next value is 1.fffffffffffffp-1 and that is 1-253, but ε is 2-52. – Jan Hudec Feb 26 '13 at 07:50
  • 2
    +1 / It's noteworthy that some systems provide this functionality in the provided C libraries, so you may be able to use it (non-portably) even if not using C++11: e.g. http://www.kernel.org/doc/man-pages/online/pages/man3/nextafter.3.html (standards: C99, POSIX.1-2001) – Tony Delroy Feb 26 '13 at 07:50
0

I think you've got the right idea. Check out Setting the precision of a double without using stream (ios_base::precision) not so much for the question, but for the examples they give of using precision. You might want to try something like printing with a precision of 53.

The way I usually see "close to but not quite" involves setting a difference threshold (typically called epsilon). In that case, you wouldn't use a getMax function, but have an epsilon used in your usage of less than. (You could do a class with the epsilon value and operator overloading. I tend to avoid operator overloading like a plague.)

Basically, you'd need:

bool lessThanEpsilon(double number, double lessThan, double epsilon)
{
    return (lessThan - number >= epsilon);
}

There are other varieties, of course. Equals would check if Math.abs(number - equals) < epsilon

Community
  • 1
  • 1
Scott Mermelstein
  • 15,174
  • 4
  • 48
  • 76