A logic bug in my C# code, what should I do? - c#

I have a logical error. I provided the following as input:
the salary is 30000
the child n° is 9
So the the net salary will be:
the family bonus + salary - tax
(750) + (30000) - (3000)
but my program count them as
(1500) + (30000) + (6000)
My program doubled (accumulated) the family bonus and the tax. Can anyone explain why?
class Program
{
static void Main(string[] args)
{
Employee e = new Employee();
e.ReadEmployee();
e.PrintEmployee();
}
}
class Employee
{
private string n;
private int byear;
private double sal;
private bool gen;
private bool mar;
private int child;
public static double tax = 0;
public static double familybonus = 0;
public string Ename
{
get { return this.n; }
set
{
this.n = value;
}
}
public int Birthyear
{
get { return this.byear; }
set
{
if (value >= 1970 && value <= 1990) this.byear = value;
else this.byear = 0;
}
}
public double Salary
{
get { return this.sal; }
set
{
if (value >= 5000 && value <= 50000) this.sal = value;
else this.sal = 0;
}
}
public bool Gender
{
get { return this.gen; }
set { this.gen = value; }
}
public bool Married
{
get { return this.mar; }
set { this.mar = value; }
}
public int NChildren
{
get { return this.child; }
set
{
if (value >= 0 && value <= 12) this.child = value;
else this.child = 0;
}
}
public double getAge()
{
return 2008 - this.Birthyear;
}
public double getNet()
{
double net = getFamilyBonus() + this.Salary - getTax();
return net;
}
public double getFamilyBonus()
{
if (this.Married == true)
familybonus += 300;
if (this.NChildren == 1) familybonus += 200;
else if (this.NChildren == 2) familybonus += 350;
else if (this.NChildren >= 3) familybonus += 450;
return familybonus;
}
public double getTax()
{
if (Salary < 10000)
tax = 0;
if (Salary <= 10000 && Salary >= 20000)
tax += Salary * 0.05;
else tax += Salary * 0.1;
return tax;
}
public void ReadEmployee()
{
Console.Write("Enter Employee Name: ");
Ename = Console.ReadLine();
Console.Write("Enter Employee birth date: ");
Birthyear = int.Parse(Console.ReadLine());
while (Birthyear < 1970 || Birthyear > 1990)
{
Console.WriteLine("Invalid Birthyear!");
Console.Write("Enter Employee Birth date: ");
Birthyear = int.Parse(Console.ReadLine());
}
string g = null;
while (g != "M" && g != "m" && g != "F" && g != "f")
{
Console.Write("Enter Employee Gender (M/F)");
g = Convert.ToString(Console.ReadLine());
}
if (g == "M" || g == "m")
Gender = true;
else
Gender = false;
Console.Write("Enter Employee Salary: ");
Salary = Double.Parse(Console.ReadLine());
while (Salary < 5000 || Salary > 50000)
{
Console.WriteLine("Invalid Salary!");
Console.Write("Enter Employee Salary: ");
Salary = int.Parse(Console.ReadLine());
}
string m = null;
while (m != "true" && m != "True" && m != "false" && m != "False")
{
Console.Write("Married (true/false)");
m = Console.ReadLine();
}
if (m == "true")
this.Married = true;
else
this.Married = false;
Console.Write("Enter Employee Children count: ");
NChildren = int.Parse(Console.ReadLine());
while (NChildren < 0 || NChildren > 12)
{
Console.WriteLine("Invalid NChildren!");
Console.Write("Enter Employee Children count: ");
NChildren = int.Parse(Console.ReadLine());
}
}
public void PrintEmployee()
{
Console.Write("Hello ");
{
if (Gender == true)
Console.Write("Mr. ");
else
Console.Write("Mrs. ");
Console.WriteLine(Ename);
}
Console.WriteLine("You are {0} years old", getAge());
Console.WriteLine("Salary= {0}", Salary);
Console.WriteLine("Tax= {0}", getTax());
Console.WriteLine("Family bonus= {0}", getFamilyBonus());
Console.WriteLine("Net= {0}", getNet());
}
}

