Looking for some advice regarding Infinity/-Infinity in C#.
I'm currently building Geometry classes, for shapes like Rectangle/Circle etc. The user will provide the input for Width/Depth and Diameter respectively.
These properties will be double
and I understand that instead of explicitly overflowing, if you were to multiple double.MaxValue
by 2, then you would get +infinity etc.
Each of the shape classes will have additional properties such as Area, Perimeter etc. Therefore, even if the provided dimensions are less than MaxValue, there is a chance that computed values could be a huge number if the user was so inclined:
E.g. Math.PI x Math.Pow(diameter, 2) / 4
=> Math.PI x Math.Pow(double.MaxValue, 2) / 4
(i.e. This method would result in +infinity even though the user provided MaxValue as input.)
My question is whether I should always be guarding against infinity? Should I throw an exception (OverflowException) if either the user value or the computed values enter infinity?
It looks like it could be a code smell to check for infinity for every property/method in these geometric classes... Is there a better way?
public double Area
{
get
{
double value = Math.PI * Math.Pow(this.diameter, 2) / 4;
if (double.IsInfinity(value)
{
throw new OverflowException("Area has overflowed.");
}
}
}
public double Perimeter
{
get
{
double value = Math.PI * this.diameter;
if (double.IsInfinity(value)
{
throw new OverflowException("Perimeter has overflowed.");
}
}
}
Appreciate your time and thoughts! Cheers.
Conceptually, you have a design problem. Values that result in an infinite area result in an invalid state for your shape.
For example, say the shape in question is a circle. Any value passed in which results in Area > double.MaxValue
is an invalid state. Stated differently, any value diameter
where Math.PI * Math.Pow(diamater, 2) > double.MaxValue
is invalid.
Solve double.MaxValue = Math.PI * Math.Pow(diamater, 2)
for diameter
(it's 1.5129091144565236E+154
, and you're welcome to validate my math), and check for that in your constructor,
private const double MaxDiameter = 1.5129091144565236E+154;
Circle(double diameter)
{
if (diameter > MaxDiameter)
{
throw ArgumentOutOfRangeException();
}
}
--
In practice, consider the following. the diameter of the known universe is around 30 gigaparsecs, which converted to Planck lengths (the smallest distance unit I can think of) is around 5.7e61, which is far, far below double.MaxValue
.
I'd not worry about double overflow in your properties. It's sensible to design your shape so you it uses a unit type you've defined, so you always know what units you're working with.
public Circle(Meters diamater)
public Rectangle(Meters width, Meters height)