Как вычислить дробь в 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