I took the existing code, and hard-wired the inputs (rather than using Console.ReadLine()), I get:
You are 28 years old Salary= 30000
Tax= 3000 Family bonus= 750 Net= 25500
The main problem seems to be not initializing values - i.e. treating fields as variables:
public double getTax()
{
if (Salary < 10000)
tax = 0;
if (Salary <= 10000 && Salary >= 20000)
tax += Salary * 0.05;
else tax += Salary * 0.1;
return tax;
}
OK - and what does tax start at if Salary >= 10000, etc. Likewise familyBouns in getFamilyBonus. By the way, how can Salary be both <= 10000 and >= 20000?
To illustrate, I've changed the output to:
Console.WriteLine("Tax= {0}", getTax());
Console.WriteLine("Tax= {0}", getTax());
Console.WriteLine("Tax= {0}", getTax());
Which shows:
Tax= 3000 Tax= 6000 Tax= 9000
My advice would be: don't store calculated values unless you know the math is so complex that it is worth it. Just calculate them as needed (no field at all).

Another problem seems to lie in the fact that you don't initialize familybonus when you say familybonus += 300. So everytime you call GetFamilybonus it's added to the previous result. You call it twice in the PrintEmployee function, once directly and once indirectly by calling getNet;

Related

Talent show program in C# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I need some help with this program I got from a programming website, I am still new to programming and this seems like too much for me right now. I don't even know where to begin with this program:
In one of the last problems, you created the most recent version of the GreenvilleRevenue program, which prompts the user for contestant data for this year’s Greenville Idol competition. Now, save all the entered data to a Greenville.ser file(this is provided by the website) that is closed when data entry is complete and then reopened and read in, allowing the user to view lists of contestants with requested talent types. The program should output the name of the contestant, the talent, and the fee.
using System;
using static System.Console;
class GreenvilleRevenue
{
static void Main()
{
const int MIN_CONTESTANTS = 0;
const int MAX_CONTESTANTS = 30;
int num;
int revenue = 0;
const char QUIT = 'Z';
char option = ' ';;
Contestant[] contestants = new Contestant[MAX_CONTESTANTS];
num = getContestantNumber(MIN_CONTESTANTS, MAX_CONTESTANTS);
revenue = getContestantData(num, contestants, revenue);
WriteLine("\n\nRevenue expected this year is {0}", revenue.ToString("C"));
while(option != QUIT)
option = getLists(num, contestants);
}
private static int getContestantNumber(int min, int max)
{
string entryString;
int num = max + 1;
Write("Enter number of contestants >> ");
entryString = ReadLine();
while(num < min || num > max)
{
if(!int.TryParse(entryString, out num))
{
WriteLine("Format invalid");
num = max + 1;
Write("Enter number of contestants >> ");
entryString = ReadLine();
}
else
{
try
{
if(num < min || num > max)
throw(new ArgumentException());
}
catch(ArgumentException e)
{
WriteLine(e.Message);
WriteLine("Number must be between {0} and {1}", min, max);
num = max + 1;
Write("Enter number of contestants >> ");
entryString = ReadLine();
}
}
}
return num;
}
private static int getContestantData(int num, Contestant[] contestants, int revenue)
{
const int ADULTAGE = 17;
const int TEENAGE = 12;
int x = 0;
string name;
char talent;
int age;
int pos;
while(x < num)
{
Write("Enter contestant name >> ");
name = ReadLine();
WriteLine("Talent codes are:");
for(int y = 0; y < Contestant.talentCodes.Length; ++y)
WriteLine(" {0} {1}", Contestant.talentCodes[y], Contestant.talentStrings[y]);
Write(" Enter talent code >> ");
char.TryParse(ReadLine(), out talent);
try
{
validateCode(talent, out pos);
}
catch(ArgumentException e)
{
WriteLine(e.Message);
WriteLine("{0} is not a valid code. Assigned as Invalid.", talent);
}
Write(" Enter contestant's age >> ");
int.TryParse(ReadLine(), out age);
if(age > ADULTAGE)
contestants[x] = new AdultContestant();
else
if(age > TEENAGE)
contestants[x] = new TeenContestant();
else
contestants[x] = new ChildContestant();
contestants[x].Name = name;
contestants[x].TalentCode = talent;
revenue += contestants[x].Fee;
++x;
}
return revenue;
}
private static char getLists(int num, Contestant[] contestants)
{
int x;
char QUIT = 'Z';
char option = ' ';
bool isValid;
int pos = 0;
bool found;
WriteLine("\nThe types of talent are:");
for(x = 0; x < Contestant.talentStrings.Length; ++x)
WriteLine("{0, -6}{1, -20}", Contestant.talentCodes[x], Contestant.talentStrings[x]);
Write("\nEnter a talent type or {0} to quit >> ", QUIT);
isValid = false;
while(!isValid)
{
if(!char.TryParse(ReadLine(), out option))
{
isValid = false;
WriteLine("Invalid format - entry must be a single character");
Write("\nEnter a talent type or {0} to quit >> ", QUIT);
}
else
{
if(option == QUIT)
isValid = true;
else
{
try
{
validateCode(option, out pos);
isValid = true;
}
catch(ArgumentException e)
{
WriteLine(e.Message);
WriteLine("{0} is not a valid code", option);
Write("\nEnter a talent type or {0} to quit >> ", QUIT);
isValid = false;
}
}
if(isValid && option != QUIT)
{
WriteLine("\nContestants with talent {0} are:", Contestant.talentStrings[pos]);
found = false;
for(x = 0; x < num; ++x)
{
if(contestants[x].TalentCode == option)
{
WriteLine(contestants[x].ToString());
found = true;
}
}
if(!found)
{
WriteLine("No contestants had talent {0}", Contestant.talentStrings[pos]);
isValid = false;
Write("\nEnter a talent type or {0} to quit >> ", QUIT);
}
}
}
}
return option;
}
public static void validateCode(char option, out int pos)
{
bool isValid = false;
pos = Contestant.talentCodes.Length - 1;
for(int z = 0; z < Contestant.talentCodes.Length; ++z)
{
if(option == Contestant.talentCodes[z])
{
isValid = true;
pos = z;
}
}
if(!isValid)
throw(new ArgumentException());
}
}
class Contestant
{
public static char[] talentCodes = {'S', 'D', 'M', 'O'};
public static string[] talentStrings = {"Singing", "Dancing",
"Musical instrument", "Other"};
public string Name {get; set;}
private char talentCode;
private string talent;
private int fee;
public char TalentCode
{
get
{
return talentCode;
}
set
{
int pos = talentCodes.Length;
for(int x = 0; x < talentCodes.Length; ++x)
if(value == talentCodes[x])
pos = x;
if(pos == talentCodes.Length)
{
talentCode = 'I';
talent = "Invalid";
}
else
{
talentCode = value;
talent = talentStrings[pos];
}
}
}
public string Talent
{
get
{
return talent;
}
}
public int Fee
{
get
{
return fee;
}
set
{
fee = value;
}
}
}
class AdultContestant : Contestant
{
public int ADULT_FEE = 30;
public AdultContestant()
{
Fee = ADULT_FEE;
}
public override string ToString()
{
return("Adult Contestant " + Name + " " + TalentCode + " Fee " + Fee.ToString("C"));
}
}
class TeenContestant : Contestant
{
public int TEEN_FEE = 20;
public TeenContestant()
{
Fee = TEEN_FEE;
}
public override string ToString()
{
return("Teen Contestant " + Name + " " + TalentCode + " Fee " + Fee.ToString("C"));
}
}
class ChildContestant : Contestant
{
public int CHILD_FEE = 15;
public ChildContestant()
{
Fee = CHILD_FEE;
}
public override string ToString()
{
return("Child Contestant " + Name + " " + TalentCode + " Fee " + Fee.ToString("C"));
}
}
I agree with Mark's opinion, as well as the others who have up-voted his comment.
I wouldn't wait on someone to post a solution to your question so I'll go ahead and give you some things to get started on your own research and solution.
(Most of this is already in your problem statement, just broken down)
Start with the existing code you've pasted in
Read it line by line and google/textbook/stackoverflow ANYTHING you don't understand. Get a general understanding, and go deep if you have time.
Learn how to save data to a file in C#
Learn how to load data from a file in C#
Find a place in the code for the save data logic. (after data entry)
Run load data logic after save data logic
Display what was loaded
Edit: As you do research, you'll find lots of stackoverflow posts with good answers. Follow the format for those questions (prior research, attempted solutions, specific question, small code snippets) in order to ask more engaging questions yourself.

