How to round up to the higher 10 in C#? - c#

I have to write a program at school that allows the user to input a 7-digits of a GTIN-8 barcode and calculate check digit. To calculate the check digit the seven input numbers are multiplied by 3, 1, 3, 1 etc.
for (i = 0; i < 7; i++)
{
//Convert String to Character
ch = gtinNum[i];
//Convert Character to Integer
number = Convert.ToInt32(ch);
product = number * weights[i];
total = total + product;
}//end for loop
After that, the total is taken away from the nearest higher ten. For example if the total was 43 then it would be 50-43.
In the simplest way possible, how do I round up to the higher ten?

You can use Math.Ceiling, you just need to divide by ten first and multiply by 10 afterwards. Divide by 10.0 to avoid integer division(Math.Ceiling takes double):
int num = 43;
int nextHigherTen = (int)Math.Ceiling(num / 10.0) * 10;
This "rounds" 41-50 up to 50. If you want it from 40-49 you could use this:
int nextHigherTen = (int)Math.Ceiling((num + 1) / 10.0) * 10;

Related

How exactly does one make random numbers add up to a declared sum?

I'm confused as to how exactly I would make 9 random numbers add to whatever number the user may input. Let's say the user inputs "200" as the number, how do I make it so that I could get 9 random numbers add up exactly to 200?
Obviously, the code below doesn't work the way I want it to because it's literally just 9 random numbers that don't add up to a specific number. I just have no idea how to get this built properly.
public static void RandomStats()
{
Random RandomClass = new Random();
int[] intRandomStats = {
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101)
};
// ...
}
I think your question is more of math question than a code question.
It sounds like what you are looking for is a multinomial distribution. A very naive way of generating a distribution like that would be to think of it like throwing dice. Imagine that you have 200 dice with 9 sides each. Roll all of them. Count all the ones that ended up with the 1 side up, that would be your first number. Then count the ones that ended up with the 2 side up, that would be your second number. Continue until all dice are counted. There are 200 dice, so the sum of the counts will be 200. Each count would have the same probability distribution.
The above pseudo-algorithm would not be so efficient, basically looping over each die. Maybe efficiency is not so important in your case, (and 200 is a small number, so it does not matter) so feel free to write this algorithm.
If efficiency matters, try to find an existing implementation in a library. Maybe the MathNet library would work for you? See the Sample method if you are interested. At the very least, now that you know the term "multinomial distribution" it should be a bit easier to google for inspiration.
Imagine you have a bag of 200 coins. You need to divvy those coins into 9 random piles. A pile can have all the coins in the bag, some of the coins in the bag, or no coins.
Each time you allocate coins for a pile, the number of coins in the bag gets smaller (unless you grabbed 0 coins in which case it stays the same). This new count is referenced for the next pile allocation.
var rand = new Random();
var amount = 200;
var targetOutputValueCount = 9;
var outputValues = new List<int>();
for (int i = 1; i < targetOutputValueCount; i++) // 1 less than all groups
{
var groupAmount = rand.Next(0, amount);
amount -= groupAmount;
outputValues.Add(groupAmount);
}
// for the last group, it's whatever is left over
outputValues.Add(amount);
foreach (var outputValue in outputValues)
{
Console.WriteLine(outputValue);
}
An example output would be
148
28
0
2
12
2
1
6
1
The advantage of this approach is that you are always guaranteed to have positive output numbers.
Just generate eight numbers and compute the ninth as the missing difference:
int theSum = 200;
var randomNumbers = new int[9];
for(int i = 0; i < 8; i)
{
randomNumbers[i] = random.Next(0, theSum);
}
randomNumbers[8] = theSum - randomNumbers.Sum();
The methods proposed so far are workable, but tend to produce results that are skewed. For example, forcing the last number to give the correct sum can give you a value that is a long way off the other values (and possibly negative, which might be a problem in some cases). Calculating random values in the range from zero up to the remaining sum will give you a series of numbers that rapidly approach zero.
Instead, to generate n random numbers from 0 to total, I would suggest picking n-1 random values in the range from 0 to total (inclusive). Consider each of these values as the location of a bookmark in a deck of total cards. If the deck is then separated into n piles at these bookmarks, then the number of cards in each pile will give you a uniformly distributed set of values that sum to total.
Here's some code to illustrate the idea (in C, sorry):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp(const void *a, const void *b) {
return *((int*)a) - *((int*)b);
}
int main(int argc, char *argv[]) {
int nterms, total, x, i, checksum;
int *array;
srand(time(0));
if (argc != 3) return puts("Require 2 arguments: <nterms> and <total>");
nterms = atoi(argv[1]); /* N.B. Input value checks omitted. */
total = atoi(argv[2]); /* Avoid large or negative values! */
/* We want to generate nterms intervals across the range from 0 to */
/* total (inclusive), so we need an array of nterms+1 values to mark */
/* the start and end of each interval. */
array = malloc((nterms+1) * sizeof(int));
/* The first and last items in this list must be zero and total (to */
/* ensure that the list of numbers add up to the correct amount) */
array[0] = 0;
array[nterms] = total;
/* Fill the rest of the array with random values from 0 to total. */
for (i=1; i<nterms; i++) {
array[i] = rand() % (total+1);
}
/* Sort these values in ascending order. */
qsort(array, nterms+1, sizeof(int), cmp);
/* Our list of random numbers can now be calculated from the */
/* difference between each pair of values in this list. */
printf("Numbers:");
for (i=checksum=0; i<nterms; i++) {
x = array[i+1] - array[i];
checksum += x;
printf(" %d", x);
}
printf("\nTotal: %d\n", checksum);
return 0;
}
You could also repeatedly generate 9 random numbers until they sum up to the desired sum. The optimal range for the random numbers is twice the target sum (200) divided by the number of random numbers (9) because then their average will be close to 200/9.
var random = new Random();
var randomNumbers = new int[9];
int input = 200;
int optimalRange = 2 * input / randomNumbers.Length;
int iterations = 0;
do {
for (int i = 0; i < randomNumbers.Length; i++) {
randomNumbers[i] = random.Next(optimalRange);
}
iterations++;
} while (randomNumbers.Sum() != input);
Console.WriteLine($"iterations = {iterations}");
Console.WriteLine($"numbers = {String.Join(", ", randomNumbers)}");
Example output:
iterations = 113
numbers = 2, 24, 39, 28, 6, 28, 34, 17, 22
In a test I repeated one million times I got these # of iterations:
average = 98.4
min = 1
max = 1366
And in 10170 cases I got it right at the first iteration.
Thanks for the hint #DrPhil. Here's a method using linq.
Random rnd = new Random();
int[] dice = new int[200];
var sidesUp = dice.Select(x => rnd.Next(1, 10));
List<int> randomNumbers = sidesUp.GroupBy(p => p).Select(x => x.Count()).ToList();
My approach ain't too different from others, but here it is:
Started by declaring an integer with the total value;
Subtracted the user input;
Used a for loop to iterate 8 times;
Each time get the division from remaining total and remaining iterations;
Option 1:
Used previous division as the maximum random value if remaining total is less than the max value;
Option 2:
Used previous division as the maximum random value;
The 9th number is the remaining total.
//run: RandomStats(0,101,200) for your particular example.
public static void RandomStats(int min, int max, int total)
{
Random randomClass = new Random();
int[] randomStats = new int[9];
int value = 0;
int totalValue = total;
bool parsed = false;
while (!parsed)
{
Console.WriteLine("Please enter a number:");
if (int.TryParse(Console.ReadLine(), out value))
{
parsed = true;
totalValue -= value;
for (int i = 0; i < randomStats.Length-1; i++)
{
//option 1
int remainMax = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
int randomValue = randomClass.Next(min, totalValue < max ? remainMax : max);
//option 2
//max = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
//int randomValue = randomClass.Next(min, max);
totalValue -= randomValue;
randomStats[i] = randomValue;
}
randomStats[8] = totalValue;
}
else
{
Console.WriteLine("Not a valid input");
}
}
Console.WriteLine($"min value: {min}\tmax value: {max}\ttotal value: {total}");
int testValue = value;
Console.WriteLine("Input value - " + value);
for (int i = 0; i < randomStats.Length; i++)
{
testValue += randomStats[i];
int randomIndex = i + 1;
Console.WriteLine(randomIndex + " Random value - " + randomStats[i]);
}
Console.WriteLine("test value - " + testValue);
Console.ReadKey();
}
option 1 output:
min value: 0 max value: 101 total value: 200
Input value - 10
1 Random value - 13
2 Random value - 2
3 Random value - 95
4 Random value - 10
5 Random value - 0
6 Random value - 15
7 Random value - 10
8 Random value - 10
9 Random value - 35
test value - 200
option 2 output:
min value: 0 max value: 67* total value: 200
Input value - 10
1 Random value - 1
2 Random value - 16
3 Random value - 5
4 Random value - 29
5 Random value - 17
6 Random value - 7
7 Random value - 48
8 Random value - 19
9 Random value - 48
test value - 200
*this was still 101 but became irrelevant since I divided remaining totals by the iterations

