NumericRangeTools
Provides numeric range generation and manipulation utilities.
Overview
The NumericRangeTools class offers powerful utilities for generating numeric ranges, creating sequences, and performing range-based calculations using modern .NET generic constraints.
API Reference
Core Methods
Range Generation
GetRange<T>(T start, T end, T step) where T : INumber
Generates a sequence of numbers from start to end with specified step size.
// Integer ranges
var integers = NumericRangeTools.GetRange(0, 10, 2);
// Result: [0, 2, 4, 6, 8, 10]
// Floating-point ranges
var decimals = NumericRangeTools.GetRange(0.0, 1.0, 0.1);
// Result: [0.0, 0.1, 0.2, 0.3, ..., 1.0]
// Custom step sizes
var fibonacci = NumericRangeTools.GetRange(1, 100, 3);
// Result: [1, 4, 7, 10, ..., 97, 100]
GetRange<T>(T start, T end, int numberOfSteps) where T : INumber
Generates a sequence with a specific number of evenly distributed steps.
// 5 evenly distributed points between 0 and 100
var points = NumericRangeTools.GetRange(0.0, 100.0, 5);
// Result: [0.0, 25.0, 50.0, 75.0, 100.0]
// 10 points between 1 and 2
var precision = NumericRangeTools.GetRange(1.0, 2.0, 10);
// Result: [1.0, 1.111..., 1.222..., ..., 2.0]
Linear Interpolation
Lerp<T>(T start, T end, double t) where T : INumber
Performs linear interpolation between two values.
// 50% between 0 and 100
double mid = NumericRangeTools.Lerp(0.0, 100.0, 0.5); // 50.0
// 25% between 10 and 20
float quarter = NumericRangeTools.Lerp(10.0f, 20.0f, 0.25); // 12.5f
// Beyond range (extrapolation)
double beyond = NumericRangeTools.Lerp(0.0, 10.0, 1.5); // 15.0
InverseLerp<T>(T start, T end, T value) where T : INumber
Finds the interpolation factor for a value within a range.
// What percentage is 50 between 0 and 100?
double t = NumericRangeTools.InverseLerp(0.0, 100.0, 50.0); // 0.5
// What percentage is 75 between 50 and 100?
double t2 = NumericRangeTools.InverseLerp(50.0, 100.0, 75.0); // 0.5
Advanced Operations
Range Mapping
MapRange<T>(T value, T fromMin, T fromMax, T toMin, T toMax) where T : INumber
Maps a value from one range to another range.
// Map temperature from Celsius (0-100) to Fahrenheit (32-212)
double celsius = 37.0; // Body temperature
double fahrenheit = NumericRangeTools.MapRange(celsius, 0.0, 100.0, 32.0, 212.0);
// Result: 98.6°F
// Map percentage (0-100) to RGB value (0-255)
int rgbValue = NumericRangeTools.MapRange(80, 0, 100, 0, 255);
// Result: 204
Range Analysis
IsInRange<T>(T value, T min, T max, bool inclusive = true) where T : INumber
Checks if a value falls within a specified numeric range.
bool inRange = NumericRangeTools.IsInRange(50, 0, 100); // true
bool outOfRange = NumericRangeTools.IsInRange(150, 0, 100); // false
bool onBoundary = NumericRangeTools.IsInRange(100, 0, 100, false); // false (exclusive)
ClampToRange<T>(T value, T min, T max) where T : INumber
Clamps a value to stay within specified bounds.
int clamped = NumericRangeTools.ClampToRange(150, 0, 100); // 100
double clampedDouble = NumericRangeTools.ClampToRange(-5.0, 0.0, 10.0); // 0.0
Practical Examples
Animation and Graphics
public class AnimationHelper
{
public float[] GenerateEaseInOutCurve(int keyframes)
{
var linear = NumericRangeTools.GetRange(0.0f, 1.0f, keyframes);
return linear.Select(t => EaseInOut(t)).ToArray();
}
private float EaseInOut(float t)
{
return t < 0.5f
? 2 * t * t
: 1 - (float)Math.Pow(-2 * t + 2, 2) / 2;
}
public Color InterpolateColor(Color start, Color end, double t)
{
var r = (byte)NumericRangeTools.Lerp(start.R, end.R, t);
var g = (byte)NumericRangeTools.Lerp(start.G, end.G, t);
var b = (byte)NumericRangeTools.Lerp(start.B, end.B, t);
return Color.FromArgb(r, g, b);
}
}
Scientific Calculations
public class ScientificCalculator
{
public double[] GenerateSineWave(double frequency, double duration, int sampleRate)
{
var timePoints = NumericRangeTools.GetRange(0.0, duration, 1.0 / sampleRate);
return timePoints.Select(t => Math.Sin(2 * Math.PI * frequency * t)).ToArray();
}
public (double[] X, double[] Y) GenerateFunction(Func<double, double> func, double xMin, double xMax, int points)
{
var xValues = NumericRangeTools.GetRange(xMin, xMax, points).ToArray();
var yValues = xValues.Select(func).ToArray();
return (xValues, yValues);
}
public double IntegrateTrapezoidal(Func<double, double> func, double a, double b, int intervals)
{
var points = NumericRangeTools.GetRange(a, b, intervals + 1).ToArray();
var h = (b - a) / intervals;
var sum = func(a) + func(b);
for (int i = 1; i < intervals; i++)
{
sum += 2 * func(points[i]);
}
return (h / 2) * sum;
}
}
Data Visualization
public class ChartGenerator
{
public DataPoint[] GenerateAxisPoints(double min, double max, int tickCount)
{
var values = NumericRangeTools.GetRange(min, max, tickCount);
return values.Select((v, i) => new DataPoint { Value = v, Index = i }).ToArray();
}
public double[] NormalizeData(double[] data, double targetMin = 0.0, double targetMax = 1.0)
{
var (dataMin, dataMax) = (data.Min(), data.Max());
return data.Select(value =>
NumericRangeTools.MapRange(value, dataMin, dataMax, targetMin, targetMax)
).ToArray();
}
public Color[] GenerateHeatmapColors(double[] values)
{
var (min, max) = (values.Min(), values.Max());
return values.Select(value =>
{
var normalized = NumericRangeTools.InverseLerp(min, max, value);
return GetHeatmapColor(normalized);
}).ToArray();
}
private Color GetHeatmapColor(double intensity)
{
// Blue (cold) to Red (hot) gradient
if (intensity < 0.5)
{
var blue = (byte)NumericRangeTools.MapRange(intensity, 0.0, 0.5, 255.0, 0.0);
var green = (byte)NumericRangeTools.MapRange(intensity, 0.0, 0.5, 0.0, 255.0);
return Color.FromArgb(0, green, blue);
}
else
{
var red = (byte)NumericRangeTools.MapRange(intensity, 0.5, 1.0, 0.0, 255.0);
var green = (byte)NumericRangeTools.MapRange(intensity, 0.5, 1.0, 255.0, 0.0);
return Color.FromArgb(red, green, 0);
}
}
}
Statistical Analysis
public class StatisticsHelper
{
public double[] GenerateNormalDistribution(double mean, double stdDev, int samples)
{
var random = new Random();
var results = new double[samples];
for (int i = 0; i < samples; i++)
{
// Box-Muller transformation
var u1 = random.NextDouble();
var u2 = random.NextDouble();
var z = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2);
results[i] = mean + stdDev * z;
}
return results;
}
public int[] CreateHistogramBins(double[] data, int binCount)
{
var (min, max) = (data.Min(), data.Max());
var binEdges = NumericRangeTools.GetRange(min, max, binCount + 1).ToArray();
var bins = new int[binCount];
foreach (var value in data)
{
for (int i = 0; i < binCount; i++)
{
if (value >= binEdges[i] && value < binEdges[i + 1])
{
bins[i]++;
break;
}
}
}
return bins;
}
}
Performance Considerations
- Uses modern .NET generic constraints for compile-time safety
- Efficient range generation with minimal allocations
- Optimized interpolation algorithms
- Supports all numeric types implementing
INumber<T>
Thread Safety
- All static methods are thread-safe
- No shared state between operations
- Safe for concurrent usage across multiple threads
Best Practices
- Type Safety: Use appropriate numeric types for your precision requirements
- Range Validation: Validate input ranges before generating sequences
- Memory Management: Consider memory usage for large range generations
- Precision: Be aware of floating-point precision limitations
- Performance: Use appropriate step sizes and point counts for your use case