Dictionary.Count is not working as expected

The following line of code is not working as expected: If there are two dictionary entries it prints "2, 2" instead of "1, 2"
Console.WriteLine($"Student: {studentMap.Count} - Average Score: {average} - Letter Grade: {GetLetterGrade(average)}");
It is not listing the dictionary count like this line ↓↓↓ of code above it in the other for-loop.
Console.WriteLine($"Enter test {studentScores.Count + 1 } for student {studentMap.Count + 1 }");
namespace Program
{
class Program
{
static void Main(string[] args)
{
string totalStudents = string.Empty;
while (!IsNumeric(totalStudents))
{
Console.WriteLine("How many students will you be grading?");
totalStudents = Console.ReadLine();
if (!IsNumeric(totalStudents))
{
Console.WriteLine(string.Empty);
Console.WriteLine("Error! Please enter numeric value.");
}
}
int studentCount = Convert.ToInt32(totalStudents);
Console.WriteLine(string.Empty);
string totalScores = string.Empty;
while (!IsNumeric(totalScores))
{
Console.WriteLine("How many test scores will you enter for each student?");
totalScores = Console.ReadLine();
if (!IsNumeric(totalScores))
Console.WriteLine("Please enter a numeric value.");
}
int scoreCount = Convert.ToInt32(totalScores);
Dictionary<int, List<int>> studentMap = new Dictionary<int, List<int>>();
for (int students = 0; students < studentCount; students++)
{
List<int> studentScores = new List<int>();
for (int scores = 0; scores < scoreCount; scores++)
{
string scoreInput = string.Empty;
Console.WriteLine(string.Empty);
Console.WriteLine($"Enter test {studentScores.Count + 1 } for student {studentMap.Count + 1 }");
scoreInput = Console.ReadLine();
Console.WriteLine(string.Empty);
Console.WriteLine("--------------------");
int intScore = Convert.ToInt32(scoreInput);
studentScores.Add(intScore);
}
studentMap.Add(students, studentScores);
}
Console.WriteLine("The test results are as follows:");
Console.WriteLine(string.Empty);
for (int i = 0; i < studentMap.Count; i++)
{
List<int> studentScores = studentMap[i];
double scoreSum = studentScores.Sum();
double scoreNum = studentScores.Count();
double average = scoreSum / scoreNum;
Console.WriteLine($"Student: {studentMap.Count} - Average Score: {average} - Letter Grade: {GetLetterGrade(average)}");
}
Console.WriteLine();
Console.ReadLine();
}
static string GetLetterGrade(double average)
{
if (average >= 90)
{
return "A";
}
else if (average >= 80)
{
return "B";
}
else if (average >= 70)
{
return "C";
}
else if (average >= 60)
{
return "D";
}
else
{
return "F";
}
}
static double GetAverage(double sum, double count)
{
return sum / count;
}
static bool IsNumeric(string input)
{
int result;
return int.TryParse(input, out result);
}
}
}
You probably misunderstood the terms Dictionary<>.Count and index. Indexes start at 0 and Count property represents the number of items in the dictionary.
So, if you have 1 item in your Dictionary<>, it's index is 0 and Dictionary<>.Count is 1.

