Selecting a number from natural number < n excluding a possibility - c#

Given n natural number starts from 0, and b which is a number in between 0 to n
I wish to randomly select a number excluding b.
Say n is 5
then The number to be selected is {0,1,2,3,4,5}
say b is 4,
then my random selection is from {0,1,2,3,5}
A way to do this is to do a while loop, until the random.nextInteger() does not find a 4.
Is there a easy to to do this other than using a while loop?

I would write a simple extension:
// N.B. : min is inclusive, max is exclusive; so range is: [min,max) - {toExclude}
public static int Next(this Random rand, int min, int max, int toExclude)
{
int v = rand.Next(min, max - 1);
if (v < toExclude)
return v;
return v + 1;
}
Usage:
var random = new Random();
var val = random.Next(0,6,4); // 6 because max is exclusive in C# random.Next()

Your approach is the best in my optinion. It is simple and elegant, and even for m=2 it is O(1) on average (The expected number of redraws is 1/2 + 1/4 + 1/8 + .... < 1).
If you want to avoid the worst case of infinite loop there is an alternative, though I doubt it will have real performance impact.
draw a random double in range [0,1]. let it be d. If d < b/m: draw a number in range [0,b) and return it.
Else (d > b/m) - draw a random number in range [b+1,m] and return it.
Note, it is indeed uniform distributed because:
There are m+1 numbers in range 0,...,m, but only m "valid" numbers (excluding b).
There are b numbers in range 0,1,...,b-1 - so the probability of the number being in this range assuming uniform distribution is b/m - which is exactly P(d < b/m).
In java it will look similar to this:
int m = 5, b = 4;
Random r = new Random();
double d = r.nextDouble();
if (d < ((double)b)/m) {
System.out.println(r.nextInt(b));
} else {
System.out.println(r.nextInt(m-b) + b + 1);
}

Here is another approach if you prefer:
import random
def random_unifrom(n,b):
assert b < n and n > 0 and b > 0
nMinusOneList = [i for i in range(n) if i != b]
lSize = len(nMinusOneList)
randIndex = random.randint(0, lSize-1)
return nMinusOneList[randIndex]
I wrote this in python just for simplicity.
creating the nMinusOneList has complexity of O(n).
returning the random index complexity depends on the random function you are using.
At the end, you loose nothing if you take this approach instead of a while loop, but even if you use the while loop approach, if the random function is random (!!) then you should not have a problem. However, my approach above excludes the number you do not need from the very beginning.
In C#, the one line I use in python might be a couple of lines which consists of a for loop on the range 0 to n, with a condition that the x (for loop index) does not equal to b, in building the list, and then you will have the list that excludes b.

Related

mistakes in prime number checker c#

i've write this piece of code to check if a number is prime or not, but it doesen't work, I mean that the output is:
1 isn't a prime number
2 is a prime number
3 isn't a prime number
4 is a prime number etc.
please can you tell me what are my mistakes,
thanks
p.s. i've writenumber =1 because i can't divide a number for 0.
for( int number =1;number <101 && number >0;number++)
{
int reimander = (number / 1) & (number / number);
Console.WriteLine(number +(reimander == 0 ? " is a prime number" : " isn't a prime number"));
}
As mentioned Daisy Shipton, your checkings are not sufficient to determine if your number is prime.
In order for a number to be prime, it has to be only divisible by one or itself.
That mean you should check the division by every single numbers between 3 and the number which you are checking the fact of behing prime.
In reality, you don't need to check every numbers between 3 and your number but only the ones between 3 and the square of your number.
In fact, if a whole number k is composite (non prime), it can be written as the product of two whole numbers p and q : k = p*q
Howevern those two numbers p and q can't be simultaneously greater than the square (s) of k, because in this case, their product whould be greater than k.
if p > s and q > s, then p x q > s x s, that to say p x q > k.
The code should looks like something like that (not tested) :
public static bool IsPrime(int number)
{
/****** easy check before going to long calculations *******/
if (number < 2) return false; // A prime number is always greater than 1
if (number == 2) return true; // 2 is prime
if (number % 2 == 0) return false; // Even numbers except 2 are not prime
/****** if your number is Odd and not equals to 2,
you have to check every numbers between 3
and the square of your number *******/
var boundary = (int)Math.Floor(Math.Sqrt(number)); // square of your number
// increment i by 2 because you already checked that your number is Odd
// and therefore not divisible by an Even number
for (int i = 3; i <= boundary; i += 2)
{
if (number % i == 0) return false; // the number can be devided by an other => COMPOSITE number
}
return true; // number at least equals to 3, divisible only by one or itself => PRIME number
}
Now you could do a basic loop for each numbers you want to test and call this function of them. Their is a lot of methods to calculate a series of prime numbers but their are also much more complicated to understand.
for (int number = 1; number < 101 && number > 0; number++)
{
Console.WriteLine(number + " is " + (IsPrime(number) ? "prime" : "not prime"));
}
There are two sorts of problem here: the is-prime algorithm and the C# syntax.
To understand the algorithm for whether a number is prime, search math sites online. For example, here.
Once you know how the math works, you can convert it into code. Based on the code you already have, you should learn the difference between & and && and how to get a remainder.

