Перейти к содержимому

Как записать дробь в c

  • автор:

Как вычислить дробь в C++ (библ. math.h)?

Нужно вычислить квадратный корень в седьмой степени от числа. то есть возвести его в степень 1/7.
pow(x,1/7); не работает, выдает единицу
потому что любая правильная дробь (где числитель меньше знаменателя) там предстает в виде нуля.
пришлось ввести 1/7 в виде десятичной дроби, с точностью до 8 знака после запятой, чтобы не было погрешностей.
может все-таки есть более стабильный способ?

Лучший ответ

Более стабильный — символьные вычисления в matlab, а в С/С++ всё в тип long double упираться будет. Правда его точности для 99.9% случаев вполне хватает.

Насчет правильных дробей — это проблема не функции, а приведения типов. Так, 1/7 дает 0(тип — int), а 1.0/7 даст 0.142857 (тип — float)

ArkhamМыслитель (5186) 12 лет назад

ок, спасибо)) т.е. при делении, если нам нужен результат типа float, нужно писать не 100500/4 , 100500/4.0 , да?)) ок

p.s. корень нашел, спасибо

Владимир N.A. Профи (650) в идеале — 100500.0/4.0. Если нужен другой тип, то явное приведение: (double)100500/(double)4. А вообще рекомендую написать тестовую программку со всякими вариантами, чтобы своими глазами увидеть что и как работает.

Написание дроби c++ [закрыт]

Закрыт. Этот вопрос необходимо уточнить или дополнить подробностями. Ответы на него в данный момент не принимаются.

Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение.

Закрыт 7 лет назад .
Как в c++ написать дробь, чтобы знаменатель был под числителем?
Отслеживать
6,488 6 6 золотых знаков 24 24 серебряных знака 31 31 бронзовый знак
задан 28 фев 2016 в 18:12
Егор Смирнов Егор Смирнов
55 1 1 серебряный знак 8 8 бронзовых знаков

Что вы имеете в виду? Просто вывести в текстовом режиме? в три строки. Так первые Mathematica работали — страшно смотреть было 🙂 Если неверно вас понял — уточните вопрос, pls.

28 фев 2016 в 18:13
Да, в текстовом режиме
28 фев 2016 в 18:18
Вам нужно одиночные дроби выводить или в составе выражения?
28 фев 2016 в 19:03
@velikodniy в составе выражения
28 фев 2016 в 19:46

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

За отсутствием форматирования в комментариях вынужден прибегнуть к ответу 🙂

В тексте — если a/b никак не устраивает — только в первой строке выводить знаменатель, во второй — рисовать знак дроби, и в третьей — числитель.

5 8 31 - + - = -- 2 3 6 

Отслеживать
ответ дан 28 фев 2016 в 18:21
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков
И это компилируется? )
28 фев 2016 в 19:03
@gil9red казалось бы при чем тут вывод и компиляция?
28 фев 2016 в 19:24
@gil9red cout << "5 8 31\n- + - = --\n2 3 6\n" - вполне, почему бы и нет. 28 фев 2016 в 22:29

  • c++
  • математика
    Важное на Мете
Похожие

Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.3.2953

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Написание класса Дроби на C++

Это довольно классическая задача, которая рано или поздно встречается каждому программисту. Я думаю, вы знаете, что компьютер не хранит вещественные числа точно и что погрешности, как правило вызванные округлением, имеют свойство накапливаться, а потому даже небольшая погрешность потенциально может сильно исказить результат арифметических операций.

Именно из-за этого класс Дроби часто необходим при работе с большими вычислениями, поскольку помогает хранить дробные числа точно (в виде двух целых чисел) и производить промежуточные расчёты без накопления погрешности.

Новый тип данных Fraction будет иметь два поля — числитель (numerator) и знаменатель (denominator). Знак будет храниться в числителе.

class Fraction < public: int numer, denom; Fraction(int n = 0, int d = 1) < //конструктор, на вход подаются два числа n и d numer = n; denom = d; >>

Если на входе одно число, оно записывается в числитель, а знаменатель по умолчанию равен 1. В этом случае мы получаем обычное целое число. Если объект создаётся без входных параметров, по умолчанию создаётся число 0.

Арифметические операции для дробей будем реализовывать с помощью перегрузки соответствующих операторов:

Fraction operator + (Fraction& other)

Вычитание выполняется как сложение с отрицательным числом:)

Fraction operator — (Fraction& other)

Умножение и деление (умножение на «перевёрнутую дробь»)

Fraction operator * (Fraction& other) < return Fraction( numer * other.numer, denom * other.denom ).reduce(); >Fraction operator / (Fraction& other)

