I have a list of probabilities like
0.0442857142857143
0.664642857142857
0.291071428571429
I want to convert them to the nearest percentages so that the sum of percentages adds up to 100
so something like this
0.0442857142857143 - 4 %
0.664642857142857 - 67 %
0.291071428571429 - 29 %
I cannot rely on Math.Round to always give me results which will add up to 1. What would be the best way to do this?
This is an method that could do the job.
public int[] Round(params decimal[] values)
{
decimal total = values.Sum();
var percents = values.Select(x=> Math.Round(x/total*100)).ToArray();
int totalPercent = perents.Sum();
var diff = 100 - totalPercent;
percents[percents.Lenght - 1] += diff;
return percents;
}
Interesting collection of answers.
The problem here is that you are getting a cumulative error in your rounding operations. In some cases the accumulated error cancels out - some values round up, others down, cancelling the total error. In other cases such as the one you have here, the rounding errors are all negative, giving an accumulated total error of (approximately) -1.
The only way to work around this in the general case is to keep track of the total accumulated error and add/subtract when that error gets large enough. It's tedious, but the only real way to get this right:
static int[] ToIntPercents(double[] values)
{
int[] results = new int[values.Length];
double error = 0;
for (int i = 0; i < values.Length; i++)
{
double val = values[i] * 100;
int percent = (int)Math.Round(val + error);
error += val - percent;
if (Math.Abs(error) >= 0.5)
{
int sign = Math.Sign(error);
percent += sign;
error -= sign;
}
results[i] = percent;
}
return results;
}
This code produces reasonable results for any size array with a sum of approximately +1.0000 (or close enough). Array can contain negative and positive values, just as long as the sum is close enough to +1.0000 to introduce no gross errors.
The code accumulates the rounding errors and when the total error exceeds the acceptable range of -0.5 < error < +0.5 it adjusts the output. Using this method the the output array for your numbers would be: [4, 67, 29]. You could change the acceptable error range to be 0 <= error < 1, giving the output [4, 66, 30], but this causes odd results when the array contains negative numbers. If that's your preference, change the if statement in the middle of the method to read:
if (error < 0 || error >= 1)
You could just multiply the number by 100 (if you have the decimal number)
0.0442857142857143 * 100 = 4 %
0.664642857142857 * 100 = 66 %
0.291071428571429 * 100 = 29 %
E: correct, 0.291071428571429 wouldn't add up to 30%...
Since you don't seem to care which number is bumped, I'll use the last. The algo is pretty simple, and will works for both the .4 edge case where you must add 1 and the one at .5 where you must remove 1 :
1) Round each number but the last one
2) Subtract 100 from the sum you have
3) Assign the remainder to the last number
As an extension method, it looks like this :
public static int[] SplitIntoPercentage(this double[] input)
{
int[] results = new int[input.Length];
for (int i = 0; i < input.Length - 1; i++)
{
results[i] = (int)Math.Round(input[i] * 100, MidpointRounding.AwayFromZero);
}
results[input.Length - 1] = 100 - results.Sum();
return results;
}
And here's the associated unit tests :
[TestMethod]
public void IfSumIsUnder100ItShouldBeBumpedToIt()
{
double[] input = new []
{
0.044,
0.664,
0.294
};
var result = input.SplitIntoPercentage();
Assert.AreEqual(100, result.Sum());
Assert.AreEqual(4, result[0]);
Assert.AreEqual(66, result[1]);
Assert.AreEqual(30, result[2]);
}
[TestMethod]
public void IfSumIsOver100ItShouldBeReducedToIt()
{
double[] input = new[]
{
0.045,
0.665,
0.295
};
var result = input.SplitIntoPercentage();
Assert.AreEqual(100, result.Sum());
Assert.AreEqual(5, result[0]);
Assert.AreEqual(67, result[1]);
Assert.AreEqual(28, result[2]);
}
Once refactored a little bit, the result looks like this :
public static int[] SplitIntoPercentage(this double[] input)
{
int[] results = RoundEachValueButTheLast(input);
results = SetTheLastValueAsTheRemainder(input, results);
return results;
}
private static int[] RoundEachValueButTheLast(double[] input)
{
int[] results = new int[input.Length];
for (int i = 0; i < input.Length - 1; i++)
{
results[i] = (int)Math.Round(input[i]*100, MidpointRounding.AwayFromZero);
}
return results;
}
private static int[] SetTheLastValueAsTheRemainder(double[] input, int[] results)
{
results[input.Length - 1] = 100 - results.Sum();
return results;
}
Logic is , Firstly we have to round off the "after decimal value" then apply round off to whole value.
static long PercentageOut(double value)
{
value = value * 100;
value = Math.Round(value, 1, MidpointRounding.AwayFromZero); // Rounds "up"
value = Math.Round(value, 0, MidpointRounding.AwayFromZero); // Rounds to even
return Convert.ToInt64(value);
}
static void Main(string[] args)
{
double d1 = 0.0442857142857143;
double d2 = 0.664642857142857;
double d3 = 0.291071428571429;
long l1 = PercentageOut(d1);
long l2 = PercentageOut(d2);
long l3 = PercentageOut(d3);
Console.WriteLine(l1);
Console.WriteLine(l2);
Console.WriteLine(l3);
}
Output
4
67
29
---
sum is 100 %
Related
All Decimal numbers are rounded to 2 digits when saved into application. I'm given a number totalAmount and asked to divide it into n equal parts(or close to equal).
Example :
Given : totalAmount = 421.9720; count = 2 (totalAmount saved into application is 421.97)
Expected : 210.99, 210.98 => sum = 421.97
Actual(with plain divide) : 210.9860 (210.99), 210.9860 (210.99) => sum = 412.98
My approach :
var totalAmount = 421.972m;
var count = 2;
var individualCharge = Math.Floor(totalAmount / count);
var leftOverAmount = totalAmount - (individualCharge * count);
for(var i = 0;i < count; i++) {
Console.WriteLine(individualCharge + leftOverAmount);
leftOverAmount = 0;
}
This gives (-211.97, -210)
public IEnumerable<decimal> GetDividedAmounts(decimal amount, int count)
{
var pennies = (int)(amount * 100) % count;
var baseAmount = Math.Floor((amount / count) * 100) / 100;
foreach (var _ in Enumerable.Range(1, count))
{
var offset = pennies-- > 0 ? 0.01m : 0m;
yield return baseAmount + offset;
}
}
Feel free to alter this if you want to get an array or an IEnumerable which is not deferred. I updated it to get the baseAmount to be the floor value so it isn't recalculated within the loop.
Basically you need to find the base amount and a total of all the leftover pennies. Then, simply add the pennies back one by one until you run out. Because the pennies are based on the modulus operator, they'll always be in the range of [0, count - 1], so you'll never have a final leftover penny.
You're introducing a few rounding errors here, then compounding them. This is a common problem with financial data, especially when you have to constrain your algorithm to only produce outputs with 2 decimal places. It's worse when dealing with actual money in countries where 1 cent/penny/whatever coins are no longer legal tender. At least when working with electronic money the rounding isn't as big an issue.
The naive approach of dividing the total by the count and rounding the results is, as you've already discovered, not going to work. What you need is some way to spread out the errors while varying the output amounts by no more than $0.01. No output value can be more than $0.01 from any other output value, and the total must be the truncated total value.
What you need is a way to distribute the error across the output values, with the smallest possible variation between the values in the result. The trick is to track your error and adjust the output down once the error is high enough. (This is basically how the Bresenham line-drawing algorithm figures out when to increase the y value, if that helps.)
Here's the generalized form, which is pretty quick:
public IEnumerable<decimal> RoundedDivide(decimal amount, int count)
{
int totalCents = (int)Math.Floor(100 * amount);
// work out the true division, integer portion and error values
float div = totalCents / (float)count;
int portion = (int)Math.Floor(div);
float stepError = div - portion;
float error = 0;
for (int i = 0; i < count; i++)
{
int value = portion;
// add in the step error and see if we need to add 1 to the output
error += stepError;
if (error > 0.5)
{
value++;
error -= 1;
}
// convert back to dollars and cents for outputput
yield return value / 100M;
}
}
I've tested it with count values from 1 through 100, all outputs sum to match the (floored) input value exactly.
Try to break it down to steps:
int decimals = 2;
int factor = (int)Math.Pow(10, decimals);
int count = 2;
decimal totalAmount = 421.97232m;
totalAmount = Math.Floor(totalAmount * factor) / factor; // 421.97, you may want round here, depends on your requirement.
int baseAmount = (int)(totalAmount * factor / count); // 42197 / 2 = 21098
int left = (int)(totalAmount * factor) % count; // 1
// Adding back the left for Mod operation
for (int i = 0; i < left; i++)
{
Console.WriteLine((decimal)(baseAmount + 1) / factor); // 21098 + 1 / 100 = 210.99
}
// The reset that does not needs adjust
for (int i = 0; i < count - left; i++)
{
Console.WriteLine((decimal)baseAmount / factor); // 21098 / 100 = 210.98
}
The program doesn't calculate/display the correct calculation/number correctly
I'm trying to learn some C# for Unity game development, and tried out some random math stuff, but something seems to not work and I can't figure out why.
Console.WriteLine("What is the total amount you'd like change for? For example: 41,15");
double change = Convert.ToDouble(Console.ReadLine());
// 500 200 100 50 20 10 5
// 2 1 0,50 0,20 0,10 0,05
int fivehundred = 0, twohundred = 0, onehundred = 0, fifty = 0, twenty = 0, ten = 0, five = 0;
int ctwo = 0, cone = 0, cfifty = 0, ctwenty = 0, cten = 0, cfive = 0;
for (int i = 0; change >= 500; i++)
{
change -= 500;
fivehundred++;
}
for (int i = 0; change >= 200; i++)
{
change -= 200;
twohundred++;
}
for (int i = 0; change >= 100; i++)
{
change -= 100;
onehundred++;
}
for (int i = 0; change >= 50; i++)
{
change -= 50;
fifty++;
}
for (int i = 0; change >= 20; i++)
{
change -= 20;
twenty++;
}
for (int i = 0; change >= 10; i++)
{
change -= 10;
ten++;
}
for (int i = 0; change >= 5; i++)
{
change -= 5;
five++;
}
for (int i = 0; change >= 2; i++)
{
change -= 2;
ctwo++;
}
for (int i = 0; change >= 1; i++)
{
change -= 1;
cone++;
}
for (int i = 0; change >= 0.50; i++)
{
change -= 0.50;
cfifty++;
}
for (int i = 0; change >= 0.20; i++)
{
change -= 0.20;
ctwenty++;
}
for (int i = 0; change >= 0.10; i++)
{
change -= 0.10;
cten++;
}
for (int i = 0; change >= 0.05; i++)
{
change -= 0.05;
cfive++;
}
Console.WriteLine("500x {0}, 200x {1}, 100x {2}, 50x {3}, 20x {4}, 10x {5}, 5x {6}, 2x {7}, 1x {8}, 0,50x {9}, 0,20x {10}, 0,10x {11}, 0,05x {12}", fivehundred, twohundred, onehundred, fifty, twenty, ten, five, ctwo, cone, cfifty, ctwenty, cten, cfive);
Even though there's still 5 cents left, the result gives me is this:
(this is when I entered 0,15 cents)
What is the total amount you'd like change for? For example: 41,15
0,15
500x 0, 200x 0, 100x 0, 50x 0, 20x 0, 10x 0, 5x 0, 2x 0, 1x 0, 0,50x 0, 0,20x 0, 0,10x 1, 0,05x 0
Press any key to continue . . .
If it's €0,09 or below, it does display that it needs 0,05 1x, but with anything above it with a remaining 5 cents, it doesn't. Everything else works as intended so far though.
(Also, any tips how I can make the code more efficient?)
I think this is what you are trying to do, but instead of using division, you are doing successive subtractions.
class Program
{
static void Main(string[] args)
{
int[] change = Currency.MakeChange(41.37m);
decimal sum = 0m;
for (int i = 0; i < change.Length; i++)
{
var amount = change[i]*Currency.Denominations[i];
sum += amount;
Debug.WriteLine($"{change[i]}×{Currency.Denominations[i]}");
}
Debug.WriteLine($"sum={sum}");
// output:
// 0×500
// 0×200
// 0×100
// 0×50
// 2×20
// 0×10
// 0×5
// 0×2
// 1×1
// 0×0.5
// 1×0.2
// 1×0.1
// 1×0.05
// 2×0.01
// sum=41.37
}
}
public class Currency
{
public static readonly decimal[] Denominations =
new decimal[] { 500m, 200m, 100m, 50m, 20m, 10m, 5m, 2m, 1m, 0.5m, 0.2m, 0.1m, 0.05m, 0.01m };
public static int[] MakeChange(decimal value)
{
int[] change = new int[Denominations.Length];
decimal remain = value;
for (int i = 0; i < Denominations.Length; i++)
{
// get the next note (amount in currency).
// must move from highest to smallest value.
decimal note = Denominations[i];
// can you divide the remainder with the note
int qty = (int)(decimal.Floor(remain/note));
change[i] = qty;
// calculate remaining amount
remain -= qty*note;
}
return change;
}
}
First of all, yes, you can simplify your code by A LOT just by replacing the for loops with while loops.
Second, to answear your actual question. The program does not enter the for loops because 0.05 it's not actually 0.05 because of how computers store floating point values in memory. EX.: 1/3 != 0.333333. To prevent this use the decimal data type.
Better explanation here and in the official C# Docs here under Precision in Comparisions.
Your code works as-is if you change from double to type decimal. There is a rounding error that occurs when using double precision, when I ran it 15-10 came out to 0.4999999999. Decimal has greater precision, so I would start there. You can figure this out either by setting breakpoints in your loops and stepping through them, or by adding Console.Writeline(change) in each loop so you can see what is happening. The debugger is your friend. That being said, lets clean up this code
Console.WriteLine("What is the total amount you'd like change for? For example: 41,15");
decimal change = Convert.ToDecimal(Console.ReadLine());
// 500 200 100 50 20 10 5
// 2 1 0,50 0,20 0,10 0,05
decimal[] currencyValues = {500m, 200m, 100m, 50m, 20m, 10m, 5m, 2m, 1m, .50m, .20m, .10m, 0.05m};
int[] returnChange = new int[13];
for(int i = 0; i < currencyValues.Length; i++)
{
if(change >= currencyValues[i])
{
returnChange[i] = (int)(change / currencyValues[i]);
change = change % currencyValues[i];
}
Console.Write($"{currencyValues[i]}x {returnChange[i]} ");
}
We can make use of arrays so we don't have to duplicate so much. So we have one array that holds the values of each denomination of currency, and then another array for the count of each denomination in the resulting change. Then we can go through each currency amount and do our calculations in one loop.
So first, we check to make sure we have at least as much change as the amount we are checking against. No need to calculate how many currency of value 5 we need to return if they only have 3, for example. Thats pretty intuitive so lets move on to the next part.
First, we divide the change left by each currency value. We only want whole numbers, we can't give someone half of a coin, after all. So we cast to integer to round the result and make it fit into our returnChange array. The next part is probably gonna look weird if you haven't seen the modulo operator % before. This basically says
Perform the division. But, rather than assigning the result of the division, assign the `remainder` instead
So if we have .70 currency, and we took out .50 for the change, the modulo % operator will say we have .20 currency remaining.
Hope this helped.
Refactor common code into reusable components. For example, your logic to calculate the count of a denomination is the same except for the denomination value and remaining balance, so create a function to abstract that logic:
// `ref` passes the decimal value in by reference, meaning any
// changes made to that parameter are also made to the variable
// passed into the method/function (by default a copy is made
// and changes here have no side effects
public int CashOut(decimal denomination, ref decimal balance)
{
var result = 0;
for (int i = 0; change >= denomination; i++)
{
balance -= denomination;
result++;
}
return result;
}
As a comment pointed out, a for loop isn't ideal here - you're not using
the variable i at all; a while loop is more appropriate:
public int CashOut( decimal denomination, ref decimal balance )
{
var result = 0;
while( balance >= denomination )
{
balance -= denomination;
++result; // preincrement operator has better performance
}
return result;
}
There are still better ways to perform your desired calculation; as another
answer pointed out, you can use division:
public int CashOut( decimal denomination, ref decimal balance )
{
var result = Convert.ToInt32( balance / denomination );
balance -= result * denomination;
return result;
}
If you didn't abstract the calculation changes, each change would require you to edit your N for loops; with this abstraction, you only have to edit it in a single place.
Replacing your for loops would look something like:
fivehundred = CashOut( 500.0M, ref change );
twohundred = CashOut( 200.0M, ref change );
// etc.
But that's still highly repetitive. As another answer and comment pointed out, you can configure an array of denominations (and results) to process sequentially:
var denominations = new[]{ 500.0M, 200.0M, 100.0M }
var results = new int[denominations.Length];
for( var i = 0; i < denominations.Length; ++i )
{
results[i] = CashOut( denominations[i], ref change );
}
But you don't need that for loop if you use LINQ!
var denominations = new[]{ 500.0M, 200.0M, 100.0M };
var results = denominations.Select( d => CashOut( d, change ) )
.ToArray();
Your output could then be written as:
for( var i = 0; i < denominations; ++i )
{
Console.Write( $"{denominations[0]}x {results[i]} " )
}
Console.WriteLine();
How about projecting an anonymous type to keep the denomination paired with its result?
var denominations = new[]{ 500.0M, 200.0M, 100.0M };
var results = denominations.Select( d =>
new
{
Denomination = d,
Count = CashOut( d, change ),
} );
Then your output could look like:
foreach(var result in results)
{
Console.Write( $"{result.Denomination}x {result.Count} " );
}
Console.WriteLine();
If you wanted to find out how many 200's were in the results, you can find it easily:
var twoHundreds = results.FirstOrDefault(r => r.Denomination == 200.0M)
?.Count // ?. means execute the following statement(s) if the value is not null
?? 0M; // ?? is the null coalescing operator meaning return this value if the precedeing is null
I'm trying to do the Modified Kaprekar Numbers problem (https://www.hackerrank.com/challenges/kaprekar-numbers) which describes a Kaprekar number by
Here's an explanation from Wikipedia about the ORIGINAL Kaprekar
Number (spot the difference!): In mathematics, a Kaprekar number for a
given base is a non-negative integer, the representation of whose
square in that base can be split into two parts that add up to the
original number again. For instance, 45 is a Kaprekar number, because
45² = 2025 and 20+25 = 45.
and what I don't understand is why 10 and 100 aren't Kaprekar numbers.
10^2 = 1000 and 10 + 00 = 10
Right?
So my solution
// Returns the number represented by the digits
// in the range arr[i], arr[i + 1], ..., arr[j - 1].
// If there are no elements in range, return 0.
static int NumberInRange(int[] arr, int i, int j)
{
int result = 0;
for(; i < j; ++i)
{
result *= 10;
result += arr[i];
}
return result;
}
// Returns true or false depending on whether k
// is a Kaprekar number.
// Example: IsKaprekar(45) = true because 45^2=2025 and 20+25=45
// Example: IsKaprekar(9) = false because the set of the split
// digits of 7^2=49 are {49,0},{4,9} and
// neither of 49+0 or 4+9 equal 7.
static bool IsKaprekar(int k)
{
int square = k * k;
int[] digits = square.ToString().Select(c => (int)Char.GetNumericValue(c)).ToArray();
for(int i = 0; i < digits.Length; ++i)
{
int right = NumberInRange(digits, 0, i);
int left = NumberInRange(digits, i, digits.Length);
if((right + left) == k)
return true;
}
return false;
}
is saying all the Kaprekar numbers between 1 and 100 are
1 9 10 45 55 99 100
whereas the "right" answer is
1 9 45 55 99
In 100+00 the right is 00, which is wrong because in a kaprekar number the right may start with zero (ex: 025) but cannot be entirely 0.
Therefore you can put a condition in the loop that
if(right==0)
return false;
The reason is because 10 x 10 = 100. Then you substring the right part with a length equals d = 2, that is digit count of original value (10), then the left part would be 1.
So l = 1 and r = 00, l + r = 1, that is not equals to 10.
The same for 100. 100 x 100 = 10000. l = 10, r = 000, so l + r = 10 not equal 100.
Here is my solution in JAVA.
static void kaprekarNumbers(int p, int q) {
long[] result = IntStream.rangeClosed(p, q).mapToLong(Long::valueOf)
.filter(v -> {
int d = String.valueOf(v).length();
Long sq = v * v;
String sqSt = sq.toString();
if (sqSt.length() > 1) {
long r = Long.parseLong(sqSt.substring(sqSt.length() - d));
long l = Long.parseLong(sqSt.substring(0, sqSt.length() - d));
return r + l == v;
} else return v == 1;
}).toArray();
if (result.length > 0) {
for (long l : result) {
System.out.print(l + " ");
}
} else {
System.out.println("INVALID RANGE");
}
}
How about something like this.
static bool IsKaprekar(int k)
{
int t;
for (int digits = new String(k).length(); digits > 0; digits--, t *= 10);
long sq = k * k;
long first = sq / t;
long second = sq % t;
return k == first + second;
}
find a number to divide and mod the square with in order to split it. This number should be a factor of 10 based on the number of digits in the original number.
calculate the square.
split the square.
compare the original to the sum of the splits.
I want to make a method that takes a variable of type int or long and returns an array of ints or longs, with each array item being a group of 3 digits. For example:
int[] i = splitNumber(100000);
// Outputs { 100, 000 }
int[] j = splitNumber(12345);
// Outputs { 12, 345 }
int[] k = splitNumber(12345678);
// Outputs { 12, 345, 678 }
// Et cetera
I know how to get the last n digits of a number using the modulo operator, but I have no idea how to get the first n digits, which is the only way to make this method that I can think of. Help please!
Without converting to string:
int[] splitNumber(int value)
{
Stack<int> q = new Stack<int>();
do
{
q.Push(value%1000);
value /= 1000;
} while (value>0);
return q.ToArray();
}
This is simple integer arithmetic; first take the modulo to get the right-most decimals, then divide to throw away the decimals you already added. I used the Stack to avoid reversing a list.
Edit: Using log to get the length was suggested in the comments. It could make for slightly shorter code, but in my opinion it is not better code, because the intent is less clear when reading it. Also, it might be less performant due to the extra Math function calls. Anyways; here it is:
int[] splitNumber(int value)
{
int length = (int) (1 + Math.Log(value, 1000));
var result = from n in Enumerable.Range(1,length)
select ((int)(value / Math.Pow(1000,length-n))) % 1000;
return result.ToArray();
}
By converting into a string and then into int array
int number = 1000000;
string parts = number.ToString("N0", new NumberFormatInfo()
{
NumberGroupSizes = new[] { 3 },
NumberGroupSeparator = "."
});
By using Maths,
public static int[] splitNumberIntoGroupOfDigits(int number)
{
var numberOfDigits = Math.Floor(Math.Log10(number) + 1); // compute number of digits
var intArray = new int[Convert.ToInt32(numberOfDigits / 3)]; // we know the size of array
var lastIndex = intArray.Length -1; // start filling array from the end
while (number != 0)
{
var lastSet = number % 1000;
number = number / 1000;
if (lastSet == 0)
{
intArray[lastIndex] = 0; // set of zeros
--lastIndex;
}
else if (number == 0)
{
intArray[lastIndex] = lastSet; // this could be your last set
--lastIndex;
}
else
{
intArray[lastIndex] = lastSet;
--lastIndex;
}
}
return intArray;
}
Try converting it to string first and do the parsing then convert it back to number again
Convert to string
Get length
If length modulus 3 == 0
String substring it into ints every 3
else if
Find remainder such as one or two left over
Substring remainder off of front of string
Then substring by 3 for the rest
You can first find out how large the number is, then use division to get the first digits, and modulo to keep the rest:
int number = 12345678;
int len = 1;
int div = 1;
while (number >= div * 1000) {
len++;
div *= 1000;
}
int[] result = new int[len];
for (int i = 0; i < result.Length; i++) {
result[i] = number / div;
number %= div;
div /= 1000;
}
You can use this with the System.Linq namespace from .NET 3.5 and above:
int[] splitNumber(long value)
{
LinkedList<int> results = new LinkedList<int>();
do
{
int current = (int) (value % 1000);
results.AddFirst(current);
value /= 1000;
} while (value > 0);
return results.ToArray();// Extension method
}
I use LinkedList<int> to avoid having to Reverse a list before returning. You could also use Stack<int> for the same purpose, which would only require .NET 2.0:
int[] splitNumber(long value)
{
Stack<int> results = new Stack<int>();
do
{
int current = (int) (value % 1000);
results.Push(current);
value /= 1000;
} while (value > 0);
return results.ToArray();
}
In c# how do I evenly divide 100 into 7?
So the result would be
16
14
14
14
14
14
14
The code below is incorrect as all 7 values are set to 15 (totalling 105).
double [] vals = new double[7];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Ceiling(100d / vals.Length);
}
Is there an easy way to do this in c#?
Thanks
To get my suggested result of 15, 15, 14, 14, 14, 14, 14:
// This doesn't try to cope with negative numbers :)
public static IEnumerable<int> DivideEvenly(int numerator, int denominator)
{
int rem;
int div = Math.DivRem(numerator, denominator, out rem);
for (int i=0; i < denominator; i++)
{
yield return i < rem ? div+1 : div;
}
}
Test:
foreach (int i in DivideEvenly(100, 7))
{
Console.WriteLine(i);
}
Here you go:
Func<int, int, IEnumerable<int>> f = (a, b) =>
Enumerable.Range(0,a/b).Select((n) => a / b + ((a % b) <= n ? 0 : 1))
Good luck explaining it in class though :)
Since this seems to be homework, here is a hint and not the full code.
You are doing Math.Ceiling and it converts 14.28 into 15.
The algorithm is this
Divide 100 by 7, put the result in X
Get the highest even number below X and put this in Y.
Multiply Y by 7 and put the answer in Z.
Take Z away from 100.
The answer is then 6 lots of Y plus whatever the result of step 4 was.
This algorithm may only work for this specific instance.
I'm sure you can write that in C#
Not sure if this is exactly what you are after, but I would think that if you use Math.ceiling you will always end up with too big a total. Math.floor would underestimate and leave you with a difference that can be added to one of your pieces as you see fit.
For example by this method you might end up with 7 lots of 14 giving you a remainder of 2. You can then either put this 2 into one of your pieces giving you the answer you suggested, or you could split it out evenly and add get two pieces of 15 (as suggested in one of the comments)
Not sure why you are working with doubles but wanting integer division semantics.
double input = 100;
const int Buckets = 7;
double[] vals = new double[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = Math.Floor(input / Buckets);
}
double remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
example for ints with more flexibility,
int input = 100;
const int Buckets = 7;
int [] vals = new int[Buckets];
for (int i = 0; i < vals.Length; i++)
{
vals[i] = input / Buckets;
}
int remainder = input % Buckets;
// give all of the remainder to the first value
vals[0] += remainder;
// If instead you wanted to distribute the remainder evenly,
// priority to first
for (int r = 0; r < remainder;r++)
{
vals[r % Buckets] += 1;
}
It is worth pointing out that the double example may not be numerically stable in that certain input values and bucket sizes could result in leaking fractional values.