Random number issue with Next method (.NET Framework)

I need to generate a lot of random numbers which must be anywhere between 1 and int.MaxValue. The arguments passed to the Next method of the Random class are not always the same. In one senario the arguments might be as follows:
Next(1, int.MaxValue);
In another they might as well be:
Next(1, 2);
The issue here is that whenever you pass values like 1 and 2 or 99 and 100, the lower number is always the "random" number returned by the method. The reason for this is because the method subtracts 1 from the maximum value (unless min and max are the same) and then gives you the random number. How would I go about generating a range of random numbers within a range of numbers, as stated above, without getting this predictable outcome?
You would need to pass the inclusive upper bound + 1, ie:
var result = rand.Next(1, 2+1); // Returns 1 or 2
var result2 = rand.Next(99, 101); // Returns 99 or 100
Note that this won't work for int.MaxValue, of course. There is no way to have Random directly return int.MaxValue. To get a [0,int.MaxValue] result, you would need to do:
var result = rand.Next(-1, int.MaxValue) + 1;
The upper bound is exclusive, not inclusive. Given that, the range [1,2) only contains one number, 1, not two.
From the documentation, the first parameter to Next(int, int) is "The inclusive lower bound", while the second is "The exclusive upper bound".
If you want to generate a random number that might be 1 or 2, you should use the following call:
rand.Next(1, 3)
Try this
using System;
namespace ConsoleApplication3
{
class Program
{
static readonly Random r = new Random();
static void Main(string[] args)
{
for (int i = 2; i <= 100; i++)
{
Console.WriteLine(GetRandom(i));
}
}
private static int GetRandom(int i)
{
return 1 + (r.Next(int.MaxValue)%i);
}
}
}
Cheers.
You can get int.MaxValue by adding 1 after getting random int:
var result = rand.Next(1, int.MaxValue) + 1;
How about a method that takes the lower and upper limits and gives you what you're looking for?
Example:
public int GetRandom(int lower, int upper)
{
return upper == int.MaxValue ? rand.Next(lower - 1, upper) + 1 : rand.Next(lower, upper + 1);
}
If the upper limit is int.MaxValue, it shifts the range down by 1 and then adds it back after it gives the random number. Otherwise, it adds 1 to the upper limit and then gives you the random number.
Then when you use it, you'll just do something like:
var randomOne = GetRandom(1, 2);
var randomTwo = GetRandom(99,int.MaxValue);

Split an integer