Why my function that calculates pi number is freezing?

I need to calculate pi number until 15th digit but my function freezes. I use this Taylor's series:
atan(x) = \sum_{n=0}^\infty \frac{(-1)^{n} \cdot x^{2n + 1}}{2n + 1}
And x equals 1.
There is my function:
public static decimal Pi()
{
decimal curr = 4m,
prev = 0m,
one = -1m,
den = 3.0m;
while (Math.Abs(curr - prev) > 1e-15m)
{
prev = curr;
curr += 4.0m * one / den;
one = -one;
den += 2.0m;
}
return curr;
}
I have debugged it, but i did't find why. Link to REPL
The problem is that the algorithm is exponential on the number of digits of precision that you want. To demonstrate I've changed your code a bit to track the number of iterations before we get a result with more and more precision
decimal curr = 4m,
prev = 0m,
one = -1m,
den = 3.0m;
int i = 0;
decimal epsilon = 1;
while(true)
{
prev = curr;
curr += 4.0m * one / den;
one = -one;
den += 2.0m;
i++;
if(Math.Abs(curr - prev) <= epsilon)
{
Console.WriteLine(curr);
Console.WritleLine(i);
epsilon /= 10m;
}
}
Here's the resulting output after it gets to 8 digits of precision.
3.4666666666666666666666666667
2
3.1891847822775947292439110472
20
3.1465677471829564012877876609
200
3.1420924036835276076022995132
2000
3.1416426510898869869000847891
20000
3.1415976535647933322124871234
200000
3.1415931535895432385563933310
2000000
3.1415927035897907384627370503
20000000
3.1415926585897932134626435385
200000000
as you can see each additional digit of percision take 10 times as many iterations and thus 15 digits will take 10,000,000 times as long as it takes to get 8.
From the formula,
|cur - prev| = 1 / (2n+1) + 1 / (2n-1)
Your function should be working correctly, you just have to wait until the 250,000,000,000,000th term. A little of patience (only a few days).
But there is no guarantee that you get 15 exact digits in the end.
Never use Leibnitz' formula. Use Machin's variant. https://en.wikipedia.org/wiki/Machin-like_formula

