Всем привет! Как мы все знаем иногда, каким то программам нужны дробные числа типа 2/3, 1/3 и тд. Но вот незадача в C# нет стандартной поддержки данных чисел. Так что давайте напишем собственный велосипед для дробных чисел.
Для начала создадим класс Fraction.
Вот заготовка класса Fraction.
class Fraction
{
int numerator ;
int denominator;
public int Numerator
{
get
{
return numerator;
}
set
{
numerator = value;
}
}
public int Denominator
{
get
{
return denominator;
}
set
{
denominator = value;
}
}
public Fraction(int n, int d){
numerator = n;
denominator = d;
}
public Fraction()
{
numerator = 0;
denominator =0;
}
}
Операции с дробями.
Теперь нужно сделать базовые операции, типа( +, -, *, /). Так давайте их сделаем.
Для начала разберемся со сложением, и вычитанием. Думаю все вы со школы знакомы с тем, прежде чем складывать и отнимать дроби их нужно приводить к общему знаменателю. Но встает вопрос а как быстро, красиво, и понятно привести дроби к общему знаменателю. И решение есть, вот этой алгоритм находящий наименьшее общий знаменатель:
public static int NOZ(int den0, int den1)
{
if (den1 % den0 == 0)
return den1;
int temp = 0;
for (int i = 2; ; i++)
{
temp = den1 * i;
if (temp % den0 == 0)
{
break;
}
}
return temp;
}
А дальше с помощью перегрузок операторов реализуем сложение и вычитание дробей. Вот так:
public static Fraction operator+(Fraction a, Fraction b)
{
Fraction fraction = new Fraction(0, NOZ(a.Denominator, b.Denominator) );
fraction.numerator = fraction.denominator / a.Denominator * a.Numerator;
fraction.numerator += fraction.denominator / b.Denominator * b.Numerator;
return fraction;
}
public static Fraction operator -(Fraction a, Fraction b)
{
Fraction fraction = new Fraction(0, NOZ(a.Denominator, b.Denominator));
fraction.numerator = fraction.denominator / a.Denominator * a.Numerator;
fraction.numerator -= fraction.denominator / b.Denominator * b.Numerator;
return fraction;
}
Теперь настала очередь умножения и деления.
Умножение очень просто делается, числитель А перемножается на числитель Б, и знаменатель А на знаменатель Б.
Деление делается перемножением числителем А на знаменатель Б, и знаменатель А на числитель Б.
Также сделаем умножение и деление на обычное число.
Давайте реализуем данные функции.
public static Fraction operator*(Fraction a, Fraction b)
{
Fraction fraction = new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
return fraction;
}
public static Fraction operator*(Fraction a, int b)
{
Fraction fraction = new Fraction(a.numerator * b, a.denominator * b);
return fraction;
}
public static Fraction operator/(Fraction a, Fraction b)
{
Fraction fraction = new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
return fraction;
}
public static Fraction operator /(Fraction a, int b)
{
Fraction fraction = new Fraction(a.numerator, a.denominator * b);
return fraction;
}
Также нужно иногда сокращать дроби, но опять же встает вопрос, а как это сделать? Внизу приложен алгоритм показывающий как это можно сделать:
public void Reduce()
{
this.Numerator = this.Numerator > 0 ? this.Numerator : -this.Numerator;
this.Denominator = this.Denominator > 0 ? this.Denominator : -this.Denominator;
int maxval = Numerator > Denominator ? Numerator : Denominator;
for (int i = maxval; i >= 2; maxval--)
{
if (Numerator % maxval == 0 && Denominator % maxval == 0)
{
this.Numerator /= maxval;
this.Denominator /= maxval;
break;
}
}
}
Также добавим перевод дроби в десятичную дробь.
public double ToDouble()
{
if (denominator != 0)
{
return numerator / denominator;
}
else
{
throw new InvalidOperationException("The denominator must not equal zero");
// return 0;
}
}
На этом пока все.
Спасибо за прочтение.