C# program for printing out copies - c#

My program is taking 2 dollars for each printed copy for the first 100 papers that is copied out. If the user prints out more than a hundread copies, for each copy that is above hundread it takes 1dollar per copy (So if I want to print out 101 copies, the price should be 200 + 1, 1 dollar for the 101:th copy and 2 dollars each for the first 100 copies). Here is my Code:
int CopyCost = 2;
int ammountOfCopies;
int discount = 1;
Console.WriteLine("How many copies would you like?: ");
ammountOfCopies = int.Parse(Console.ReadLine());
for (int i = 0; i < ammountOfCopies; i++)
{
if (ammountOfCopies > 100)
CopyCost = 2 - discount;
else
CopyCost = 2;
CopyCost *= ammountOfCopies;
}
Console.WriteLine("The total cost for your copies is: {0} ", CopyCost);
Console.ReadLine();
But the problem I have is, if I choose to write out 101 copies, it discounts every copy to 1 dollar, and not only the one above 100.

This is more a math problem than a coding one. You need to take the amount of copies at or below 100 and multiply it with the normal price. Then take the amount of copies over 100 and multiply with the discounted price. No need for the for loop.
Break the problem into small pieces in the code, for instance, like so:
int price = 2;
int discountedPrice = price - 1;
int amountAtNormalPrice = Math.Min(amountOfCopies, 100);
int amountAtDiscountPrice = Math.Max(amountOfCopies - 100, 0);
int amountTotal = (amountAtNormalPrice * price) + (amountAtDiscountedPrice * discountedPrice);

You are looping over each of your copies (numberOfCopies, btw, not amountOfCopies) and applying the calculation each time. You should calculate directly instead; there's no need for a loop in this situation:
if (numberOfCopies > 100)
{
CopyCost = 200 + (numberOfCopies - 100);
}
else
{
CopyCost = 2 * numberOfCopies;
}

Better, use this code:
int TotalCost;
if (amountOfCopies > 100)
{
TotalCost = (amountOfCopies - 100) * (CopyCost - discount) + 100 * CopyCost;
}
else
{
TotalCost = amountOfCopies * CopyCost;
}
Console.WriteLine("The total cost for your copies is: {0} ", TotalCost);

Or if you prefer a one-liner:
price = (copies * 2) - Math.Max(copies - 100, 0);

Related

How to divide a decimal number into rounded parts that add up to the original number?

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
}

Can't print my result outside of for loop in C#

I'm very new to C# and this exercise has been bugging me for a bit. The basic idea is I get an input of a number of Pheonix and need to read body length, width and length of wing for each one in order to calculate the amount of years they live. I created a for loop to read all the parameters, but I just don't know how to post the result at the end without having it output after every cycle. For example I have an input of:
2 phoenixes:
P1:
Body length: 100
Body width: 50
Length of 1 wing: 30
Total years: 100 ^ 2 * (50 + 2 * 30) = 1100000
P2:
Body length: 150
Body width: 25
Length of 1 wing: 10
Total years: 150 ^ 2 * (25 + 2 * 10) = 1012500
-- And I'm supposed to get the output:
2 100 50 30 150 25 10 1100000 1012500.
Instead I get the output:
2 100 50 30 1100000 1012500 150 25 10 1100000 1012500.
How do I avoid this?
int pheonixamount = int.Parse(Console.ReadLine());
for (int i = 0; i < pheonixamount; i++)
{
List<double> pheonix = new List<double>(3);
double bodylength = double.Parse(Console.ReadLine());
double bodywidth = double.Parse(Console.ReadLine());
double lengthof1wing = double.Parse(Console.ReadLine());
pheonix.Add(bodylength);
pheonix.Add(bodywidth);
pheonix.Add(lengthof1wing);
double result = Math.Pow(bodylength, 2) * (bodywidth + 2 * lengthof1wing);
Console.WriteLine(result);
}
It's right time to declare Phoenix class:
public class Phoenix {
public Phoenix(double bodyLength,
double bodyWidth,
double lengthWidth) {
if (bodyLength < 0)
throw new ArgumentOutOfRangeException(nameof(bodyLength));
else if (bodyWidth < 0)
throw new ArgumentOutOfRangeException(nameof(bodyWidth));
else if (lengthWidth < 0)
throw new ArgumentOutOfRangeException(nameof(lengthWidth));
BodyLength = bodyLength;
BodyWidth = bodyWidth;
LengthWidth = lengthWidth;
}
public double BodyLength {get;}
public double BodyWidth {get;}
public double LengthWidth {get;}
public double TotalYears {
get {
return BodyLength * BodyLength * (BodyWidth + 2 * LengthWidth);
}
}
public override string ToString() {
return $"{BodyLength} {BodyWidth} {LengthWidth}";
}
}
Now let's read all phoenixes into a collection (List<Phoenix>):
int pheonixamount = int.Parse(Console.ReadLine());
List<Phoenix> phoenixes = new List<Phoenix>();
for (int i = 0; i < pheonixamount; i++) {
Phoenix bird = new Phoenix(
double.Parse(Console.ReadLine()),
double.Parse(Console.ReadLine()),
double.Parse(Console.ReadLine())
);
phoenixes.Add(bird);
}
Finally, let's make a report based on phoenixes collection:
string report = string.Join(" ",
// 2 - number of phoenixes
phoenixes.Count().ToString(),
// phoenixes' exteriers (lengths and widths)
string.Join(" ", phoenixes),
// phoenixes' total years - a pinch of Linq - Select
string.Join(" ", phoenixes.Select(item => item.TotalYears))
);
Console.Write(report);
Instead of writing result in same loop use another loop to print all values on console.
As per your desired output you need to use Console.Write() not Console.WriteLine()
Your code create new list after each iteration in for loop, take that out of for loop
int pheonixamount = int.Parse(Console.ReadLine());
List<double> pheonix = new List<double>(pheonixamount); //Use pheonixamount instead of constant value
List<double> resultList = new List<double>(pheonixamount);
for (int i = 0; i < pheonixamount; i++)
{
double bodylength = double.Parse(Console.ReadLine());
double bodywidth = double.Parse(Console.ReadLine());
double lengthof1wing = double.Parse(Console.ReadLine());
//Best way to store three values is to create new class, instead of storing in three different variables
pheonix.Add(bodylength);
pheonix.Add(bodywidth);
pheonix.Add(lengthof1wing);
double result = Math.Pow(bodylength, 2) * (bodywidth + 2 * lengthof1wing);
resultList(result);
}
//Print your pheonix values
for (int i = 0; i < pheonixamount; i +=3)
{
//i, i+1, i+2 will give you bodyLength, bodyWidth, lengthof1wing respectively
Console.Write(pheonix[i] +" "+ pheonix[i+1] +" "+ pheonix[i+2]);
}
//Print your result
foreach (var item in resultList)
{
Console.Write(item);
}
}

Linear regression gradient descent using C#

I'm taking the Coursera machine learning course right now and I cant get my gradient descent linear regression function to minimize. I use: one dependent variable, an intercept, and four values of x and y, therefore the equations are fairly simple. The final value of the Gradient Decent equation varies wildly depending on the initial values of alpha and beta and I cant figure out why.
I've only been coding for about two weeks, so my knowledge is limited to say the least, please keep this in mind if you take the time to help.
using System;
namespace LinearRegression
{
class Program
{
static void Main(string[] args)
{
Random rnd = new Random();
const int N = 4;
//We randomize the inital values of alpha and beta
double theta1 = rnd.Next(0, 100);
double theta2 = rnd.Next(0, 100);
//Values of x, i.e the independent variable
double[] x = new double[N] { 1, 2, 3, 4 };
//VAlues of y, i.e the dependent variable
double[] y = new double[N] { 5, 7, 9, 12 };
double sumOfSquares1;
double sumOfSquares2;
double temp1;
double temp2;
double sum;
double learningRate = 0.001;
int count = 0;
do
{
//We reset the Generalized cost function, called sum of squares
//since I originally used SS to
//determine if the function was minimized
sumOfSquares1 = 0;
sumOfSquares2 = 0;
//Adding 1 to counter for each iteration to keep track of how
//many iterations are completed thus far
count += 1;
//First we calculate the Generalized cost function, which is
//to be minimized
sum = 0;
for (int i = 0; i < (N - 1); i++)
{
sum += Math.Pow((theta1 + theta2 * x[i] - y[i]), 2);
}
//Since we have 4 values of x and y we have 1/(2*N) = 1 /8 = 0.125
sumOfSquares1 = 0.125 * sum;
//Then we calcualte the new alpha value, using the derivative of
//the cost function.
sum = 0;
for (int i = 0; i < (N - 1); i++)
{
sum += theta1 + theta2 * x[i] - y[i];
}
//Since we have 4 values of x and y we have 1/(N) = 1 /4 = 0.25
temp1 = theta1 - learningRate * 0.25 * sum;
//Same for the beta value, it has a different derivative
sum = 0;
for (int i = 0; i < (N - 1); i++)
{
sum += (theta1 + theta2 * x[i]) * x[i] - y[i];
}
temp2 = theta2 - learningRate * 0.25 * sum;
//WE change the values of alpha an beta at the same time, otherwise the
//function wont work
theta1 = temp1;
theta2 = temp2;
//We then calculate the cost function again, with new alpha and beta values
sum = 0;
for (int i = 0; i < (N - 1); i++)
{
sum += Math.Pow((theta1 + theta2 * x[i] - y[i]), 2);
}
sumOfSquares2 = 0.125 * sum;
Console.WriteLine("Alpha: {0:N}", theta1);
Console.WriteLine("Beta: {0:N}", theta2);
Console.WriteLine("GCF Before: {0:N}", sumOfSquares1);
Console.WriteLine("GCF After: {0:N}", sumOfSquares2);
Console.WriteLine("Iterations: {0}", count);
Console.WriteLine(" ");
} while (sumOfSquares2 <= sumOfSquares1 && count < 5000);
//we end the iteration cycle once the generalized cost function
//cannot be reduced any further or after 5000 iterations
Console.ReadLine();
}
}
}
There are two bugs in the code.
First, I assume that you would like to iterate through all the element in the array. So rework the for loop like this: for (int i = 0; i < N; i++)
Second, when updating the theta2 value the summation is not calculated well. According to the update function it should be look like this: sum += (theta1 + theta2 * x[i] - y[i]) * x[i];
Why the final values depend on the initial values?
Because the gradient descent update step is calculated from these values. If the initial values (Starting Point) are too big or too small, then it will be too far away from the final values (Final Value). You could solve this problem by:
Increasing the iteration steps (e.g. 5000 to 50000): gradient descent algorithm has more time to converge.
Decreasing the learning rate (e.g. 0.001 to 0.01): gradient descent update steps are bigger, therefore it converges faster. Note: if the learning rate is too small, then it is possible to step through the global minimum.
The slope (theta2) is around 2.5 and the intercept (theta1) is around 2.3 for the given data. I have created a github project to fix your code and i have also added a shorter solution using LINQ. It is 5 line of codes. If you are curious check it out here.

How to round up to the higher 10 in 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;

Overcoming a discrepancy in a division

I have the following code to divide an amount by a number and allocate the result as an amount that needs to be paid per month.
objData.month_per_amount = (Convert.ToDecimal(txtAmount.Value) / Convert.ToInt32(txtMonths.Value));
In a scenario example if I divide 13 by 3 and round off the result to 2 decimal places I get 4.33 for each month. But when I multiply 4.33 by 3 I am getting 12.99, which is not equivalent to 13. There is a discrepancy of 0.01. In this scenario how can I allocate like below:
month 1: 4.33
month 2: 4.33
month 3: 4.34
Hope I made it clear, the preferred code should only be executed if there is such a discrepancy, for example if 14 is to be divided by 2, we get 7 for each month and 7+7=14, so exactly the same figure we are getting here.
In accounting you'd often use something called 'reducing balance' for this. The idea is that you calculate the month's total, deduct it from the overall total and reduce the number of months. So something like:
decimal balance = 13m;
int months = 3;
int monthsRemaining = 3;
for (var i = 0; i < months; i++)
{
decimal thisMonth = Math.Round(balance / monthsRemaining, 2);
balance -= thisMonth;
monthsRemaining -= 1;
Console.WriteLine("Month {0}: {1}", i + 1, thisMonth);
}
This will result in 4.33, 4.34, 4.33.
The benefit of this method is that the rounding errors are distributed fairly evenly throughout the period rather than all in one month. For example, 100 over 24 months using that method would result in 23 payments of 4.17 and 1 of 4.09 whereas reducing balance would be 4.16 or 4.17 each month.
You do not have to check the remainder. A more efficient C# code (in terms of the required computation) would be like the following.
double amount = 13;
int months = 3;
int precision = 2;
double[] amountForEachMonth = new double[months];
double temp = Math.Round(amount / months, precision);
for (int i = 0 ; i < months - 1 ; i++)
amountForEachMonth[i] = temp;
amountForEachMonth[months - 1] = amount - (temp * (months - 1)) ;
You don't need to make it a special case when there is a discrepancy, you can simply always calculate the payment of the last month as what's left to pay to reach the total amount. If there is no discrepancy then it will be the same value anyway. Example:
int months = Convert.ToInt32(txtMonths.Value);
decimal amount = Convert.ToDecimal(txtAmount.Value);
month_per_amount = Decimal.Round(amount / months, 2);
decimal last_month = amount - (months - 1) * month_per_amount;
for (int month = 1; month <= months; month++) {
decimal monthly = month < months ? month_per_amount : last_month;
Console.WriteLine("Month {0}: {1}", month, monthly);
}
if " amount % month == 0 " , no discrepancy occures. otherwise, the last item should be a little more than others .
(The code here may have some syntax issues, I wanted to show you the algorithm.)
decimal amount = Convert.ToDecimal(txtAmount.Value);
int month = Convert.ToInt32(txtMonths.Value);
int n = 3;
decimal amounts[3];//n = 3
for (int i = 0 ; i < n-1 ; i++)
amounts[i] = amount / month;
if ( amount % month != 0 ) {
amounts[n-1] = amount - ( amount / month * (n-1) ) ;
else
amounts[n-1] = amount / month ;

Categories

Resources