You can still make this function faster and gain another second if you don't use `IEnumerable` and an enumerator but for example a `List<int>`
public static List<int> Primes(int upperLimit)
{
var result = new List<int>();
if (upperLimit < 2)
{
throw new ArgumentException("Upper Limit be must greater than or equal to 2.");
}
result.Add(2);
if (upperLimit == 2)
{
return result;
}
// Check odd numbers for primality
const int offset = 3;
Func<int, int> toNumber = index => (2 * index) + offset;
Func<int, int> toIndex = number => (int)((number - offset) * 0.5);
var bits = new bool[toIndex(upperLimit) + 1];
var upperSqrtIndex = toIndex((int)Math.Sqrt(upperLimit));
for (var i = 0; i <= upperSqrtIndex; i++)
{
// If this bit has already been turned off, then its associated number is composite.
if (bits[i]) { continue;}
var number = toNumber(i);
// The instant we have a known prime, immediately yield its value.
result.Add(number);
// Any multiples of number are composite and their respective bits should be turned off.
for (var j = toIndex(number * number); (j > i) && (j < bits.Length); j += number)
{
bits[j] = true;
}
}
// Output remaining primes once bit array is fully resolved:
for (var i = upperSqrtIndex + 1; i < bits.Length; i++)
{
if (!bits[i])
{
result.Add(toNumber(i));
}
}
return result;
}
Here are two profiler screenshots:
[![Enumerator][1]][1]
[![List][2]][2]
[1]: https://i.sstatic.net/Me2xg.png
[2]: https://i.sstatic.net/g8dZH.png