I've got some code that I've worked on that is functional but I feel I'm doing it in a very obtuse way.
I have a fixed size array of 13 elements. The array is populated from a SQL table. If given a number, I'd like to know between which two array indexes the number belongs.
For example: If my number is 500 and I have the following elements:
-500, -400, -255, -89, 77, 243, 409, 575, 741, 907, 1073, 1500, 2000
...500 would be between elements 6 and 7. (409 and 575)
I've written a fairly brute force method for doing this using IF statements, code below. I basically create a second array and I use the IF statements to check the number against the first array. Note - I'm ignoring the case where the number is greater than the the max or min array numbers. I've searched for an array method that can search between indexes to no avail. Any ideas on how I can do this more efficiently? Thank you.
int[] deviations = new int[13] { -500, -400, -255, -89, 77, 243, 409, 575, 741, 907, 1073, 1500, 2000 };
int[] arrayCheck = new int[12];
Int64 num = 500;
Console.WriteLine("The number is: {0}", num);
if ((num >= deviations[0]) && (num < deviations[1]))
{arrayCheck[0] = 1;}
else { arrayCheck[0] = 0;}
if ((num >= deviations[1]) && (num < deviations[2]))
{arrayCheck[1] = 1;}
else { arrayCheck[1] = 0;}
if ((num >= deviations[2]) && (num < deviations[3]))
{ arrayCheck[2] = 1; }
else { arrayCheck[2] = 0; }
if ((num >= deviations[3]) && (num < deviations[4]))
{ arrayCheck[3] = 1; }
else { arrayCheck[3] = 0; }
if ((num >= deviations[4]) && (num < deviations[5]))
{ arrayCheck[4] = 1; }
else { arrayCheck[4] = 0; }
if ((num >= deviations[5]) && (num < deviations[6]))
{ arrayCheck[5] = 1; }
else { arrayCheck[5] = 0; }
if ((num >= deviations[6]) && (num < deviations[7]))
{ arrayCheck[6] = 1; }
else { arrayCheck[6] = 0; }
if ((num >= deviations[7]) && (num < deviations[8]))
{ arrayCheck[7] = 1; }
else { arrayCheck[7] = 0; }
if ((num >= deviations[8]) && (num < deviations[9]))
{ arrayCheck[8] = 1; }
else { arrayCheck[8] = 0; }
if ((num >= deviations[9]) && (num < deviations[10]))
{ arrayCheck[9] = 1; }
else { arrayCheck[9] = 0; }
if ((num >= deviations[10]) && (num < deviations[11]))
{ arrayCheck[10] = 1; }
else { arrayCheck[10] = 0; }
if ((num >= deviations[11]) && (num < deviations[12]))
{ arrayCheck[11] = 1; }
else { arrayCheck[11] = 0; }
int arrayIndex = Array.IndexOf(arrayCheck, 1);
Console.WriteLine("The num is between array indexes: {0} and {1}", arrayIndex, arrayIndex + 1);
If array is sorted, Array.BinarySearch is the way to go.
int[] deviations = new int[13] { -500, -400, -255, -89, 77, 243, 409, 575, 741, 907, 1073, 1500, 2000 };
var index = Array.BinarySearch(deviations,500);
if(index >= 0)
{
//Found at index
}
else
{
int expectedindex = ~index;
//Should fall in expectedindex
}
Array.BinarySearch returns the index of the specified value in the
specified array, if value is found. If value is not found and value is
less than one or more elements in array, a negative number which is
the bitwise complement of the index of the first element that is
larger than value. If value is not found and value is greater than any
of the elements in array, a negative number which is the bitwise
complement of (the index of the last element plus 1).
So when this method returns a negative value, that means given value is not found. but the bit-wise complement of the expected index of the element is returned. Bitwise complement works by changing the bits representation of 1 to 0 and 0 to 1, We make use of ~ operator to turn the bitwise complemented number back to original.
You could use the following two LINQ statements:
var previousIndex = deviations.Select((d, idx) => new { d, idx })
.Last(x => x.d <= num).idx;
var nextIndex = deviations.Select((d, idx) => new { d, idx })
.First(x => x.d >= num).idx;
You might want to use LastOrDefault() and FirstOrDefault() if you're worried about being below the smallest number or above the largest.
Assuming your array is already sorted, can't you just loop through the array?
(Not tested code)
var foundIndex = -1;
for ( var i = 0; i < deviations.GetUpperBound(0); i++ )
{
if ( num >= deviations[i] && num < deviations[i+1] )
{
foundIndex = i;
break;
}
}
Related
I wrote a method that does return sum of decreasing sequence.
For example:
if sequence is 13 9 7 12 13 15, then sum is 29 (13 + 9 + 7).
Now I want to optimize it. Cause the same code is repeating muliple times. But I don't now how. Maybe someone can help me?
int sumMax = 0;
for (int i = 0; i < array.Length; i++)
{
if (i == 0)
{
if (array[i] % 2 == 1)
{
sum += array[i];
if (sumMax < sum)
{
sumMax = sum;
}
}
}
else
{
if (array[i] % 2 == 0)
{
sum = 0;
}
else
{
if (sum != 0)
{
if (array[i - 1] > array[i])
{
sum += array[i];
if (sumMax < sum)
{
sumMax = sum;
}
}
}
else
{
sum += array[i];
if (sumMax < sum)
{
sumMax = sum;
}
}
}
}
}
return sumMax;
Seems like a fairly simple problem. Could simply loop over the array and keep track of the current count and current max value no?
var values = new int[] {13, 9 ,7 ,12 ,13, 15};
var max = Int32.MaxValue;
var total = 0;
foreach (int value in values){
if(value >= max)continue;
max = value;
total += value;
}
This loops over every element in the array so is O(n), might be some way to make this look nicer using LINQ?
I misread what he was asking, something like this would work instead would it not?
var values = new int[] {13, 9 ,7 ,12 ,13, 15};
int previous = int.MaxValue;
var total = 0;
var max = 0;
foreach(int value in values){
if(value >= previous){
if(total > max) max = total;
total = 0;
}
total += value;
previous = value;
}
if(total > max) max = total;
Console.WriteLine(max);
You can still probabbly make this look nicer with some LINQ, but performance wise its still O(n)
I have a
list<int> input = //from db of one million records
of 1 million records .
Although I know that using input.OrderByDescending().Skip(1).Take(1) will solve the problem but if I have 1 million records , it is not a best practice to use OrderBY.
In this scenario which solution is the best one when we have more records?
Scan the list while tracking the max, as well as max2 and you'll get O(N) versus O(N * log(N)) time complexity:
// Maximum value
int max = Math.Max(input[input.Count - 1], input[input.Count - 2]);
// Second greatest
int max2 = Math.Min(input[input.Count - 1], input[input.Count - 2]);
// i >= 0: Comparing with 0 is slightly faster then with Count
for (int i = input.Count - 3; i >= 0; --i) {
int v = input[i];
if (v >= max) {
max2 = max;
max = v;
}
else if (v > max2)
max2 = v;
}
Edit: In case duplicates should be ignored (see comments below) and thus the answer for [1, 2, 3, 4, 4, 4, 4] should be 3, not 4:
// Maximum value
int max = int.MinValue;
// Second greatest
int max2 = int.MinValue;
// i >= 0: Comparing with 0 is slightly faster then with Count
for (int i = input.Count - 1; i >= 0; --i) {
int v = input[i];
if (v > max) {
max2 = max;
max = v;
}
else if (v > max2 && v != max)
max2 = v;
}
If your list contains only distinct values, you can also do:
var max = input.Max();
input.Remove(max);
var result = input.Max();
You can do it by keeping track of the next max and iterating once through the list.
int max = Int32.MinValue;
int nextMax = Int32.MinValue;
for(int i=0; i<list.Count(); i++)
{
if(list[i] > max)
{
nextMax = max;
max = list[i];
}
else if(list[i] > nextMax)
{
nextMax = list[i];
}
}
This is a solution iterating just once and using LINQ and C# 7 tuples:
var input = Enumerable.Range(0, 101);
var topTwo = input.Aggregate((Biggest: Int32.MinValue, SecondBiggest: Int32.MinValue),
(acc, next) =>
{
if (next > acc.Biggest)
{
acc.SecondBiggest = acc.Biggest;
acc.Biggest = next;
}
if (next < acc.Biggest && next > acc.SecondBiggest)
acc.SecondBiggest = next;
return acc;
});
WriteLine(topTwo.SecondBiggest); // 99
I took a look at the following question from project euler:
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
What is the 10 001st prime number?
I tried to take the square root of the number and than find all the prime numbers below the square root of the number and then divide the number by all the square roots and see if there is 0 left each time. If the number is not divisible by all the primes under its square root its a prime number. I did this to lower the itterations the programm has to make. Here is what I have now, I am not sure why it isn't working. Anybody knows what i did wrong?
List<int> primeNumbers = new List<int>();
bool prime = true;
bool MainPrime = true;
int check = 1;
for (long i = 3; i < long.MaxValue; i++)
{
if ((i % 2) != 0)
{
int root = Convert.ToInt32(Math.Sqrt(i));
for (int j = 1; j < root; j++)
{
for (int k = 2; k < j; k++)
{
if ((j% k) == 0)
{
prime = false;
}
}
if (prime)
{
primeNumbers.Add(j);
}
prime = true;
}
}
foreach (var item in primeNumbers)
{
if ((i%item) == 0)
{
MainPrime = false;
}
}
primeNumbers.Clear();
if (MainPrime)
{
check++;
}
if (check == 10001)
{
Console.WriteLine(i);
break;
}
}
Console.ReadKey();
Several points:
When finding possible prime divisors, you need to check all numbers up to the square root included, so your condition j < root is incorrect.
You don't have to recalculate the primes again for every number. Keep the list as you go and add new primes to it.
As soon as you find a divisor, you can break out of the foreach loop.
Improved code:
List<long> primeNumbers = new List<long>() { 2 };
for (long i = 3; i < long.MaxValue; i += 2)
{
if(!primeNumbers.Any(p => (i % p) == 0))
{
primeNumbers.Add(i);
if (primeNumbers.Count == 10001)
{
Console.WriteLine(i);
break;
}
}
}
Gives 104743 as the 10001st prime.
What we can do is we can use SieveOfEratosthenes to make an bool array in which all the prime numbers value are set to be true than after that;
1.As we found any prime number increment the count with 1;
2.And as count get equal to 10001 we print its value and break through the loop.
Have a Look at code in C++ (I recommend you to learn SieveOfEratosthenes first)
#include <bits/stdc++.h>
using namespace std;
void SieveOfEratosthenes(long long unsigned n)
{
bool prime[n];
memset(prime, true, sizeof(prime)); //This is SieveOfEratosthenes
for (long long p = 2; p * p <= n; p++)
{
if (prime[p] == true)
{
for (long long i = p * p; i <= n; i += p)
prime[i] = false;
}
}
long long count=0; //initializing count as 0;
for (long long p = 2; p <= n; p++) //running the loop form 2 to n
{
if (prime[p]) //we have bool array in which all prime number set to true using sieve
count++; //increment the count because we found a prime number
if(count==10001) // and as count reaches to 10001 we found our number
{
cout<<p;break;} // print the answer and also break form the loop
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
long long unsigned n=999999;
SieveOfEratosthenes(n); //pass the value of n in sieve function
return 0;
}
Try this one out using python
sp=2
cnt = 1
while cnt <= 10001:
primeflag = 0
for j in range(2,sp):
if(sp%j == 0):
primeflag = 1
break;
if(primeflag == 1):
pass
else:
print(cnt ,sp)
cnt = cnt +1
sp =sp+1
#which Gives
#10001 104743
At first user gives a number (n) to program, for example 5.
the program must find the smallest number that can be divided to n (5).
and this number can only consist of digits 0 and 9 not any other digits.
for example if user gives 5 to program.
numbers that can be divided to 5 are:
5, 10, 15, 20, 25, 30, ..., 85, 90, 95, ...
but 90 here is the smallest number that can be divided to 5 and also consist of digits (0 , 9). so answer for 5 must be 90.
and answer for 9 is 9, because it can be divided to 9 and consist of digit (9).
my code
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
Int64 i ,j=1,y=x;
bool t = false;
for (i = x + 1; t == false; i++)
{
if (i % 9 == 0 && i % 10 == 0 && i % x == 0)
{
j = i;
for (; (i /= 10) != 0; )
{
i /= 10;
if (i == 0)
t = true;
continue;
}
}
}
lblAnswer.Text = Convert.ToString(j);
If you're happy to go purely functional then this works:
Func<IEnumerable<long>> generate = () =>
{
Func<long, IEnumerable<long>> extend =
x => new [] { x * 10, x * 10 + 9 };
Func<IEnumerable<long>, IEnumerable<long>> generate2 = null;
generate2 = ns =>
{
var clean = ns.Where(n => n > 0).ToArray();
return clean.Any()
? clean.Concat(generate2(clean.SelectMany(extend)))
: Enumerable.Empty<long>();
};
return generate2(new[] { 9L, });
};
Func<long, long?> f = n =>
generate()
.Where(x => x % n == 0L)
.Cast<long?>()
.FirstOrDefault();
So rather than iterate through all possible values and test for 0 & 9 and divisibility, this just generates only numbers with 0 & 9 and then only tests for visibility. It is much faster this way.
I can call it like this:
var result = f(5L); // 90L
result = f(23L); //990909L
result = f(123L); //99999L
result = f(12321L); //90900999009L
result = f(123212L); //99909990090000900L
result = f(117238L); //990990990099990990L
result = f(1172438L); //null == No answer
These results are super fast. f(117238L) returns a result on my computer in 138ms.
You can try this way :
string a = txtNumber.Text;
Int64 x = Convert.ToInt64(a);
int counter;
for (counter = 1; !isValid(x * counter); counter++)
{
}
lblAnswer.Text = Convert.ToString(counter*x);
code above works by searching multiple of x incrementally until result that satisfy criteria : "consist of only 0 and or 9 digits" found. By searching only multiple of x, it is guaranteed to be divisible by x. So the rest is checking validity of result candidate, in this case using following isValid() function :
private static bool isValid(int number)
{
var lastDigit = number%10;
//last digit is invalid, return false
if (lastDigit != 0 & lastDigit != 9) return false;
//last digit is valid, but there is other digit(s)
if(number/10 >= 1)
{
//check validity of digit(s) before the last
return isValid(number/10);
}
//last digit is valid, and there is no other digit. return true
return true;
}
About strange empty for loop in snippet above, it is just syntactic sugar, to make the code a bit shorter. It is equal to following while loop :
counter = 1;
while(!isValid(input*counter))
{
counter++;
}
Use this simple code
int inputNumber = 5/*Or every other number, you can get this number from input.*/;
int result=1;
for (int i = 1; !IsOk(result,inputNumber); i++)
{
result = i*inputNumber;
}
Print(result);
IsOk method is here:
bool IsOk(int result, int inputNumber)
{
if(result%inputNumber!=0)
return false;
if(result.ToString().Replace("9",string.Empty).Replace("0",string.Empty).Length!=0)
return false;
return true;
}
My first solution has very bad performance, because of converting a number to string and looking for characters '9' and '0'.
New solution:
My new solution has very good performance and is a technical approach since of using Breadth-first search(BFS).
Algorithm of this solution:
For every input number, test 9, if it is answer print it, else add 2 child numbers (90 & 99) to queue, and continue till finding answer.
int inputNumber = 5;/*Or every other number, you can get this number from input.*/
long result;
var q = new Queue<long>();
q.Enqueue(9);
while (true)
{
result = q.Dequeue();
if (result%inputNumber == 0)
{
Print(result);
break;
}
q.Enqueue(result*10);
q.Enqueue(result*10 + 9);
}
Trace of number creation:
9
90,99
900,909,990,999
9000,9009,9090,9099,9900,9909,9990,9999
.
.
.
I wrote this code for console, and i used goto command however it is not prefered but i could not write it with only for.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace main
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter your number");
Int64 x = Convert.ToInt64(Console.ReadLine());
Int64 y, j, i, k, z = x;
x = x + 5;
loop:
x++;
for (i = 0, y = x; y != 0; i++)
y /= 10;
for (j = x, k = i; k != 0; j /= 10, k--)
{
if (j % 10 != 9)
if (j % 10 != 0)
goto loop;
}
if (x % z != 0)
goto loop;
Console.WriteLine("answer:{0}",x);
Console.ReadKey();
}
}
}
I am trying to write a prime number function in C# and I am wondering if the follow code will work. It "appears" to work with the first 50 numbers or so. I just want to make sure it will work no matter how big the number is:
static bool IsPrime(int number)
{
if ((number == 2) || (number == 3) || (number == 5) || (number == 7) || (number == 9))
return true;
if ((number % 2 != 0) && (number % 3 != 0) && (number % 5 != 0) &&
(number % 7 != 0) && (number % 9 != 0) && (number % 4 != 0) &&
(number % 6 != 0))
return true;
return false;
}
No it won't work! Try 121 = 11 * 11 for example which obviously isn't a prime.
For any number given to your function, that is a product of the prime numbers X1, X2, ..., Xn(where n >= 2) with all of them being greater or equal to 11, your function will return true. (And also, as already said, 9 isn't a prime).
From wikipedia you can see that:
In mathematics, a prime number (or a prime) is a natural number that has exactly two distinct natural number divisors: 1 and itself.
so a very simple and naive algorithm on checking whether a number is prime could be:
public bool CalcIsPrime(int number) {
if (number == 1) return false;
if (number == 2) return true;
if (number % 2 == 0) return false; // Even number
for (int i = 2; i < number; i++) { // Advance from two to include correct calculation for '4'
if (number % i == 0) return false;
}
return true;
}
For better algorithms check here: Primality Test
If you want to check your code, do inlcude a test, here's a test case written in xunit.
[Theory]
[MemberData(nameof(PrimeNumberTestData))]
public void CalcIsPrimeTest(int number, bool expected) {
Assert.Equal(expected, CalcIsPrime(number));
}
public static IEnumerable<object[]> PrimeNumberTestData() {
yield return new object[] { 0, false };
yield return new object[] { 1, false };
yield return new object[] { 2, true };
yield return new object[] { 3, true };
yield return new object[] { 4, false };
yield return new object[] { 5, true };
yield return new object[] { 6, false };
yield return new object[] { 7, true };
yield return new object[] { 8, false };
yield return new object[] { 9, false };
yield return new object[] { 10, false };
yield return new object[] { 11, true };
yield return new object[] { 23, true };
yield return new object[] { 31, true };
yield return new object[] { 571, true };
yield return new object[] { 853, true };
yield return new object[] { 854, false };
yield return new object[] { 997, true };
yield return new object[] { 999, false };
}
It had to be done...
public static bool IsPrime(this int number)
{
return (Enumerable.Range(1,number).Where(x => number % x == 0).Count() == 2);
}
This approach definitely won't work, unless your if statement explicitly enumerates all the prime numbers between 0 and sqrt(INT_MAX) (or the C# equivalent).
To properly check for primality, you basically need to attempt to divide your number by every prime number less than its square root. The Sieve of Eratosthenes algorithm is your best bet.
You are apparently writing from a contrafactual dimension where 9 is a prime number, so I guess that our answers might not work for you. Two things though:
Prime number generating functions are a non-trivial but exiting matter, the Wikipedia page is a good starter (http://en.wikipedia.org/wiki/Formula_for_primes)
from (number%2!=0) it follows (number%4!=0). If you can't divide by 10, then you can't divide by 100 either.
Primality testing is the way to go, but in case you want a quick and dirty hack, here's something.
If it's not working fast enough, you can build a class around it and store the PrimeNumbers collection from call to call, rather than repopulating it for each call.
public bool IsPrime(int val)
{
Collection<int> PrimeNumbers = new Collection<int>();
int CheckNumber = 5;
bool divisible = true;
PrimeNumbers.Add(2);
PrimeNumbers.Add(3);
// Populating the Prime Number Collection
while (CheckNumber < val)
{
foreach (int i in PrimeNumbers)
{
if (CheckNumber % i == 0)
{
divisible = false;
break;
}
if (i * i > CheckNumber) { break; }
}
if (divisible == true) { PrimeNumbers.Add(CheckNumber); }
else { divisible = true; }
CheckNumber += 2;
}
foreach (int i in PrimeNumbers)
{
if (CheckNumber % i == 0)
{
divisible = false;
break;
}
if (i * i > CheckNumber) { break; }
}
if (divisible == true) { PrimeNumbers.Add(CheckNumber); }
else { divisible = true; }
// Use the Prime Number Collection to determine if val is prime
foreach (int i in PrimeNumbers)
{
if (val % i == 0) { return false; }
if (i * i > val) { return true; }
}
// Shouldn't ever get here, but needed to build properly.
return true;
}
There are some basic rules you can follow to check if a number is prime
Even numbers are out. If x % 2 = 0, then it is not prime
All non-prime numbers have prime factors. Therefore, you only need test a number against primes to see if it factors
The highest possible factor any number has is it's square root. You only need to check if values <= sqrt(number_to_check) are even divisible.
Using that set of logic, the following formula calculates 1,000,000 Primes Generated in: 134.4164416 secs in C# in a single thread.
public IEnumerable<long> GetPrimes(int numberPrimes)
{
List<long> primes = new List<long> { 1, 2, 3 };
long startTest = 3;
while (primes.Count() < numberPrimes)
{
startTest += 2;
bool prime = true;
for (int pos = 2; pos < primes.Count() && primes[pos] <= Math.Sqrt(startTest); pos++)
{
if (startTest % primes[pos] == 0)
{
prime = false;
}
}
if (prime)
primes.Add(startTest);
}
return primes;
}
Bear in mind, there is lots of room for optimization in the algorithm. For example, the algorithm could be parallelized. If you have a prime number (let's say 51), you can test all the numbers up to it's square (2601) for primeness in seperate threads as all it's possible prime factors are stored in the list.
static List<long> PrimeNumbers = new List<long>();
static void Main(string[] args)
{
PrimeNumbers.Add(2);
PrimeNumbers.Add(3);
PrimeNumbers.Add(5);
PrimeNumbers.Add(7);
for (long i = 11; i < 10000000; i += 2)
{
if (i % 5 != 0)
if (IsPrime(i))
PrimeNumbers.Add(i);
}
}
static bool IsPrime(long number)
{
foreach (long i in PrimeNumbers)
{
if (i <= Math.Sqrt(number))
{
if (number % i == 0)
return false;
}
else
break;
}
return true;
}
this is a simple one
only odd numbers are prime....so
static bool IsPrime(int number)
{
int i;
if(number==2)
return true; //if number is 2 then it will return prime
for(i=3,i<number/2;i=i+2) //i<number/2 since a number cannot be
{ //divided by more then its half
if(number%i==0) //if number is divisible by i, then its not a prime
return false;
}
return true; //the code will only reach here if control
} //is not returned false in the for loop
This is a simple code for find prime number depend on your input.
static void Main(string[] args)
{
String input = Console.ReadLine();
long num = Convert.ToInt32(input);
long a, b, c;
c = 2;
for(long i=3; i<=num; i++){
b = 0;
for (long j = 2; j < i ; j++) {
a = i % j;
if (a != 0) {
b = b+1;
}
else {
break;
}
}
if(b == i-2){
Console.WriteLine("{0}",i);
}
}
Console.ReadLine();
}
ExchangeCore Forums have a good bit of code that will pretty much let you generate any ulong number for primes. But basically here's the gist:
int primesToFind = 1000;
int[] primes = new int[primesToFind];
int primesFound = 1;
primes[0] = 2;
for(int i = 3; i < int.MaxValue() && primesFound < primesToFind; i++)
{
bool isPrime = true;
double sqrt = Math.sqrt(i);
for(int j = 0; j<primesFound && primes[j] <= sqrt; j++)
{
if(i%primes[j] == 0)
{
isPrime = false;
break;
}
}
if(isPrime)
primes[primesFound++] = i;
}
Once this code has finished running your primes will all be found in the primes array variable.
https://www.khanacademy.org/computing/computer-science/cryptography/comp-number-theory/a/trial-division
public static bool isPrime(int number)
{
for (int k = 2; k <= Math.Ceiling(Math.Sqrt(number)); k++)
{
if (number > k && number % k == 0)
break;
if (k >= Math.Ceiling(Math.Sqrt(number)) || number == k)
{
return true;
}
}
return false;
}
Prime Numbers from 0 - 1 Million in less than two tenths of a second
Just finished it. Last test was 0.017 seconds.
Regular HP Laptop. 2.1 GHz
It takes longer when it gets larger. For primes 1 - 1 billion , my last test was 28.6897 seconds. It might be faster in your program because I was casting class objects to get parameter values in mine.
Method Info
Uses the Sieve of Eratosthenes
Accepts floor and ceiling as arguments
Uses arrays instead of lists for fast performance
Size of array is initialized according to Rosser-Schoenfeld upper bound
Skips multiples of 2, 5, and 7 when assigning values
Max range is between 0 and 2,147,483,646 (1 min 44.499 s)
Heavily commented
Using
using System;
using System.Diagnostics;
using System.Collections;
Method
private static int[] GetPrimeArray(int floor, int ceiling)
{
// Validate arguments.
if (floor > int.MaxValue - 1)
throw new ArgumentException("Floor is too high. Max: 2,147,483,646");
else if (ceiling > int.MaxValue - 1)
throw new ArgumentException("Ceiling is too high. Max: 2,147,483,646");
else if (floor < 0)
throw new ArgumentException("Floor must be a positive integer.");
else if (ceiling < 0)
throw new ArgumentException("Ceiling must be a positve integer.");
else if (ceiling < floor)
throw new ArgumentException("Ceiling cannot be less than floor.");
// This region is only useful when testing performance.
#region Performance
Stopwatch sw = new Stopwatch();
sw.Start();
#endregion
// Variables:
int stoppingPoint = (int)Math.Sqrt(ceiling);
double rosserBound = (1.25506 * (ceiling + 1)) / Math.Log(ceiling + 1, Math.E);
int[] primeArray = new int[(int)rosserBound];
int primeIndex = 0;
int bitIndex = 4;
int innerIndex = 3;
// Handle single digit prime ranges.
if (ceiling < 11)
{
if (floor <= 2 && ceiling >= 2) // Range includes 2.
primeArray[primeIndex++] = 2;
if (floor <= 3 && ceiling >= 3) // Range includes 3.
primeArray[primeIndex++] = 3;
if (floor <= 5 && ceiling >= 5) // Range includes 5.
primeArray[primeIndex++] = 5;
return primeArray;
}
// Begin Sieve of Eratosthenes. All values initialized as true.
BitArray primeBits = new BitArray(ceiling + 1, true);
primeBits.Set(0, false); // Zero is not prime.
primeBits.Set(1, false); // One is not prime.
checked // Check overflow.
{
try
{
// Set even numbers, excluding 2, to false.
for (bitIndex = 4; bitIndex < ceiling; bitIndex += 2)
primeBits[bitIndex] = false;
}
catch { } // Break for() if overflow occurs.
}
// Iterate by steps of two in order to skip even values.
for (bitIndex = 3; bitIndex <= stoppingPoint; bitIndex += 2)
{
if (primeBits[bitIndex] == true) // Is prime.
{
// First position to unset is always the squared value.
innerIndex = bitIndex * bitIndex;
primeBits[innerIndex] = false;
checked // Check overflow.
{
try
{
// Set multiples of i, which are odd, to false.
innerIndex += bitIndex + bitIndex;
while (innerIndex <= ceiling)
{
primeBits[innerIndex] = false;
innerIndex += bitIndex + bitIndex;
}
}
catch { continue; } // Break while() if overflow occurs.
}
}
}
// Set initial array values.
if (floor <= 2)
{
// Range includes 2 - 5.
primeArray[primeIndex++] = 2;
primeArray[primeIndex++] = 3;
primeArray[primeIndex++] = 5;
}
else if (floor <= 3)
{
// Range includes 3 - 5.
primeArray[primeIndex++] = 3;
primeArray[primeIndex++] = 5;
}
else if (floor <= 5)
{
// Range includes 5.
primeArray[primeIndex++] = 5;
}
// Increment values that skip multiples of 2, 3, and 5.
int[] increment = { 6, 4, 2, 4, 2, 4, 6, 2 };
int indexModulus = -1;
int moduloSkipAmount = (int)Math.Floor((double)(floor / 30));
// Set bit index to increment range which includes the floor.
bitIndex = moduloSkipAmount * 30 + 1;
// Increase bit and increment indicies until the floor is reached.
for (int i = 0; i < increment.Length; i++)
{
if (bitIndex >= floor)
break; // Floor reached.
// Increment, skipping multiples of 2, 3, and 5.
bitIndex += increment[++indexModulus];
}
// Initialize values of return array.
while (bitIndex <= ceiling)
{
// Add bit index to prime array, if true.
if (primeBits[bitIndex])
primeArray[primeIndex++] = bitIndex;
checked // Check overflow.
{
try
{
// Increment. Skip multiples of 2, 3, and 5.
indexModulus = ++indexModulus % 8;
bitIndex += increment[indexModulus];
}
catch { break; } // Break if overflow occurs.
}
}
// Resize array. Rosser-Schoenfeld upper bound of π(x) is not an equality.
Array.Resize(ref primeArray, primeIndex);
// This region is only useful when testing performance.
#region Performance
sw.Stop();
if (primeArray.Length == 0)
Console.WriteLine("There are no prime numbers between {0} and {1}",
floor, ceiling);
else
{
Console.WriteLine(Environment.NewLine);
for (int i = 0; i < primeArray.Length; i++)
Console.WriteLine("{0,10}:\t\t{1,15:#,###,###,###}", i + 1, primeArray[i]);
}
Console.WriteLine();
Console.WriteLine("Calculation time:\t{0}", sw.Elapsed.ToString());
#endregion
return primeArray;
}
Comments are welcome! Especially improvements.
Here we must have to consider the square root factor. A prime number can be verified if it is not divisible by any number less than the value of square root of any near number.
static bool isPrime(long number)
{
if (number == 1) return false;
if (number == 2) return true;
if (number % 2 == 0) return false; //Even number
long nn= (long) Math.Abs(Math.Sqrt(number));
for (long i = 3; i < nn; i += 2) {
if (number % i == 0) return false;
}
return true;
}