Convert Decimal but stay with same amount of Digits as original C#

For example, if I have a decimal of 10.205 and I subtracted 0.305 of it, then it should be displayed as 09.900 instead of 9.9, as all unnecessary digits before and after should become zeros.
So maybe it would be good having a method that will calculate 10205 - 305 (= 9900) and then return a converted decimal string "09.900".
How can I always stay with the same amount of digits.
If I write this code:
decimal x = 10.205m;
decimal y = 0.305m;
decimal z = x - y;
Console.WriteLine(z);
The output is 9.900. No need to do anything special.
Now, if I do decimal.GetBits(z) on the above z I get int[] { 9900, 0, 0, 196608 }.
But, if I redefine z as z = 9.9 and do a decimal.GetBits(z) I get int[] { 99, 0, 0, 65536 }.
The fourth value in the array is the number of decimal places (if you divide by 65535 you can find out how many).
So, with z = 9.9 I get 1 decimal place (65536 / 65536 == 1). To change it to 3 decimal places I add 2 * 65536 to the fourth integer, but I also need to multiply the first integer by 100 (or 10 ^ 2). I then get these bits: int[] { 9900, 0, 0, 196608 }.
Then you can do z = new decimal(new int[] { 99 * 10 * 10, 0, 0, 65536 + 2 * 65536 });.
Then when I do Console.WriteLine(z) I get 9.900.
I built this Extension method:
public static decimal getDecimalFixed(decimal amount, decimal subtract)
{
var parts = amount.ToString().Split('.');
decimal sum = amount - subtract;
// get's a string of zeros using the same amount of digits
string part1zeros = new String('0', parts[0].Length);
string part2zeros = new String('0', parts[1].Length);
// decimal format ex: ToString("000.0000")
return Convert.ToDecimal(sum.ToString(part1zeros + "." + part2zeros));
}

