An even better solution might be to use a function like the Logistic function.
Double minAlt = 0.0;
Double maxAlt = 500000.0;
Int32 numberSteps = 1000;
Double boundary = +6.0;
for (Int32 step = 0; step < numberSteps; step++)
{
Double t = -boundary + 2.0 * boundary * step / (numberSteps - 1);
Double correction = 1.0 / (1.0 + Math.Exp(Math.Abs(boundary)));
Double value = 1.0 / (1.0 + Math.Exp(-t));
Double correctedValue = (value - correction) / (1.0 - 2.0 * correction);
Double curAlt = correctedValue * (maxAlt - minAlt) + minAlt;
}
Because the current altitude is explicitly calculated you do not have to rely on a iterative calculation introducing all sorts of precision releated errors.
See the sample code for how to tune the function shape.
Here is a sample console application that displays the function. You can play a bit with the parameters to get a feeling for the behavior.
using System;
namespace LogisticFunction
{
class Program
{
static void Main(string[] args)
{
Double minAlt = 5.0;
Double maxAlt = 95.0;
Int32 numberSteps = 60;
// Keep maxAlt and numberSteps small if you don't want a giant console window.
Console.SetWindowSize((Int32)maxAlt + 12, numberSteps + 1);
// Positive values produce ascending functions.
// Negative values produce descending functions.
// Values with smaller magnitude produce more linear functions.
// Values with larger magnitude produce more step like functions.
// Zero causes an error.
// Try for example +1.0, +6.0, +20.0 and -1.0, -6.0, -20.0
Double boundary = +6.0;
for (Int32 step = 0; step < numberSteps; step++)
{
Double t = -boundary + 2.0 * boundary * step / (numberSteps - 1);
Double correction = 1.0 / (1.0 + Math.Exp(Math.Abs(boundary)));
Double value = 1.0 / (1.0 + Math.Exp(-t));
Double correctedValue = (value - correction) / (1.0 - 2.0 * correction);
Double curAlt = correctedValue * (maxAlt - minAlt) + minAlt;
Console.WriteLine(String.Format("{0, 10:N4} {1}", curAlt, new String('#', (Int32)Math.Round(curAlt))));
}
Console.ReadLine();
}
}
}