Related
I can't figure out why I keep getting the "Index was outside the
bounds of the array" error. I am trying to tally up the salaries to
display.
Is there are any someone who could explain to me how the error message works.
namespace sales_commission {
class Program {
static void Main (string[] args) {
const int ARRAY_LENGTH = 8;
int[] salaries = { 210, 400, 450, 950, 800, 330, 430, 233, 223, 590, 679, 1000 };
var salary = new int[ARRAY_LENGTH];
foreach(int number in salaries) {
try {
if (number >= 200 && number <= 299) {
salary[0]++;
} else if (number >= 300 && number <= 399) {
salary[1]++;
} else if (number >= 400 && number <= 499) {
salary[2]++;
} else if (number >= 500 && number <= 599) {
salary[3]++;
} else if (number >= 600 && number <= 699) {
salary[4]++;
} else if (number >= 700 && number <= 799) {
salary[5]++;
} else if (number >= 800 && number <= 899) {
salary[6]++;
} else if (number >= 900 && number <= 999) {
salary[7]++;
} else if (number >= 1000) {
salary[8]++;
}
} catch (IndexOutOfRangeException ex) {
Console.WriteLine (ex.Message);
Console.WriteLine ($"salaries[{number}] = {salary[number]}");
}
}
for (var result = 0; result <= salary.Length; ++result) {
Console.WriteLine ($"{result* 100 + 200} - {result * 100 + 200 + 99} {salary[result],15}");
}
}
}
}
You have 9 salary brackets. 200-299, 300-399, 400-499, 500-599, 600-699, 700-799, 800-899, 900-999 and >= 1000. That means you need 9 storage spaces for the counts. Array indexes start at 0, so your array length needs to be 9, this gives you [0 to 8] indexes.
const int ARRAY_LENGTH = 8; // This needs to be 9.
You get an array out of bounds because:
} else if (number >= 1000) {
salary[8]++; // Index 8 doesn't exist, only [0 to 7] for an ARRAY_LENGTH of 8.
Your loop also accesses data outside of the array bounds. This is because the condition of your loop runs until it reaches and includes the index of the length itself. So if your array has 8 spaces [0 to 7], your loop runs from [0 to 8] and the moment it access index 8, you're out of bounds. This can easily be fixed as below:-
for (var result = 0; result <= salary.Length; ++result) { // Change this to result < salary.Length
Console.WriteLine ($"{result* 100 + 200} - {result * 100 + 200 + 99 {salary[result],15}");
}
I'm trying to decode bitcoin address from Base58 string into byte array, and to do that I rewrited original function from Satoshi repository (https://github.com/bitcoin/bitcoin/blob/master/src/base58.cpp), written in c++, to c# (which I'm using).
Original code
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool DecodeBase58(const char *psz, std::vector<unsigned char>& vch) {
// Skip leading spaces.
while (*psz && isspace(*psz))
psz++;
// Skip and count leading '1's.
int zeroes = 0;
while (*psz == '1') {
zeroes++;
psz++;
}
// Allocate enough space in big-endian base256 representation.
std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
// Process the characters.
while (*psz && !isspace(*psz)) {
// Decode base58 character
const char *ch = strchr(pszBase58, *psz);
if (ch == NULL)
return false;
// Apply "b256 = b256 * 58 + ch".
int carry = ch - pszBase58;
for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
carry += 58 * (*it);
*it = carry % 256;
carry /= 256;
}
assert(carry == 0);
psz++;
}
// Skip trailing spaces.
while (isspace(*psz))
psz++;
if (*psz != 0)
return false;
// Skip leading zeroes in b256.
std::vector<unsigned char>::iterator it = b256.begin();
while (it != b256.end() && *it == 0)
it++;
// Copy result into output vector.
vch.reserve(zeroes + (b256.end() - it));
vch.assign(zeroes, 0x00);
while (it != b256.end())
vch.push_back(*(it++));
return true;
}
Mine rewrited c# version
private static string Base58characters = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static bool Decode(string source, ref byte[] destination)
{
int i = 0;
while (i < source.Length)
{
if (source[i] == 0 || !Char.IsWhiteSpace(source[i]))
{
break;
}
i++;
}
int zeros = 0;
while (source[i] == '1')
{
zeros++;
i++;
}
byte[] b256 = new byte[(source.Length - i) * 733 / 1000 + 1];
while (i < source.Length && !Char.IsWhiteSpace(source[i]))
{
int ch = Base58characters.IndexOf(source[i]);
if (ch == -1) //null
{
return false;
}
int carry = Base58characters.IndexOf(source[i]);
for (int k = b256.Length - 1; k > 0; k--)
{
carry += 58 * b256[k];
b256[k] = (byte)(carry % 256);
carry /= 256;
}
i++;
}
while (i < source.Length && Char.IsWhiteSpace(source[i]))
{
i++;
}
if (i != source.Length)
{
return false;
}
int j = 0;
while (j < b256.Length && b256[j] == 0)
{
j++;
}
destination = new byte[zeros + (b256.Length - j)];
for (int kk = 0; kk < destination.Length; kk++)
{
if (kk < zeros)
{
destination[kk] = 0x00;
}
else
{
destination[kk] = b256[j++];
}
}
return true;
}
Function that I'm using for converting from byte-array to HexString
public static string ByteArrayToHexString(byte[] source)
{
return BitConverter.ToString(source).Replace("-", "");
}
To test if everything is working correctly I've used test cases found online here (https://github.com/ThePiachu/Bitcoin-Unit-Tests/blob/master/Address/Address%20Generation%20Test%201.txt). Good thing is that 97% of this test are passed correctly but for 3 there is a little error and I do not know where it is coming from. So my ask to you is to point me what could for these test go wrong or where in rewriting I've made an error. Thank you in advance.
The test cases where errors occures are 1, 21 and 25.
1.
Input:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
Output:
000966776006953D5567439E5E39F86A0D273BEED61967F6
Should be:
00010966776006953D5567439E5E39F86A0D273BEED61967F6
21.
Input:
1v3VUYGogXD7S1E8kipahj7QXgC568dz1
Output:
0008201462985DF5255E4A6C9D493C932FAC98EF791E2F22
Should be:
000A08201462985DF5255E4A6C9D493C932FAC98EF791E2F22
25.
Input:
1axVFjCkMWDFCHjQHf99AsszXTuzxLxxg
Output:
006C0B8995C7464E89F6760900EA6978DF18157388421561
Should be:
00066C0B8995C7464E89F6760900EA6978DF18157388421561
In your for-loop:
for (int k = b256.Length - 1; k > 0; k--)
The loop condition should be k >= 0 so that you don't skip the first byte in b256.
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;
}
}
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;
}