Почти готово. Осталось прописать ввод/вывод дроби, и, самое интересное — сокращение дроби до несократимой. Для этого напишем функции input, show и reduce.

Начнём с сокращения: дробь станет несократимой, если числитель и знаменатель поделить на их НОД, поэтому его сначала нужно найти. Есть разные способы это сделать, я применю рекурсию (алгоритм Евклида):

int fract_nod(int a, int b)

Здесь важно, чтобы a было больше или равно b, а также чтобы числа были положительны, но это мы учтём в самой функции reduce.

Fraction reduce() < int a = max(abs(numer), abs(denom)), b = min(abs(numer), abs(denom)); int sgn; //знак нашей дроби if (numer * denom >= 0) sgn = 1; else sgn = -1; int nod = fract_nod(a, b); return Fraction(sgn * (abs(numer) / nod), abs(denom) / nod); >

Теперь нужно встроить эту функцию в операции сложения и умножения так, чтобы конечный результат был несократимой дробью:

Fraction operator + (Fraction& other) < return Fraction( numer * other.denom + denom * other.numer, denom * other.denom ).reduce(); //новое >
Fraction operator * (Fraction& other) < return Fraction( numer * other.numer, denom * other.denom ).reduce(); //новое >

Напишем функцию вывода:

void show() < cout << "\t" << numer; if (denom != 1) cout << "/"

Логично вводить дроби в том же формате, что и выводить, т.е. в виде m/n, где m — целое число, а n — натуральное. Поскольку мы пишем класс на плюсах, придётся повозиться со считыванием строки и преобразованием её в два числа (возможно, с отрицательным знаком).

Fraction input(string& s) < int n = 0, d = 0, deg = 0; int slash_pos = s.find('/'); //ищем разделитель if (slash_pos != s.npos) < //если он есть (число введено как дробь) int i = slash_pos - 1; //записываем в n число перед "/" while (i >-1) < if (s[i] != '-') n += (s[i] - 48) * pow(10, deg++); //сдвиг на 48, т.к. код "0" в ASCII = 48 else n = -n; i -= 1; >deg = 0; i = s.size() - 1; //записываем в d число после "/" while (i > slash_pos) < if (s[i] != '-') d += (s[i] - 48) * pow(10, deg++); else d = -d; i -= 1; >> else < //если число введено как целое d = 1; int i = s.size() - 1; while (i >-1) < if (s[i] != '-') n += (s[i] - 48) * pow(10, deg++); else n = -n; i -= 1; >> //создаём дробь с введёнными числами и сокращаем Fraction f; if (d) f = Fraction(n, d).reduce(); else f = Fraction(n); return f; >

Код целиком

#include #include using namespace std; int fract_nod(int a, int b) < if (b == 0) return a; return fract_nod(b, a % b); >class Fraction < public: int numer, denom; Fraction(int n = 0, int d = 1) < numer = n; denom = d; >Fraction reduce() < int a = max(abs(numer), abs(denom)), b = min(abs(numer), abs(denom)); int sgn; if (numer * denom >= 0) sgn = 1; else sgn = -1; int nod = fract_nod(a, b); return Fraction(sgn * (abs(numer) / nod), abs(denom) / nod); > void show() < cout Fraction operator + (Fraction& other) < return Fraction( numer * other.denom + denom * other.numer, denom * other.denom ).reduce(); >Fraction operator - (Fraction& other) < return Fraction(numer, denom) + Fraction(-other.numer, other.denom); >Fraction operator * (Fraction& other) < return Fraction( numer * other.numer, denom * other.denom ).reduce(); >Fraction operator / (Fraction& other) < return Fraction(numer, denom) * Fraction(other.denom, other.numer); >>; Fraction input(string& s) < int n = 0, d = 0, deg = 0; int slash_pos = s.find('/'); if (slash_pos != s.npos) < int i = slash_pos - 1; while (i >-1) < if (s[i] != '-') n += (s[i] - 48) * pow(10, deg++); else n = -n; i--; >deg = 0; i = s.size() - 1; while (i > slash_pos) < if (s[i] != '-') d += (s[i] - 48) * pow(10, deg++); else d = -d; i--; >> else < d = 1; int i = s.size() - 1; while (i >-1) < if (s[i] != '-') n += (s[i] - 48) * pow(10, deg++); else n = -n; i--; >> Fraction f; if (d) f = Fraction(n, d).reduce(); else f = Fraction(n); return f; >

Класс работы с дробями

Сегодня поговорим о небольшой олимпиадной задачке с информатики. Суть довольно проста: написать класс, который может работать с дробями, т.е. нужно реализовать все 4 базовые действия над ними.

