0

I have been working on a c# vector class in order to practice my skills and teach myself and I came across a rather infuriating issue.

    public void Rotate (double rotation)
    {
        double xT;
        xT = x * Math.Cos (rotation * (Math.PI / 180)) - y * Math.Sin (rotation * (Math.PI / 180));
        y = x * Math.Sin (rotation * (Math.PI / 180)) + y * Math.Cos (rotation * (Math.PI / 180));
        x = xT; /*Figure out a better way to this*/
    }

This code is sloppy I know, but the issue comes from when I try a simple rotation of (1,0) 180 degrees around, instead of the expected (-1,0) that I should get, it instead returns (-1, -6.2343e-12) or something to that extent.

I understand that this is a issue with a lack of exactness in doubles, but I want to know if there is a way to have it still return a 0 instead of a number to the -12th.

Is there any way to do this?

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
toa697
  • 11
  • 4
  • 1
    `-0.0000000000062343` looks pretty much like 0 to me. Why is it bothering you? Does it really mess up your following calculations? You could round it up, but I wouldn't bother. – Pierre-Luc Pineault Feb 08 '15 at 03:23
  • This is a known "issue" in .NET with Sin/Cos. See the highest voted answer in http://stackoverflow.com/questions/3249710/accuracy-of-math-sin-and-math-cos-in-c-sharp. All I can say is that is how double values work, and if you need precise zeroes, then you need to round all your values to 11 decimal points. This problem is especially bad for values that should be zero, since the closest double values to zero are +/- 5e-324. – NextInLine Feb 08 '15 at 03:25
  • I know that there isnt a real way to avoid it, It just very much bugs me to see something other than what I know is the simple and correct answer, I was hoping there was a way to fix it. – toa697 Feb 08 '15 at 03:31
  • You can use a `sin` and `cos` that takes a number of degrees or a number of revolutions around the circle as argument instead. I don't know any C# implementation of such, but, if this really bothers you, you might port the implementation from `trigpi.c` in CRlibm. With the approach you're using, you're hosed as soon as you multiply your `double` by pi/180. – tmyklebu Feb 08 '15 at 03:37
  • @MickyDuncan: I would argue that 100 is not the correct answer in your example, but that whatever your program computes is. – tmyklebu Feb 08 '15 at 03:49
  • @MickyDuncan: And why shouldn't it? – tmyklebu Feb 08 '15 at 03:59
  • 1
    possible duplicate of [Storing cos and sin into a vector and getting weird values](http://stackoverflow.com/questions/27643267/storing-cos-and-sin-into-a-vector-and-getting-weird-values) – Pascal Cuoq Feb 08 '15 at 12:10
  • 1
    I am voting to close as a duplicate of a question in a different language because the fundamental issue here is not the programming language. – Pascal Cuoq Feb 08 '15 at 12:11
  • @PascalCuoq: I'm a little iffy on closing as-dupe of that question unless you update your answer there to point to actual implementations of `cospi` and `sinpi`. The question is a dupe, but the language here is an extra obstacle; – tmyklebu Feb 08 '15 at 15:48
  • @tmyklebu I take the opposite view: as long as the answer is “well, there is no real solution here, the fundamental problem is …, an attempt would start with sinpi and cospi but they are not widespread and it's not a perfect solution anyway, better would be cosdeg/sindeg but these do not even exist…”, it's the same answer for both questions in both languages. If my answer there was more useful, providing an actual solution for C++, then it would be a shame to close this one as a duplicate, because the C++ solution wouldn't necessarily work in C# :) – Pascal Cuoq Feb 08 '15 at 16:01
  • @PascalCuoq: But trigpi/trigdeg *are* real solutions to this problem! Since they aren't natively supported by .NET, they might be more trouble than the problem's worth to the poster, but they do solve the problem. – tmyklebu Feb 08 '15 at 16:32
  • @PascalCuoq: Also, you appear to be two upvotes shy of the gold floating-point badge. Why not post an answer, wait for two upvotes, *and then* close the question as a dupe all by yourself? :) – tmyklebu Feb 08 '15 at 17:11
  • @tmyklebu That would be *gaming* the system. I might as well take a well-received answer of mine to a past floating-point question that was well received but did not happen to be tagged floating-point, and re-tag it. Despicable! Although I like the irony of your proposal (but I don't think I would be allowed to re-vote to close or that the system would take my vote into account as a hammer vote). – Pascal Cuoq Feb 08 '15 at 17:35

1 Answers1

0

It is usually faster/cleaner to work with immutable structs for vectors

public struct Vector
{
   readonly double x, y;
   public Vector(double x, double y) { this.x=x; this.y=y; }
   public Vector Rotate(double angle) 
   {
       angle *= Math.PI/180;
       double cos = Math.Cos(angle), sin=Math.Sin(angle);
       return new Vector(
          x*cos-y*sin,
          x*sin+y*cos );
   }
}

Now as far as precision goes, the is no alternative but to use the trig functions in System.Math. I recommend sanitizing the angle inputs by wrapping them between -180..180 before converting into radians and using into the trig functions.

John Alexiou
  • 28,472
  • 11
  • 77
  • 133