Student class and Menu class not working

this is Students.cs
It is showing an error "NullReferenceException was unhandled" at line ---- Console.WriteLine("Student{0}: {1}, {2:P} {3}", i+1, stuList[i].studentName,stuList[i].studentPercentage, stuList[i].studentLetterGrade);
Can I get help finding the error with this two classes
private static int studentCount = 0;
// Instance variables go here
private string studentName;
private double studentPercentage;
private string studentLetterGrade;
private Grade test = new Grade(0);
private Grade hwQz = new Grade(700);
//Default Constructor Method
public Student()
{
}//end of Student Constructor method
public Student(string name)
{
//if(name.Length == 0)
SetStudentName("Jane Doe");
//else
//SetStudentName(name);
}//end of Overloaded Constructor method
public Student(string name, int percent, string letter)
{
SetStudentName(name);
SetStudentPercent(percent);
SetStudentLetter(letter);
}//end of Overloaded Constructor method
//Class Methods
// retrieve the student count
public static int GetStudentCount()
{
return studentCount;
}//end of GetStudentCount method
// set the student count
public static void SetStudentCount(int newStudentCount)
{
studentCount = newStudentCount;
}//end of SetStudentCount method
// list students
public static void ListStudents(Student[] stuList)
{
//Clear Screen
Console.Clear();
for (int i = 0; i < studentCount; i++)
{
Console.WriteLine("Student{0}: {1}, {2:P} {3}", i+1, stuList[i].studentName,stuList[i].studentPercentage, stuList[i].studentLetterGrade);
}
}
// Instance methods go here
// retrieve the Student name
public string GetStudentName()
{
return studentName;
}//end of GetStudentName method
// set the Student name
public void SetStudentName(string newName)
{
studentName = newName;
}//end of SetStudentName method
// retrieve the Student percent
public double GetStudentPercent()
{
return studentPercentage;
}//end of GetStudentPercent method
// set the Student address
public void SetStudentPercent(double newPercent)
{
studentPercentage = newPercent;
}//end of SetStudentPercent method
// retrieve the Student Letter
public string GetStudentLetter()
{
return studentLetterGrade;
}//end of GetStudentLetter method
// set the Student letter
public void SetStudentLetter(string newLetter)
{
studentLetterGrade = "A+";
}//end of SetStudentLetter method
public void EnterStudentScores()
{
test.EnterScores("Test");
hwQz.EnterScores("Homework & Quiz");
//Store the overall score in a temp variable
double gradePercent = ((50 * test.GetGradePercent()) + (50 * hwQz.GetGradePercent()));
//Using typecasting to force a double into an int data type
SetStudentPercent(gradePercent);
SetStudentLetter(test.GetLetterGrade(gradePercent));
}
}
}
The above Students.cs is connected with Menu.cs
bool runApp = true;
Student[] students = new Student[35];
//Application loop
while (runApp)
{
Console.Clear();
Console.WriteLine("\n\tGrade Book Menu\n");
Console.WriteLine("\t1) Add Student");
Console.WriteLine("\t2) Enter Student Grades");
Console.WriteLine("\t3) List Student Grades");
Console.Write("\nEnter Selection or Press Escape to exit: ");
ConsoleKeyInfo key = Console.ReadKey();
if (key.Key == ConsoleKey.Escape)
{
runApp = false;
}
else
{
switch (key.Key)
{
case ConsoleKey.NumPad1:
case ConsoleKey.D1:
//Get the current student count stored in the Student Class variable
int indexForNewStudent = Student.GetStudentCount();
indexForNewStudent = 0;
Console.Write("\nEnter Student Name: ");
//Instantiate a Student object and place it in the array of Student objects called student
students[indexForNewStudent] = new Student(Console.ReadLine()); //Call overloaded constructor
//Increment Student count
Student.SetStudentCount(indexForNewStudent + 2); //Add to index to account for new student
break;
case ConsoleKey.NumPad2:
case ConsoleKey.D2:
Console.WriteLine("\nEnter the Student Number. Use List Students to get Student Number.");
int studentNumber = 0; //Temporary variable to hold the student number to enter grades
//Test the entered string is a number and between 1 and 30
if ((int.TryParse(Console.ReadLine(), out studentNumber)) && (studentNumber >= 1) &&
(studentNumber <= 30))
{
//In the event a student has not been added this code will crash
if (Student.GetStudentCount() > 0) //Has a student been added?
students[studentNumber - 1].EnterStudentScores(); //Subtract 1 from enterd number for array index
else
Console.WriteLine("A student has not been added");
}
else
{
Console.WriteLine("Invalid Student Number. Enter a number from 1 to 30");
}
break;
case ConsoleKey.NumPad3:
case ConsoleKey.D3:
Student.ListStudents(students);
break;
default:
Console.WriteLine("Invalid Menu Selection");
break;
}
Console.Write("Press a key to return to Menu");
Console.ReadKey();
}
}
Console.Write("\nExiting Application. Press any key to close window... ");
Console.ReadKey();
}
}
}
This code is also connect with the following Grade.cs
private double[] earnedScores = new double[30];
private double pointTotal = 0;
private int scoresEntered = 0;
public Grade()
{
}
public Grade(double total)
{
pointTotal = total;
}
public void SetPointTotal(int total)
{
pointTotal = (double)total; //using double to type cast an int into a double
}
public void SetPointTotal(double total) // Overloaded method for SetPointTotal
{
pointTotal = total;
}
public void EnterScores(string scoreType)
{
//Loop that lets the user enter up to 30 scores
//the loop ends after 30 entries or Q is pressed
do
{
Console.Clear(); //Clear screen
//scoreType is a string passed in that prints to the screen to help user know what scores are being entered
Console.WriteLine("{0} Scores", scoreType);
Console.WriteLine("Enter up to {0} scores or Q to quit.", earnedScores.Length);
Console.Write("Enter score{0}: ", scoresEntered + 1);
string input = Console.ReadLine();
//Validate user entered string stored in input.
//Return -2 if Q was pressed and -1 if the string is invalid
double inputNumber = ValidateScore(input);
if (inputNumber == -1)
{
Console.WriteLine("Invalid entry. Please enter a valid positive score.");
Console.ReadKey();
}
else if (inputNumber == -2)
{
break;
}
else
{
earnedScores[scoresEntered] = inputNumber;
scoresEntered++;
}
} while(scoresEntered < earnedScores.Length);
}
public void DisplayScore(string scoreType)
{
//scoreType is a string passed in that prints to the screen to help user know what scores are being displayed
Console.WriteLine("{0} Scores", scoreType);
//Loop thru the earnedScores array and print each element's value
for (int i = 0; i < scoresEntered; i++)
{
Console.WriteLine("Score{0}: {1}", i + 1, earnedScores[i]);
}
}
public double ValidateScore(string inText)
{
int dotCount = 0; //Variable to hold the count of decimals
char[] temp = inText.ToCharArray(); //char array to hold incoming string
if (inText.Length > 0) //text is not blank if length greater than zero
{
for (int i = 0; i < inText.Length; i++) //loop thru each character and test contents
{
if (temp[i] == '.') //is it a decimal
{
dotCount += 1; //dotCount++; does the same thing
if (dotCount > 1) //More than 1 decimal invalid
return -1;
}
else if (temp[i] == '-') //if Negative sign
{
if (i != 0) //If Negative is not 1st element of array then invalid
return -1;
}
else if (!char.IsNumber(temp[i])) //If character is not a number
{
if (temp[i] == 'Q' || temp[i] == 'q') //If Q or q then exit loop
{
return -2;
}
else //Any other letter invalid
{
return -1;
}
}
}
}
else
{
return -1; //Blank was entered
}
return Convert.ToDouble(inText);
}
public double GetGradePercent()
{
double totalEarnedPoints = 0; //Start with zero
//Add all elements of the array to total
for (int i = 0; i < scoresEntered; i++)
{
totalEarnedPoints += earnedScores[i];
}
//Return grade percentage by dividing earned points by total points
return totalEarnedPoints / pointTotal;
}
public string GetLetterGrade(double percentage)
{
//Incoming parameter will be in decimal format. Example 90% will be 0.90
percentage *= 100; //Multiply incoming percentage by 100 to move decimal point scaling number from 0 to 100
if (percentage >= 97.0)
{
return "A+";
}
else if ((percentage < 97) && (percentage >= 93))
{
return "A";
}
else if ((percentage < 93) && (percentage >= 90))
{
return "A-";
}
else if ((percentage < 90) && (percentage >= 87))
{
return "B+";
}
else if ((percentage < 87) && (percentage >= 83))
{
return "B";
}
else if ((percentage < 83) && (percentage >= 80))
{
return "B-";
}
else if ((percentage < 80) && (percentage >= 77))
{
return "C+";
}
else if ((percentage < 77) && (percentage >= 70))
{
return "C";
}
else if ((percentage < 70) && (percentage >= 60))
{
return "D";
}
else
{
return "E";
}
}
public void ClearScores()
{
scoresEntered = 0; //Clear number of scores previously entered
//Reset all elements of the array back to zero
for (int i = 0; i < earnedScores.Length; i++)
{
earnedScores[i] = 0.0;
}
}
}
}
In your add student code you have a couple of problems
indexForNewStudent = 0;
This means you will always be overwriting the first student rather than adding a new one.
//Increment Student count
Student.SetStudentCount(indexForNewStudent + 2); //Add to index to account for new student
The +2 here means that your student count will be 1 greater than the number of students, meaning that the ListStudents function will then try to access a student that hasn't been added yet. It should be +1

Fractions in a NumericUpDown/DomainUpDown

Is it possible to display fractions in a NumericUpDown or a DomainUpDown?
I know there are some fonts that have various fraction characters, but I would like to keep my form using Microsoft Sans Serif uniformly.
What do you mean by upto one-tenth.
I have a sample code for you, try if it works for you
nupdwn.Minimum = -10;
nupdwn.Maximum = 10;
nupdwn.Increment = 0.25;
nupdwn.DecimalPlaces = 2;
Microsoft Sans Serif does support fractional characters:
I will try to program a derived NumericUpDown to show fractional values. If it succeeds, i will share the code here...
Here is my Sample-Code for a FractionalUpDown.
Be sure to set DecimalPlaces to your needs.
With Mode, you can choose the formatting of the value:
EMode.Decimal => 2,500.
EMode.Fractional => ⁵⁄₂
EMode.FractionalMixed => 2 ¹⁄₂
EMode.FractionalASCII => 5/2
EMode.FractionalMixedASCII => 2 1/2
Code:
public class FractionalUpDown: NumericUpDown {
//Hide Hexadecimal
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool Hexadecimal {
get { return false; }
set { base.Hexadecimal = false; }
}
private EMode mode;
[DefaultValue(EMode.Fractional)]
public EMode Mode {
get { return mode; }
set {
if (value != mode) {
mode = value;
UpdateEditText();
}
}
}
public enum EMode {
Fractional,
FractionalMixed,
FractionalASCII,
FractionalMixedASCII,
Decimal
}
public FractionalUpDown() {
}
protected override void UpdateEditText() {
if (Mode == EMode.Decimal) {
base.UpdateEditText();
return;
}
double accuracy = Math.Pow(10.0, -(DecimalPlaces + 1));
if (accuracy > 0.1) accuracy = 0.1;
this.Text = FractionToString(DoubleToFraction((double)Value, accuracy), Mode);
}
public struct Fraction {
public Fraction(int n, int d) {
N = n;
D = d;
}
public int N { get; private set; }
public int D { get; private set; }
}
private static readonly char[] numbers = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
private static readonly char[] numerators = new char[10] { '⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹' };
private static readonly char[] denumerators = new char[10] { '₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉' };
protected string FractionToString(Fraction frac, EMode mode) {
int full = 0;
int n = frac.N;
string result = string.Empty;
bool mixed = mode == EMode.FractionalMixed ||
mode == EMode.FractionalMixedASCII;
bool useFractionalChars = mode == EMode.Fractional ||
mode == EMode.FractionalMixed;
if (mixed && Math.Abs(frac.N) >= frac.D) {
full = frac.N / frac.D;
n = Math.Abs(frac.N % frac.D);
if (full != 0) result = full.ToString();
else if (n == 0) return "0";
}
if (n != 0) {
string fracNtext = n.ToString();
string fracDtext = frac.D.ToString();
if (useFractionalChars) {
for (int i = 0; i < 10; i++) fracNtext = fracNtext.Replace(numbers[i], numerators[i]);
for (int i = 0; i < 10; i++) fracDtext = fracDtext.Replace(numbers[i], denumerators[i]);
} else {
if (full != 0) result += " ";
}
result += fracNtext + '⁄' + fracDtext;
} else {
//Fractional Part == 0/?
if (full == 0) {
if (mixed == true) {
return "0";
} else {
if (useFractionalChars) {
return numerators[0].ToString() + '⁄' + denumerators[1].ToString();
} else {
return numbers[0].ToString() + '⁄' + numbers[1].ToString();
}
}
}
}
return result;
}
//Source: https://stackoverflow.com/questions/5124743/algorithm-for-simplifying-decimal-to-fractions/32903747#32903747
protected Fraction DoubleToFraction(double value, double accuracy) {
if (accuracy <= 0.0 || accuracy >= 1.0) {
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
}
int sign = Math.Sign(value);
if (sign == -1) {
value = Math.Abs(value);
}
// Accuracy is the maximum relative error; convert to absolute maxError
double maxError = sign == 0 ? accuracy : value * accuracy;
int n = (int)Math.Floor(value);
value -= n;
if (value < maxError) {
return new Fraction(sign * n, 1);
}
if (1 - maxError < value) {
return new Fraction(sign * (n + 1), 1);
}
// The lower fraction is 0/1
int lower_n = 0;
int lower_d = 1;
// The upper fraction is 1/1
int upper_n = 1;
int upper_d = 1;
while (true) {
// The middle fraction is (lower_n + upper_n) / (lower_d + upper_d)
int middle_n = lower_n + upper_n;
int middle_d = lower_d + upper_d;
if (middle_d * (value + maxError) < middle_n) {
// real + error < middle : middle is our new upper
Seek(ref upper_n, ref upper_d, lower_n, lower_d, (un, ud) => (lower_d + ud) * (value + maxError) < (lower_n + un));
upper_n = middle_n;
upper_d = middle_d;
} else if (middle_n < (value - maxError) * middle_d) {
// middle < real - error : middle is our new lower
Seek(ref lower_n, ref lower_d, upper_n, upper_d, (ln, ld) => (ln + upper_n) < (value - maxError) * (ld + upper_d));
lower_n = middle_n;
lower_d = middle_d;
} else {
// Middle is our best fraction
return new Fraction((n * middle_d + middle_n) * sign, middle_d);
}
}
}
/// <summary>
/// Binary seek for the value where f() becomes false.
/// Source: https://stackoverflow.com/questions/5124743/algorithm-for-simplifying-decimal-to-fractions/32903747#32903747
/// </summary>
protected void Seek(ref int a, ref int b, int ainc, int binc, Func<int, int, bool> f) {
a += ainc;
b += binc;
if (f(a, b)) {
int weight = 1;
do {
weight *= 2;
a += ainc * weight;
b += binc * weight;
}
while (f(a, b));
do {
weight /= 2;
int adec = ainc * weight;
int bdec = binc * weight;
if (!f(a - adec, b - bdec)) {
a -= adec;
b -= bdec;
}
}
while (weight > 1);
}
}
}