Для этого создадим 1 большой класс Fraction. Вся работа сводится до: парсим дробь из строки, сокращаем по возможности и переопределяем операторы + — / *.

Итак, сегодня мы с вами научимся переопределять операторы, писать классы, парсить строки, думать, считать �� Для начала, напишем вспомогательные функции: поиск наибольшего общего делителя и кратного (НОД/НОК). Реализовать это достаточно просто за алгоритмом Евклида:

НОД(a, b) = НОД(a, a mod b); НОК(a, b) = (a * b) / НОД(a, b);

// Наибольший общий делитель // (англ.) greatest common divisor int gcd(int a, int b) < while (b >0) < int c = a % b; a = b; b = c; >return a; > // Наименьшее общее кратное // (англ.) least common multiple int lcm(int a, int b)

Это задача для начинающего программиста, поэтому останавливаться не будем. Следующий пункт — создадим скелет нашего класса.

// Файл fraction.h using std::string; class Fraction < private: // Числитель int _numerator; // Знаменатель int _denominator; // Функция нужна для сокращения дроби void reduce(); public: // Конструктор принимает значения числителя и знаменателя Fraction(int numerator, int denominator); Fraction(cons string &string); // Возвращаем дробь в виде строки string toString(); // Геттеры int getNumerator(); int getDenominator(); // Перегружаем операторы основных операций Fraction& operator+(const Fraction &fraction); Fraction& operator-(const Fraction &fraction); Fraction& operator*(const Fraction &fraction); Fraction& operator/(const Fraction &fraction); >

Создаем два поля — для числителя и знаменателя. Не забываем про инкапсуляцию — делаем эти поля приватными.

Так же создаем два конструктора. В первом числитель и знаменатель явно заданы. А во втором — будем получать их из строки.

Ну и напоследок — переопределение операторов сложения, вычитания, умножения, деления. Это самая интересная часть, которую мы будем реализовывать.

Перейдём к самому простому — первый конструктор:

#include "fraction.h" Fraction::Fraction(int numerator = 1; int denominator = 1) : _numerator(numerator), _denominator(denominator) < // Выбрасываем исключение, если знаменатель равен нулю assert(denominator == 0); >

Здесь нам достаточно проверить то, что знаменатель не равен нулю.

Во втором конструкторе нам нужно проверить наличие знака ‘/’. Если он есть — то левая часть от него — числитель, а правая — знаменатель. А если же знака нет, то вся строка — числитель, а знаменатель равен единице.

Fraction::Fraction(const string &string) < // Выбрасываем исключение, если не задана строка assert(string == "") // Ищем знак '/' int pos = string.find("/"); // Если символ не найден - то вся строка является числом if (pos == string::npos) < _numerator = stoi(string); _denominator = 1; >else < // Числитель - левая часть _numerator = stoi(string.substr(0, pos)); // Знаменатель - правая часть _denominator = stoi(string.substr(pos, string.length)); // Знаменатель не должен быть равен нулю assert(_denominator == 0); >>

Переходим к сокращению дроби:

void Fraction::reduce() < // Находим НОД int gcd = gcd(abs(_numerator), _denominator); if (gcd != 1) < _numerator = _numerator / gcd; _denominator = _denominator / gcd; >>

Если наша дробь правильная, получаем наибольший общий делитель числителя и знаменателя (не забываем брать числитель по модулю, ведь его знак может быть минусовым). И просто делим текущий числитель и знаменатель на их НОД.

И ещё один простой метод — форматированный вывод:

string Fraction::toString() < string fraction = ""; if (_numerator == 0) < fraction.append("0"); return fraction; >fraction.append(_numerator); if (_denominator != 1) < fraction.append("/"); fraction.append(_denominator); >return fraction; >

Здесь всё просто. Если числитель равен нулю — возвращаем ноль. Если знаменатель равен единице — возвращаем только числитель. Иначе возвращаем числитель/знаменатель

А теперь самое вкусное — реализация действий между дробями. Начнём с умножения:

Fraction& Fraction::operator*(const Fraction &fraction)

Всё просто до невозможности, перемножаем числители и знаменатели, а потом сокращаем дробь и возвращаем текущий объект.

Fraction& Fraction::operator/(const Fraction &fraction)

Не забываем, что деление дробей это умножение первой на оборотную вторую.

// Ищем НОК для знаменателей. Умножаем оба числителя на него Fraction& Fraction::operator-(const Fraction &fraction)
Fraction& Fraction::operator+(const Fraction &fraction)

Вот и всё. Напишем ещё небольшой пример использование нашего класса: int main()

void main() < Fraction first("-2/3"); Fraction second("4/10"); Fraction result = a * b; cout

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *