Download the code (2.90 KB)
I was working on an educational project using Windows Phone and XNA on the desktop (the phone will be controlling the desktop). The project involves demonstrating the laws of celestial mechanics. So the modeled entities have attributes with large values (ex: the mass of a planet in kilograms, the distance the planet is from its sun in meters, so on). In the Xna portion of the program the Vector3 class appeared to be a good fit for modeling a planet's position, velocity, acceleration, and so on. My only concern with Vector3 is the precision of the numeric type that it uses. It uses a single precision number. When I started my initial test I was seeing how small objects reacted on the earth's surface just to make sure that my gravity calculations were correct. Everything worked fine; the object would fall toward the earth with the expected acceleration. So I went straight from modeling a small object on the earth's surface to modeling the Earth's moon. That's when things broke down. The numbers coming back from the gravity calculations were all wrong.
It turns out I was running into a precision problem. Floating point types have enough precision to hold the final results of my calculations, but not enough prevision to hold the large intermediate values during the calculations. There are three ways to solve this:
- Use a Vector class with a higher precision numeric type
- Copy values from Vector3 to doubles, perform calculations, copy results back to Vector3
- Perform my calculations using Astronomical Units (AU) instead of meters.
I started with trying to copy values to double types before doing calculations first. That works, but I had concerns with the code getting messy and the overhead in coding that way. I thought about using astronomical units. But that would add an extra mental layer of complication. I think of calculations for gravity in terms of meters and trying to work in some other unit would likely lead to problems. There was no higher precision Vector3 class available. So last night I converted the Vector3 class to a double-precision version of itself that I named Vector3D. A majority of the methods available on Vector3 are available on the Vector3D class.
I replaced the Vector3 with the Vector3D class and everything worked as expected.
I figure at some point some one else will run into this problem so I've posted a copy of this class (link at the top of this entry). If I need to add more functionality to this class I'll be updating the version at the above link to.