Isbn generate the check digit

This code verifies whether an ISBN is valid. For nine-digit inputs, I'd like to form a valid ISBN by calculating and appending the check digit. For inputs less than nine digits, I'd like it to return the error message "Please enter a correct number". How should I go about this?
public class isbn
{ //attributes
private string isbnNum;
//method
public string GetIsbn()
{
return this.isbnNum;
}
//constructor
public isbn()
{
Console.Write("Enter Your ISBN Number: ");
this.isbnNum = Console.ReadLine();
}//end default constructor
//method
public string displayISBN()
{
return this.GetIsbn();
}
public static void Main(string[] args)
{
//create a new instance of the ISBN/book class
isbn myFavoriteBook = new isbn();
//contains the method for checking validity
bool isValid = CheckDigit.CheckIsbn(myFavoriteBook.GetIsbn());
//print out the results of the validity.
Console.WriteLine(string.Format("Your book {0} a valid ISBN",
isValid ? "has" : "doesn't have"));
Console.ReadLine();
}
public static class CheckDigit
{ // attributes
public static string NormalizeIsbn(string isbn)
{
return isbn.Replace("-", "").Replace(" ", "");
}
public static bool CheckIsbn(string isbn) // formula to check ISBN's validity
{
if (isbn == null)
return false;
isbn = NormalizeIsbn (isbn);
if (isbn.Length != 10)
return false;
int result;
for (int i = 0; i < 9; i++)
if (!int.TryParse(isbn[i].ToString(), out result))
return false;
int sum = 0;
for (int i = 0; i < 9; i++)
sum += (i + 1) * int.Parse(isbn[i].ToString());
int remainder = sum % 11;
if (remainder == 10)
return isbn[9] == 'X';
else
return isbn[9] == (char)('0' + remainder);
}
Just change it to append the last character rather than checking that it's present. The above could be cleaned up a bit, but just changing it as required results in:
public static string MakeIsbn(string isbn) // string must have 9 digits
{
if (isbn == null)
throw new ArgumentNullException();
isbn = NormalizeIsbn (isbn);
if (isbn.Length != 9)
throw new ArgumentException();
int result;
for (int i = 0; i != 9; i++)
if (!int.TryParse(isbn[i].ToString(), out result))
throw new ArgumentException()
int sum = 0;
for (int i = 0; i != 9; i++)
sum += (i + 1) * int.Parse(isbn[i].ToString());
int remainder = sum % 11;
if (remainder == 10)
return isbn + 'X';
else
return isbn + (char)('0' + remainder);
}

Categories

Resources