• Forum
  • Lounge
  • getThreadHijacker() and setThreadHijacke

 
getThreadHijacker() and setThreadHijacker()

http://www.cplusplus.com/forum/beginner/142434/
http://www.cplusplus.com/forum/beginner/142642/
Disch wrote:
> Have fun debugging mysterious NaN and INF values in your vectors :)

You're mistreating the problem. If NaN/INF are a problem, they're going to be a problem everywhere... not just in your vectors. So why butcher the vector class to address a problem that isn't with the vector class?

If you don't want NaN/INF, then don't use doubles.

1
2
3
4
5
6
7
8
9
class NotQuiteADouble
{
    // a class the behaves like a double, but does not allow NaN/INF
};


sf::Vector<NotQuiteADouble>  foo;

foo.x = 5.0;  // yay!   public!  No risk of NaN! 
So, your solution is to completely replace the fundamental type you use everywhere. Versus this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct Vector2d
{
    //...

    double get_x(){ return x; }
    double get_y(){ return y; }

    void set_x(double v)
    {
//        if(is_allowed(v))
        {
            x = v;
            return;
        }
//        else { debug(v); }
        x = double{};
    }
    void set_y(double v)
    {
//        if(is_allowed(v))
        {
            y = v;
            return;
        }
//        else { debug(v); }
        y = double{};
    }

    //...

private:
    double x, y;
};
The compiler will almost always optimize the code to be the same as just directly accessing the members. But now you can enable checking for bad values whenever you want. This vector class is used everywhere and by simply adding a few lines in the setters you can get much closer to the source of the bad values, and then remove the debugging afterward.
Last edited on
So, your solution is to completely replace the fundamental type you use everywhere.


Your complaint was because NaN and INF are error prone.

If that's the case... then why are you only worried about NaN and INF inside the vector class? If this is a fundamental type that you are using everywhere, then don't have risk having that problem everywhere in your program? Why put a band-aid on just this one area --- an area that has absolutely nothing to do with the actual problem?



And no... my solution is not to replace a fundamental type. My solution is to not worry about such a contrived problem. I have been using doubles for over a decade and have never had a NaN/INF issue.



The point is... you are trying to fix a problem in this vector class... but that vector class has nothing to do with the actual problem.


The compiler will almost always optimize the code to be the same as just directly accessing the members.


I'm not worried about optimization. I'm worried about the class being overly complicated and clunky to use.

Compare your 33 line class to this, [practically] equally functional and easier to use class:

1
2
3
4
5
class Vector2d
{
public:
    double x, y;
};


The only difference? Doesn't guard against NaN/INF. Which again... is not an issue with vector -- but is an issue with double.



EDIT:

What's more... maybe I want NaN in my vector!

This is a general purpose support class. It shouldn't be telling me what values are and aren't valid. How can it possibly know what my needs are? I mean... I guess you could make it know... but then it's not a general purpose class anymore -- it's customized class built to address your specific problem.
Last edited on
OK, so I will agree with you about Vector2d. It's probably better to have a clean() member function.

But let's look at the circle class. Do you really want to allow NaNs there? Won't bad things happen when you try to draw it?
It's probably better to have a clean() member function.


I would even disagree with that. It's not Vector2d's job to bounds check. At all.

That would be like building a similar clean function into std::vector<double>. It doesn't make any sense.

But let's look at the circle class. Do you really want to allow NaNs there? Won't bad things happen when you try to draw it?


This makes a little more sense because conceptually you cannot have a negative radius. Though I still am not sure I'd agree that it's worth throwing up getters/setters for that.
> Have fun debugging mysterious NaN and INF values in your vectors :)

+/-INF does not cause fundamental problems; but NaN is another matter altogether.
NaN requires special-casing when any standard library algorithm involving comparisons is used.

Andrew Koenig on comparing floating point values, NaN, and strict weak ordering:

The purpose of NaN is to provide a value — or, more accurately, a family of values — that can be used to indicate that something went wrong during the process of computing that value. NaN values have the curious property that they compare as "unordered" with all values, even with themselves. In other words, if x is a NaN, and y is any floating-point value, NaN or not, then x<y, x>y, x<=y, x>=y, and x==y are all false, and x!=y is true.

This definition means that < on floating-point values fails to meet the requirements for C++ order relations! The reason for this failure is that if x and y are unequal ordinary values, and z is NaN, then x is unrelated to z, z is unrelated to y, but x and y are not unrelated to each other. Therefore, "unrelated" is not transitive, as C++ requires.

Remember that the requirements on "unrelated" cause it to partition the set of all values into equivalence classes. Because all NaN values are mutually unrelated, it makes sense to include them in a single equivalence class. As soon as we do so, we are saying that all NaN values are indistinguishable from each other for comparison purposes. In order for comparison to make sense, then, we must define it so that NaN is distinguishable from other values, so that non-NaN values can consistently be distinguished from each other.

The most straightforward strategy for defining comparison on floating-point numbers that might include NaN is to decide either that every NaN is "less than" every other number or "greater than" every other number.

1
2
3
4
5
6
bool compare(double x, double y)
 {
       if (isnan(y))
            return !isnan(x);
       return x < y;
 }

...

In short, comparing two floating-point numbers is harder than it looks if your goal is to meet the C++ order-relation requirements.

(Excerpt from an article on: 'How can we compare two numbers, either of which might be integer or floating-point?')
Disch wrote:
I would even disagree with that. It's not Vector2d's job to bounds check. At all.
Yes, you're right - I should have said "non-member function".
Disch wrote:
This makes a little more sense because conceptually you cannot have a negative radius. Though I still am not sure I'd agree that it's worth throwing up getters/setters for that.
A negative radius means that the front of the circle faces into the screen instead of out of the screen. But only for a ReversibleCircle. The implications? The draw order of the circle's components (e.g. fill texture, outline texture) is reversed.
Last edited on
A circle with a negative radius may not exist in the real world, but there are plenty of mathematical operations that work just fine ( and some specifically ) with them.

As far as rendering this circle to the screen, the circle should have no idea about how the renderer is going to handle its negative value.
If we define a circle as {p | norm(p - c) <= r}, then a negative radius is allowed. If we define it as {p | norm(p - c) * sign(r) <= r * sign(r)}, then a negative circle is a plane with the corresponding positive circle excised.
Topic archived. No new replies allowed.