Random occurrences

I am not quite sure how to go about this.
I need to generate 14,296 random numbers with different levels of probability.
so for example I need an array containing the numbers 18, 1, and 17. Each number has a different percent probability of occuring. So:
55% = 18
(7,862.8 times)
30% = 1
(4,288.8 times)
15% = 17
(2,144.4 times)
the result would be something like new Array () { 18, 18, 1, 17, 1, 18...}
If you'll always have the values as integer percentages, I'd fill a 100-element array with values according to the probability, so in this case your array would have 55 occurrences of 18, 30 occurrences of 1, and 15 occurrences of 17. Then you just need to pick 14,296 random values from that array. (i.e. pick an integer in the range [0, 100) and take that element.)
For different ways of expressing the probabilities, there are different approaches, of course. But if you're given integer percentages, this is an easily-understood option. (Another way is to scale all of the probabilities by the total, i.e. into a range of [0, 1), and then take a random double in that range.)
Divide the range of random generator into proportional segments, and, judging to which segment the next random number has fallen into, select the corresponding number from your set.
Something like (simplified):
const int numbers[3] = { 1, 17, 18 };
const int borders[2] = { 0.30*MAX_RANDOM, (0.30 + 0.15) * MAX_RANDOM };
int i = random.next(), num;
if (i < borders[0]) num = number[0];
else if (i < borders[0]) num = number[1];
else num = number[2];
Of course, if there's more numbers than three, it's better to use a loop.
Note: unlike Jon Skeet's solution, this one can provide any desired granularity up to 1/(MAX_RANDOM+1) (which is often up to 2^32 on 32-bit machines), rather than strictly 1%.
Random r = new Random();
// for each number to generate
int nextNumber;
double probability = r.NextDouble();
if (probability < 55.0 / 100.0)
nextNumber = 18;
else if (probability < (55.0 + 30.0) / 100.0)
nextNumber = 1;
else
nextNumber = 17;
How about something like this (untested):
struct np
{
int n;
int p;
}
Create a List<np> and will it with value/percentage pairs (e.g. n = 18, p = 55).
Then just do the following to pick a number:
List<np> npl = new List<np>();
// (fill the list here)
int r = rnd.next(total_of_all_p_values); // get random number
int res = 0; // result
for(int i = 0; i < npl.Length(); r -= npl[i++].n)
{
if(r < npl[i].p) // remaining vlaue is smaller than current percentage
{
res = npl[i].n;
break;
}
}
You could populate a List<T> with the appropriate number of each of the 3 numbers, and then randomize the List.

Evenly divide in c#

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.

Categories

Resources