/// <summary>
/// Produce textual representation of the value distribution of histogram data by percentile.
/// The distribution is output with exponentially increasing resolution, with each exponentially decreasing
/// half-distance containing <paramref name="percentileTicksPerHalfDistance"/> percentile reporting tick points.
/// </summary>
/// <param name="histogram">The histogram to operate on</param>
/// <param name="writer">The <see cref="TextWriter"/> into which the distribution will be output</param>
/// <param name="percentileTicksPerHalfDistance">
/// The number of reporting points per exponentially decreasing half-distance
/// </param>
/// <param name="outputValueUnitScalingRatio">
/// The scaling factor by which to divide histogram recorded values units in output.
/// Use the <see cref="OutputScalingFactor"/> constant values to help choose an appropriate output measurement.
/// </param>
/// <param name="useCsvFormat">Output in CSV (Comma Separated Values) format if <c>true</c>, else use plain text form.</param>
public static void OutputPercentileDistribution(this HistogramBase histogram,
TextWriter writer,
int percentileTicksPerHalfDistance = 5,
double outputValueUnitScalingRatio = OutputScalingFactor.None,
bool useCsvFormat = false)
{
var formatter = useCsvFormat
? (IOutputFormatter) new CsvOutputFormatter(writer, histogram.NumberOfSignificantValueDigits, outputValueUnitScalingRatio)
: (IOutputFormatter) new HgrmOutputFormatter(writer, histogram.NumberOfSignificantValueDigits, outputValueUnitScalingRatio);
try
{
formatter.WriteHeader();
foreach (var iterationValue in histogram.Percentiles(percentileTicksPerHalfDistance))
{
formatter.WriteValue(iterationValue);
}
formatter.WriteFooter(histogram);
}
catch (ArgumentOutOfRangeException)
{
// Overflow conditions on histograms can lead to ArgumentOutOfRangeException on iterations:
if (histogram.HasOverflowed())
{
writer.Write("# Histogram counts indicate OVERFLOW values");
}
else
{
// Re-throw if reason is not a known overflow:
throw;
}
}
}