I have been searching around the internet for a while but haven't found what I am looking for.
Let me start with some code example:
int a = 25;
int b;
int c;
What I want to do here is I want to split the a variable and give the two values to variable b and c. The result would be int b = 2 and int c = 5, or vice versa (doesn't matter in the purpose I'm going to use this).
How can you do this?
You can use integer division and modulo for that:
int b = a / 10;
int c = a % 10;
If the variable a contains a larger number, you would first determine how many digits you want in each variable. If you for example want two digits in c, you would use 100 as the second operand in both operations.
One way you could do it is with the following code:
int input = 123845;
var digits = input.ToString().Select(x=>int.Parse(x.ToString()));
This will first of all convert your input number to a string. It then treats this string as a character array when passing to Select. It then converts the char to a string and then parses it as an int, resulting in an IEnumerable<int>.
Of note is that this won't work if your input is a negative number (it will complain about the -). It wouldn't be too hard to check for the "-" at the beginning if you wanted to though.
The other way is to continually divide by 10 getting all the digits out one by one.
public IEnumerable<int> GetDigits(int input)
{
int currentNumber = input;
List<int> digits = new List<int>();
while (currentNumber !=0)
{
digits.Add(currentNumber%10);
currentNumber = currentNumber/10;
}
digits.Reverse();
return digits;
}
This will loop through the number adding the last digit to a list as it goes. It then returns the list reversed. This does deal with negative numbers and if the input is negative all output numbers iwll be negative.
An important note is that both of these methods will deal with more than two digits input numbers.
int a = 12345;
a = Math.Abs(a);
int length = a.ToString().Length;
int[] array = new int[length];
for (int i = 0; i < length; i++)
{
array[i] = a % 10;
a /= 10;
}

How to know the repeating decimal in a fraction?

I already know when a fraction is repeating decimals. Here is the function.
public bool IsRepeatingDecimal
{
get
{
if (Numerator % Denominator == 0)
return false;
var primes = MathAlgorithms.Primes(Denominator);
foreach (int n in primes)
{
if (n != 2 && n != 5)
return true;
}
return false;
}
}
Now, I'm trying to get the repeated number. I'm checking this web site: http://en.wikipedia.org/wiki/Repeating_decimal
public decimal RepeatingDecimal()
{
if (!IsRepeatingDecimal) throw new InvalidOperationException("The fraction is not producing repeating decimals");
int digitsToTake;
switch (Denominator)
{
case 3:
case 9: digitsToTake = 1; break;
case 11: digitsToTake = 2; break;
case 13: digitsToTake = 6; break;
default: digitsToTake = Denominator - 1; break;
}
return MathExtensions.TruncateAt((decimal)Numerator / Denominator, digitsToTake);
}
But I really realized, that some numbers has a partial decimal finite and later infinite. For example: 1/28
Do you know a better way to do this? Or an Algorithm?
A very simple algorithm is this: implement long division. Record every intermediate division you do. As soon as you see a division identical to the one you've done before, you have what's being repeated.
Example: 7/13.
1. 13 goes into 7 0 times with remainder 7; bring down a 0.
2. 13 goes into 70 5 times with remainder 5; bring down a 0.
3. 13 goes into 50 3 times with remainder 11; bring down a 0.
4. 13 goes into 110 8 times with remainder 6; bring down a 0.
5. 13 goes into 60 4 times with remainder 8; bring down a 0.
6. 13 goes into 80 6 times with remainder 2; bring down a 0.
7. 13 goes into 20 1 time with remainder 7; bring down a 0.
8. We have already seen 13/70 on line 2; so lines 2-7 have the repeating part
The algorithm gives us 538461 as the repeating part. My calculator says 7/13 is 0.538461538. Looks right to me! All that remains are implementation details, or to find a better algorithm!
If you have a (positive) reduced fraction numerator / denominator, the decimal expansion of the fraction terminates if and only if denominator has no prime factor other than 2 or 5. If it has any other prime factor, the decimal expansion will be periodic. However, the cases where the denominator is divisible by at least one of 2 and 5 and where it isn't give rise to slightly different behaviour. We have three cases:
denominator = 2^a * 5^b, then the decimal expansion terminates max {a, b} digits after the decimal point.
denominator = 2^a * 5^b * m where m > 1 is not divisible by 2 or by 5, then the fractional part of the decimal expansions consists of two parts, the pre-period of length max {a, b} and the period, whose length is determined by m and independent of the numerator.
denominator > 1 is not divisible by 2 or by 5, then the decimal expansion is purely periodic, meaning the period starts immediately after the decimal point.
The treatment of cases 1. and 2. has a common part, let c = max {a, b}, then
numerator / denominator = (numerator * 2^(c-a) * 5^(c-b)) / (10^c * m)
where m = 1 for case 1. Note that one of the factors 2^(c-a) and 5^(c-b) with which we multiply the numerator is 1. Then you get the decimal expansion by expanding
(numerator * 2^(c-a) * 5^(c-b)) / m
and shifting the decimal point c places to the left. In the first case (m = 1) that part is trivial.
The treatment of cases 2. and 3. also has a common part, the calculation of a fraction
n / m
where n and m have no common prime factor (and m > 1). We can write n = q*m + r with 0 <= r < m (division with remainder, r = n % m), q is the integral part of the fraction and rather uninteresting.
Since the fraction was assumed reduced, we have r > 0, so we want to find the expansion of a fraction r / m where 0 < r < m and m is not divisible by 2 or by 5. As mentioned above, such an expansion is purely periodic, so finding the period means finding the complete expansion.
Let's go about finding the period heuristically. So let k be the length of the (shortest) period and p = d_1d1_2...d_k the period. So
r / m = 0.d_1d_2...d_kd_1d_2...d_kd_1...
= (d_1d_2...d_k)/(10^k) + (d_1d_2...d_k)/(10^(2k)) + (d_1d_2...d_k)/(10^(3k)) + ...
= p/(10^k) * (1 + 1/(10^k) + 1/(10^(2k)) + 1/(10^(3k)) + ...)
The last term is a geometric series, 1 + q + q^2 + q^3 + ... which, for |q| < 1 has the sum 1/(1-q).
In our case, 0 < q = 1/(10^k) < 1, so the sum is 1 / (1 - 1/(10^k)) = 10^k / (10^k-1). Thus we have seen that
r / m = p / (10^k-1)
Since r and m have no common factor, that means there is an s with 10^k - 1 = s*m and p = s*r. If we know k, the length of the period, we can simply find the digits of the period by calculating
p = ((10^k - 1)/m) * r
and padding with leading zeros until we have k digits. (Note: it is that simple only if k is sufficiently small or a big integer type is available. To calculate the period of for example 17/983 with standard fixed-width integer types, use long division as explained by #Patrick87.)
So it remains to find the length of the period. We can revert the reasoning above and find that if m divides 10^u - 1, then we can write
r / m = t/(10^u - 1) = t/(10^u) + t/(10^(2u)) + t/(10^(3u)) + ...
= 0.t_1t_2...t_ut_1t_2...t_ut_1...
and r/m has a period of length u. So the length of the shortest period is the minimal positive u such that m divides 10^u - 1, or, put another way, the smallest positive u such that 10^u % m == 1.
We can find it in O(m) time with
u = 0;
a = 1;
do {
++u;
a = (10*a) % m;
while(a != 1);
Now, finding the length of the period that way is not more efficient than finding the digits and length of the period together with long division, and for small enough m that is the most efficient method.
int[] long_division(int numerator, int denominator) {
if (numerator < 1 || numerator >= denominator) throw new IllegalArgumentException("Bad call");
// now we know 0 < numerator < denominator
if (denominator % 2 == 0 || denominator % 5 == 0) throw new IllegalArgumentException("Bad denominator");
// now we know we get a purely periodic expansion
int[] digits = new int[denominator];
int k = 0, n = numerator;
do {
n *= 10;
digits[k++] = n / denominator;
n = n % denominator;
}while(n != numerator);
int[] period = new int[k];
for(n = 0; n < k; ++n) {
period[n] = digits[n];
}
return period;
}
That works as long as 10*(denominator - 1) doesn't overflow, of course int could be a 32-bit or 64-bit integer as needed.
But for large denominators, that is inefficient, one can find the period length and also the period faster by considering the prime factorisation of the denominator. Regarding the period length,
If the denominator is a prime power, m = p^k, the period length of r/m is a divisor of (p-1) * p^(k-1)
If a and b are coprime and m = a * b, the period length of r/m is the least common multiple of the period lengths of 1/a and 1/b.
Taken together, the period length of r/m is a divisor of λ(m), where λ is the Carmichael function.
So to find the period length of r/m, find the prime factorisation of m and for all prime power factors p^k, find the period of 1/(p^k) - equivalently, the multiplicative order of 10 modulo p^k, which is known to be a divisor of (p-1) * p^(k-1). Since such numbers haven't many divisors, that is quickly done.
Then find the least common multiple of all these.
For the period itself (the digits), if a big integer type is available and the period isn't too long, the formula
p = (10^k - 1)/m * r
is a quick way to compute it. If the period is too long or no big integer type is available, efficiently computing the digits is messier, and off the top of my head I don't remember how exactly that is done.
One way would be to repeat the way that you do long division by hand, and keep note of the remainder at each stage. When the remainder repeats, the rest of the process must repeat as well. E.g. the digits of 1.0/7 are 0.1 remainder 3 then 0.14 remainder 2 then 0.142 remainder 6 then 0.1428 remainder 4 then 0.14285 remainder 5 then 0.142857 remainder 1 which is the 1 that starts it off again amd so you get 0.1428571 remainder 3 and it repeats again from there.
The long division algorithm is pretty good, so I have nothing to add there.
But note that your algorithm IsRepeatingDecimal may not work and is inneficient.
It will not work if your fraction is not irreductible, that is if there exists an integer larger than 1 that divides both your numerator and your denominator. For example, if you feed 7/14 then your algorithm will return true when it should return false.
To reduce your fraction, find the gcd between both numerator and denominator and divide both by this gcd.
If you assume that the fraction is irreducible, then your test
if (Numerator % Denominator == 0)
can simply be replaced with
if (Denominator == 1)
But that is still unnecessary since if Denominator is 1, then your list 'primes' is going to be empty and your algorithm will return false anyway.
Finally, calling MathAlgorithms.Primes(Denominator) is going to be expensive for large numbers and can be avoided. Indeed, all you need to do is divide your denominator by 5 (respectively 2) untill it is no longer divisible by 5 (resp. 2). If the end result is 1, then return false, otherwise return true.
I came here expecting to be able to copy & paste the code to do this, but it didn't exist. So after reading #Patrick87's answer, I went ahead and coded it up. I spent some time testing it thoroughly and giving things a nice name. I thought I would leave it here so others don't have to waste their time.
Features:
If the decimal terminates, it handles that. It calculates the period and puts that in a separate variable called period, in case you want to know the length of the reptend.
Limitations:
It will fail if the transient + reptend is longer than can be represented by a System.Decimal.
public static string FormatDecimalExpansion(RationalNumber value)
{
RationalNumber currentValue = value;
string decimalString = value.ToDecimal().ToString();
int currentIndex = decimalString.IndexOf('.');
Dictionary<RationalNumber, int> dict = new Dictionary<RationalNumber, int>();
while (!dict.ContainsKey(currentValue))
{
dict.Add(currentValue, currentIndex);
int rem = currentValue.Numerator % currentValue.Denominator;
int carry = rem * 10;
if (rem == 0) // Terminating decimal
{
return decimalString;
}
currentValue = new RationalNumber(carry, currentValue.Denominator);
currentIndex++;
}
int startIndex = dict[currentValue];
int endIndex = currentIndex;
int period = (endIndex - startIndex); // The period is the length of the reptend
if (endIndex >= decimalString.Length)
{
throw new ArgumentOutOfRangeException(nameof(value),
"The value supplied has a decimal expansion that is longer" +
$" than can be represented by value of type {nameof(System.Decimal)}.");
}
string transient = decimalString.Substring(0, startIndex);
string reptend = decimalString.Substring(startIndex, period);
return transient + $"({reptend})";
}
And for good measure, I will include my RationalNumber class.
Note: It inherits from IEquatable so that it works correctly with the dictionary:
public struct RationalNumber : IEquatable<RationalNumber>
{
public int Numerator;
public int Denominator;
public RationalNumber(int numerator, int denominator)
{
Numerator = numerator;
Denominator = denominator;
}
public decimal ToDecimal()
{
return Decimal.Divide(Numerator, Denominator);
}
public bool Equals(RationalNumber other)
{
return (Numerator == other.Numerator && Denominator == other.Denominator);
}
public override int GetHashCode()
{
return new Tuple<int, int>(Numerator, Denominator).GetHashCode();
}
public override string ToString()
{
return $"{Numerator}/{Denominator}";
}
}
Enjoy!

Average function without overflow exception

.NET Framework 3.5.
I'm trying to calculate the average of some pretty large numbers.
For instance:
using System;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var items = new long[]
{
long.MaxValue - 100,
long.MaxValue - 200,
long.MaxValue - 300
};
try
{
var avg = items.Average();
Console.WriteLine(avg);
}
catch (OverflowException ex)
{
Console.WriteLine("can't calculate that!");
}
Console.ReadLine();
}
}
Obviously, the mathematical result is 9223372036854775607 (long.MaxValue - 200), but I get an exception there. This is because the implementation (on my machine) to the Average extension method, as inspected by .NET Reflector is:
public static double Average(this IEnumerable<long> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
long num = 0L;
long num2 = 0L;
foreach (long num3 in source)
{
num += num3;
num2 += 1L;
}
if (num2 <= 0L)
{
throw Error.NoElements();
}
return (((double) num) / ((double) num2));
}
I know I can use a BigInt library (yes, I know that it is included in .NET Framework 4.0, but I'm tied to 3.5).
But I still wonder if there's a pretty straight forward implementation of calculating the average of integers without an external library. Do you happen to know about such implementation?
Thanks!!
UPDATE:
The previous example, of three large integers, was just an example to illustrate the overflow issue. The question is about calculating an average of any set of numbers which might sum to a large number that exceeds the type's max value. Sorry about this confusion. I also changed the question's title to avoid additional confusion.
Thanks all!!
This answer used to suggest storing the quotient and remainder (mod count) separately. That solution is less space-efficient and more code-complex.
In order to accurately compute the average, you must keep track of the total. There is no way around this, unless you're willing to sacrifice accuracy. You can try to store the total in fancy ways, but ultimately you must be tracking it if the algorithm is correct.
For single-pass algorithms, this is easy to prove. Suppose you can't reconstruct the total of all preceding items, given the algorithm's entire state after processing those items. But wait, we can simulate the algorithm then receiving a series of 0 items until we finish off the sequence. Then we can multiply the result by the count and get the total. Contradiction. Therefore a single-pass algorithm must be tracking the total in some sense.
Therefore the simplest correct algorithm will just sum up the items and divide by the count. All you have to do is pick an integer type with enough space to store the total. Using a BigInteger guarantees no issues, so I suggest using that.
var total = BigInteger.Zero
var count = 0
for i in values
count += 1
total += i
return total / (double)count //warning: possible loss of accuracy, maybe return a Rational instead?
If you're just looking for an arithmetic mean, you can perform the calculation like this:
public static double Mean(this IEnumerable<long> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
double count = (double)source.Count();
double mean = 0D;
foreach(long x in source)
{
mean += (double)x/count;
}
return mean;
}
Edit:
In response to comments, there definitely is a loss of precision this way, due to performing numerous divisions and additions. For the values indicated by the question, this should not be a problem, but it should be a consideration.
You may try the following approach:
let number of elements is N, and numbers are arr[0], .., arr[N-1].
You need to define 2 variables:
mean and remainder.
initially mean = 0, remainder = 0.
at step i you need to change mean and remainder in the following way:
mean += arr[i] / N;
remainder += arr[i] % N;
mean += remainder / N;
remainder %= N;
after N steps you will get correct answer in mean variable and remainder / N will be fractional part of the answer (I am not sure you need it, but anyway)
If you know approximately what the average will be (or, at least, that all pairs of numbers will have a max difference < long.MaxValue), you can calculate the average difference from that value instead. I take an example with low numbers, but it works equally well with large ones.
// Let's say numbers cannot exceed 40.
List<int> numbers = new List<int>() { 31 28 24 32 36 29 }; // Average: 30
List<int> diffs = new List<int>();
// This can probably be done more effectively in linq, but to show the idea:
foreach(int number in numbers.Skip(1))
{
diffs.Add(numbers.First()-number);
}
// diffs now contains { -3 -6 1 5 -2 }
var avgDiff = diffs.Sum() / diffs.Count(); // the average is -1
// To get the average value, just add the average diff to the first value:
var totalAverage = numbers.First()+avgDiff;
You can of course implement this in some way that makes it easier to reuse, for example as an extension method to IEnumerable<long>.
Here is how I would do if given this problem. First let's define very simple RationalNumber class, which contains two properties - Dividend and Divisor and an operator for adding two complex numbers. Here is how it looks:
public sealed class RationalNumber
{
public RationalNumber()
{
this.Divisor = 1;
}
public static RationalNumberoperator +( RationalNumberc1, RationalNumber c2 )
{
RationalNumber result = new RationalNumber();
Int64 nDividend = ( c1.Dividend * c2.Divisor ) + ( c2.Dividend * c1.Divisor );
Int64 nDivisor = c1.Divisor * c2.Divisor;
Int64 nReminder = nDividend % nDivisor;
if ( nReminder == 0 )
{
// The number is whole
result.Dividend = nDividend / nDivisor;
}
else
{
Int64 nGreatestCommonDivisor = FindGreatestCommonDivisor( nDividend, nDivisor );
if ( nGreatestCommonDivisor != 0 )
{
nDividend = nDividend / nGreatestCommonDivisor;
nDivisor = nDivisor / nGreatestCommonDivisor;
}
result.Dividend = nDividend;
result.Divisor = nDivisor;
}
return result;
}
private static Int64 FindGreatestCommonDivisor( Int64 a, Int64 b)
{
Int64 nRemainder;
while ( b != 0 )
{
nRemainder = a% b;
a = b;
b = nRemainder;
}
return a;
}
// a / b = a is devidend, b is devisor
public Int64 Dividend { get; set; }
public Int64 Divisor { get; set; }
}
Second part is really easy. Let's say we have an array of numbers. Their average is estimated by Sum(Numbers)/Length(Numbers), which is the same as Number[ 0 ] / Length + Number[ 1 ] / Length + ... + Number[ n ] / Length. For to be able to calculate this we will represent each Number[ i ] / Length as a whole number and a rational part ( reminder ). Here is how it looks:
Int64[] aValues = new Int64[] { long.MaxValue - 100, long.MaxValue - 200, long.MaxValue - 300 };
List<RationalNumber> list = new List<RationalNumber>();
Int64 nAverage = 0;
for ( Int32 i = 0; i < aValues.Length; ++i )
{
Int64 nReminder = aValues[ i ] % aValues.Length;
Int64 nWhole = aValues[ i ] / aValues.Length;
nAverage += nWhole;
if ( nReminder != 0 )
{
list.Add( new RationalNumber() { Dividend = nReminder, Divisor = aValues.Length } );
}
}
RationalNumber rationalTotal = new RationalNumber();
foreach ( var rational in list )
{
rationalTotal += rational;
}
nAverage = nAverage + ( rationalTotal.Dividend / rationalTotal.Divisor );
At the end we have a list of rational numbers, and a whole number which we sum together and get the average of the sequence without an overflow. Same approach can be taken for any type without an overflow for it, and there is no lost of precision.
EDIT:
Why this works:
Define: A set of numbers.
if Average( A ) = SUM( A ) / LEN( A ) =>
Average( A ) = A[ 0 ] / LEN( A ) + A[ 1 ] / LEN( A ) + A[ 2 ] / LEN( A ) + ..... + A[ N ] / LEN( 2 ) =>
if we define An to be a number that satisfies this: An = X + ( Y / LEN( A ) ), which is essentially so because if you divide A by B we get X with a reminder a rational number ( Y / B ).
=> so
Average( A ) = A1 + A2 + A3 + ... + AN = X1 + X2 + X3 + X4 + ... + Reminder1 + Reminder2 + ...;
Sum the whole parts, and sum the reminders by keeping them in rational number form. In the end we get one whole number and one rational, which summed together gives Average( A ). Depending on what precision you'd like, you apply this only to the rational number at the end.
Simple answer with LINQ...
var data = new[] { int.MaxValue, int.MaxValue, int.MaxValue };
var mean = (int)data.Select(d => (double)d / data.Count()).Sum();
Depending on the size of the set fo data you may want to force data .ToList() or .ToArray() before your process this method so it can't requery count on each pass. (Or you can call it before the .Select(..).Sum().)
If you know in advance that all your numbers are going to be 'big' (in the sense of 'much nearer long.MaxValue than zero), you can calculate the average of their distance from long.MaxValue, then the average of the numbers is long.MaxValue less that.
However, this approach will fail if (m)any of the numbers are far from long.MaxValue, so it's horses for courses...
I guess there has to be a compromise somewhere or the other. If the numbers are really getting so large then few digits of lower orders (say lower 5 digits) might not affect the result as much.
Another issue is where you don't really know the size of the dataset coming in, especially in stream/real time cases. Here I don't see any solution other then the
(previousAverage*oldCount + newValue) / (oldCount <- oldCount+1)
Here's a suggestion:
*LargestDataTypePossible* currentAverage;
*SomeSuitableDatatypeSupportingRationalValues* newValue;
*int* count;
addToCurrentAverage(value){
newValue = value/100000;
count = count + 1;
currentAverage = (currentAverage * (count-1) + newValue) / count;
}
getCurrentAverage(){
return currentAverage * 100000;
}
Averaging numbers of a specific numeric type in a safe way while also only using that numeric type is actually possible, although I would advise using the help of BigInteger in a practical implementation. I created a project for Safe Numeric Calculations that has a small structure (Int32WithBoundedRollover) which can sum up to 2^32 int32s without any overflow (the structure internally uses two int32 fields to do this, so no larger data types are used).
Once you have this sum you then need to calculate sum/total to get the average, which you can do (although I wouldn't recommend it) by creating and then incrementing by total another instance of Int32WithBoundedRollover. After each increment you can compare it to the sum until you find out the integer part of the average. From there you can peel off the remainder and calculate the fractional part. There are likely some clever tricks to make this more efficient, but this basic strategy would certainly work without needing to resort to a bigger data type.
That being said, the current implementation isn't build for this (for instance there is no comparison operator on Int32WithBoundedRollover, although it wouldn't be too hard to add). The reason is that it is just much simpler to use BigInteger at the end to do the calculation. Performance wise this doesn't matter too much for large averages since it will only be done once, and it is just too clean and easy to understand to worry about coming up with something clever (at least so far...).
As far as your original question which was concerned with the long data type, the Int32WithBoundedRollover could be converted to a LongWithBoundedRollover by just swapping int32 references for long references and it should work just the same. For Int32s I did notice a pretty big difference in performance (in case that is of interest). Compared to the BigInteger only method the method that I produced is around 80% faster for the large (as in total number of data points) samples that I was testing (the code for this is included in the unit tests for the Int32WithBoundedRollover class). This is likely mostly due to the difference between the int32 operations being done in hardware instead of software as the BigInteger operations are.
How about BigInteger in Visual J#.
If you're willing to sacrifice precision, you could do something like:
long num2 = 0L;
foreach (long num3 in source)
{
num2 += 1L;
}
if (num2 <= 0L)
{
throw Error.NoElements();
}
double average = 0;
foreach (long num3 in source)
{
average += (double)num3 / (double)num2;
}
return average;
Perhaps you can reduce every item by calculating average of adjusted values and then multiply it by the number of elements in collection. However, you'll find a bit different number of of operations on floating point.
var items = new long[] { long.MaxValue - 100, long.MaxValue - 200, long.MaxValue - 300 };
var avg = items.Average(i => i / items.Count()) * items.Count();
You could keep a rolling average which you update once for each large number.
Use the IntX library on CodePlex.
NextAverage = CurrentAverage + (NewValue - CurrentAverage) / (CurrentObservations + 1)
Here is my version of an extension method that can help with this.
public static long Average(this IEnumerable<long> longs)
{
long mean = 0;
long count = longs.Count();
foreach (var val in longs)
{
mean += val / count;
}
return mean;
}
Let Avg(n) be the average in first n number, and data[n] is the nth number.
Avg(n)=(double)(n-1)/(double)n*Avg(n-1)+(double)data[n]/(double)n
Can avoid value overflow however loss precision when n is very large.
For two positive numbers (or two negative numbers) , I found a very elegant solution from here.
where an average computation of (a+b)/2 can be replaced with a+((b-a)/2.

Categories

Resources