Как вывести дробь вместо десятичного числа?

В С++, когда я вычисляю 2/3, он выводит десятичные значения, как я могу просто получить исходный формат (например, 2/3) вместо 0,66666667

Спасибо


person Sean    schedule 27.01.2011    source источник
comment
Это зависит от того, что вы подразумеваете под вычислением 2/3   -  person Itamar Katz    schedule 27.01.2011
comment
Этот вопрос должен сопровождаться примером кода, а также фактическим и ожидаемым результатом.   -  person Björn Pollex    schedule 27.01.2011
comment
Здесь есть интересная демонстрация, показывающая работу преобразования десятичной дроби в дробь: webmath.com/dec2fract. html   -  person Tony    schedule 27.01.2011
comment
@Tony: Да, это интересно, но далеко не математически строго, и поэтому я чувствую, что это опасно вводит в заблуждение для действительного понимания предмета. Хотя это начало :-). Для более подробного объяснения см., например, en.wikipedia.org/wiki/Continued_fractions , в частности раздел Лучшее рациональное в интервале. (Извините, я математик, не удержался...).   -  person sleske    schedule 27.01.2011
comment
напоминает мне 355/113   -  person user3528438    schedule 07.10.2015


Ответы (13)


Вы не можете. Вам нужно будет написать класс, посвященный хранению рациональных чисел (т.е. дробей). Или просто используйте библиотеку Boost Rational Number.

person Oliver Charlesworth    schedule 27.01.2011
comment
+1: очевидное решение - просто не выбрасывайте эту информацию! - person Eamon Nerbonne; 27.01.2011
comment
Существует конечное число значений int, которые производят 0.66666667. Почему бы просто не написать функцию, которая выбирает один? Ответ не ты не можешь - person Inverse; 31.01.2011
comment
@Inverse: вы не можете ни с каким разумным подходом. Похоже, вы предлагаете умножить значение с плавающей запятой на все возможные знаменатели, пока не найдете результат, близкий к целочисленному значению? Очевидно, это практически бесконечная алгоритмическая сложность (есть ли лучшие методы?). И даже это не вернет исходный формат в соответствии с запросом ОП; он не может различить 2/3 и 4/6. - person Oliver Charlesworth; 31.01.2011
comment
@Inverse: нет, существует бесконечное количество целых чисел, которые производят 0.66666667. Это может быть 1/3, или 1000000/3000001, или 1000001/3000000 и т. д. (предполагая, что достаточно нулей, чтобы исчерпать точность FP). Вы можете легко показать, что для любого числа FP существует бесконечное (хотя и счетно бесконечное) количество целых дробей. - person sleske; 16.11.2011
comment
Конечно, на практике вам обычно нужна дробь с наименьшим знаменателем, который достаточно близок к вашему числу FP. На самом деле существует только одна такая дробь, если вы установите фиксированный предел максимальной разницы между числом FP ​​и дробью (или если вы установите верхнюю границу для знаменателя). Подробности смотрите в моем ответе :-). - person sleske; 16.11.2011
comment
@Oli Charlesworth: Да, наивный подход с использованием всех знаменателей сработает, но, очевидно, он довольно медленный. И да, есть лучшие способы; общий алгоритм использует непрерывные дроби. Например, Pari/GP реализует это, см. мой ответ. - person sleske; 16.11.2011
comment
@sleske: даже если бы каждая пара 32-битных целых чисел давала значение, их все равно было бы конечное число, меньше 2 ^ 64 - person Inverse; 18.11.2011
comment
@Oli Charlesworth: начните с 66666667/100000000, это O (1). Затем запустите какой-нибудь вариант GCD, чтобы уменьшить дробь, если хотите. - person Inverse; 18.11.2011
comment
@Inverse: Как отличить 66666667/100000000 от 2/3? - person Oliver Charlesworth; 18.11.2011
comment
@Inverse: Чтобы начать с 66666667/100000000[...] Затем запустите какой-нибудь вариант GCD. Да, это сработало бы, если бы FP мог точно представлять все дроби. Однако это невозможно, поэтому в большинстве случаев дробь, которую вы получаете из представления FP, не совсем равна дроби, с которой вы начали. Тогда вам нужен какой-то алгоритм аппроксимации (например, объясненный в моем ответе :-)). - person sleske; 18.11.2011

Если я правильно понимаю, у вас есть число с плавающей запятой (переменная типа float или double), и вы хотите вывести это значение в виде дроби.

Если это так, вам необходимо уточнить свой вопрос:

  • Число FP является дробью по определению: число FP состоит из двух целых чисел, мантиссы m и показателя степени e (и знака , но это не имеет значения здесь). Таким образом, каждое число FP на самом деле является парой (m,e), а значение f, которое оно представляет, равно f=mb^e (где < em>b — фиксированная целочисленная база, обычно 2). Таким образом, естественное представление в виде дроби — это просто m / b^(-e) с e‹0 (если e>=0 , < em>f в любом случае является целым числом).
  • Однако вы, вероятно, захотите получить дробь с наименьшим разумным делителем. Это другой вопрос. Чтобы получить это, вы могли бы, например. используйте функцию bestappr из библиотеки Pari/GP. В вашем случае вы, вероятно, использовали бы bestappr(x, A) с x вашим вводом и A наибольшим знаменателем, который вы хотите попробовать. bestappr даст вам ближайшую к x дробь, знаменатель которой меньше A.
person sleske    schedule 27.01.2011

напишите свой собственный класс Rational для вычисления делений

class Rational
{
public:
    int numerator, denominator;

    Rational(int num, int den=1){
        numerator = num;
        denominator=den;
    }
    Rational(Rational other){
        numerator = other.numerator;
        denominator = other.denominator;
    }
    double operator / (int divisor){
            denominator *= divisor;
            simplificate();
            return getrealformat();
    }
    Rational& operator / (int divisor){
            denominator *= divisor;
            simplificate();
            return this;
    }
    Rational& operator / (Rational &divisor){
            numerator *= divisor.numerator;
            denominator *= divisor.denominator;
            simplificate();
            return this;
    }
    double operator / (int divisor){
            denominator *= divisor;
            simplificate();
        return getrealformat();
    }
    double getrealformat(){
        return numerator/denominator;
    }
    simplificate(){
        int commondivisor = 1;
        for(int i=2;i<=min(abs(numerator), abs(denominator));i++)
            if( numerator%i == 0 && denominator%i == 0 )
                commondivisor = i;
        numerator /= commondivisor;
        denominator /= commondivisor;
    }
};

использовать

Rational r1(45), r2(90), r3=r1/r2;
cout<<r3.numerator<<'/'<<r3.denominator;
cout<<r3.getrealformat();
person Aak    schedule 27.01.2011
comment
Как это обрабатывает преобразование из float или double в Rational? - person Thomas Matthews; 27.01.2011
comment
Рациональный оператор = (двойное число) { числитель = число * десятичные числа; / * один раз указано ранее, например. 100 */ знаменатель = десятичные дроби; упростить(); } - person Aak; 31.01.2012
comment
pastebin.com/LhGK3gNG: здесь я попытался протестировать вышеупомянутый класс. Однако я не мог использовать приведенный выше код как есть (потому что он показывал некоторые ошибки), и мне пришлось переписать несколько вещей. В конце концов, это не работает, как ожидалось. Кто-нибудь может проверить, что пошло не так? @ThomasMatthews - person ; 17.03.2018
comment
Спасибо за ссылку, но брандмауэры блокируют доступ к ссылке. Может быть, вы могли бы отредактировать свой пост вместо этого? - person Thomas Matthews; 17.03.2018
comment
@ThomasMatthews Я создал новую ссылку: paste.ofcode.org/SVZLDr72BUyEUkam5GrAEt Надеюсь, это сработает - person ; 17.03.2018

как я могу просто получить исходный формат (например, 2/3) вместо 0,66666667

Только с большим трудом, обернув нечто вроде библиотеки GMP пользовательскими операторами вывода. Ниже немного больше о GMP:

Что такое GMP?

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

Основными целевыми приложениями для GMP являются приложения и исследования в области криптографии, приложения для обеспечения безопасности в Интернете, системы алгебры, исследования в области вычислительной алгебры и т. д.

GMP тщательно спроектирован так, чтобы быть максимально быстрым как для небольших операндов, так и для больших операндов. Скорость достигается за счет использования полных слов в качестве основного арифметического типа, использования быстрых алгоритмов, высокооптимизированного ассемблерного кода для наиболее распространенных внутренних циклов для многих ЦП и общего упора на скорость.

GMP работает быстрее, чем любая другая библиотека bignum. Преимущество GMP увеличивается с размером операнда для многих операций, поскольку GMP использует асимптотически более быстрые алгоритмы.

Первая версия GMP была выпущена в 1991 году. Она постоянно развивается и поддерживается, а новая версия выпускается примерно раз в год.

person Dirk Eddelbuettel    schedule 27.01.2011
comment
Это или какое-то подобное сооружение — практически единственный способ. Вы все еще должны отслеживать с самого начала. Если у вас просто 0,6666667, вы не сможете узнать, было ли это 6666667/10000000 или 2/3. - person T.E.D.; 27.01.2011


В общем случае это невозможно: числа с плавающей запятой неточны и не сохраняют достаточно информации для полного восстановления дроби.

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

Если вы полностью контролируете код, идея Оли лучше: не выбрасывайте информацию в первую очередь.

person Eamon Nerbonne    schedule 27.01.2011
comment
Это НЕ СОВЕРШЕННО верно. Если у вас есть конкретная точность, с которой вы готовы жить (скажем, 0,00001), вы можете умножить ее на величину, обратную этой точности, что даст вам большие числитель и знаменатель. В этот момент можно было бы разложить на множители и числитель, и знаменатель, а затем начать удалять общие множители, пока не останется наименьшая дробь, которая дает значение с плавающей запятой, которое находится в пределах указанной вами точности исходного числа с плавающей запятой. - person BobG; 27.01.2011
comment
Вы имеете в виду: это не всегда верно для всех чисел с плавающей запятой. Точнее, для любого числа с плавающей запятой существует бесконечное множество рациональных чисел, по крайней мере столь же близких к нему, как и к другим числам с плавающей запятой, хотя ровно одно из этих рациональных чисел в точности равно числу с плавающей запятой. Это лучше? - person Eamon Nerbonne; 27.01.2011
comment
@BobG: этот алгоритм, как правило, не находит оптимальную дробь, поскольку выбранный вручную начальный знаменатель (1/0,00001 в вашем примере) не делится на оптимальный делитель (например, 3 в примере Шона). Во всяком случае, это звучит как другой вопрос... - person Eamon Nerbonne; 27.01.2011
comment
Во всяком случае, нет необходимости в реализации алгоритма нахождения наилучшего рационального приближения; такие реализации уже существуют, например, в Pari/GP (см. мой ответ). - person sleske; 27.01.2011

Вы можете хранить все числители и знаменатели вашей дроби как целые числа. Целые числа имеют точное представление в двоичном виде.

person ThomasMcLeod    schedule 27.01.2011
comment
... пока они этого не сделают. Существует max int, после которого вам придется использовать какую-то библиотеку bignum. Или с плавающей запятой, что возвращает его к исходной задаче. - person T.E.D.; 27.01.2011
comment
@TED, переполнение целых чисел не было проблемой ОП. - person ThomasMcLeod; 27.01.2011
comment
я бы сказал, что 1/10 ^ 20 - достаточная точность практически для любого приложения. - person flownt; 27.01.2011

Чтобы упростить усилия, я предлагаю вам по возможности придерживаться известных знаменателей.

Я работаю с приложением, в котором дроби ограничены знаменателями степени 2 или с использованием 3 (для третей).

Я конвертирую в эти дроби, используя приближение (округление до ближайшего 1,0/24,0).

Без некоторых ограничений нахождение знаменателя может быть довольно сложной задачей и занимать много времени выполнения.

person Thomas Matthews    schedule 27.01.2011

Я новичок, и этот способ, который я использую, может быть неправильным.

#include <iostream>

using namespace std;
int main ()
{
  double a;
  double b;
  double c;

  cout << "first number: ";
  cin >> a;
  cout << "second number: ";
  cin >> b;

  c = a/b;
  cout << "result is: " << c << endl;

  if (b != 0) {
    if (a > 0) {
      if (c - (int)c > 0 && c - (int)c < 1)
        cout << "fraction: " << a << "/" << b;
    } else {
      if (c - (int)c < 0 && c - (int)c < 1)
        cout << "fraction: " << a << "/" << b;
    }
  }

  return 0;
}
person EmPlusPlus    schedule 10.06.2013
comment
Я думаю, вы ответили на другой вопрос. Ваш ответ касается отделения целой части числа с плавающей запятой от нецелой части (т.е. разделения 1.25 на 1 и .25). Но вопрос заключается в преобразовании числа с плавающей запятой в дробное представление рационального числа, то есть 1 1/4 или 5/4. - person jogojapan; 10.06.2013
comment
С этим вы можете распознать плавающий результат и распечатать их дробным способом. - person EmPlusPlus; 10.06.2013
comment
Для 1.25 ваша программа выводит 1 и .25, верно? Как он превращает .25 в 1/4? - person jogojapan; 10.06.2013
comment
Хорошо, ребята, я только что отредактировал это так, как я сказал :) проверьте это и оставьте комментарий :) - person EmPlusPlus; 10.06.2013
comment
Но теперь ваша программа требует, чтобы пользователь явно указал все a и b. Некоторые другие ответы тоже говорили об этом; если в качестве входных данных задано рациональное число, вы можете просто сохранить его, чтобы оно было у вас, когда оно вам нужно. Но настоящая трудность заключается в вычислении a и b из числа с плавающей запятой. - person jogojapan; 10.06.2013
comment
Извините, я не понял, что вы имеете в виду!!! Но я пробовал это для многих чисел, и это дало правильный результат! - person EmPlusPlus; 10.06.2013
comment
Я имею в виду следующее: попробуйте написать программу, в которой пользователь вводит только c, а программа вычисляет a и b. Но в любом случае... это не так важно. - person jogojapan; 10.06.2013
comment
Ага, понятно !!! Я попробую, но я только начинающий! и вопрос касается вычисления a и b и их дробного результата. - person EmPlusPlus; 10.06.2013

Разделение обоих чисел на их HCF может помочь.

person Abhishek Jain    schedule 09.06.2014

#include <iostream>
using namespace std;

int main() {
    int a,b,q,r;
    cin>>a>>b;//first number and second number
    q = a/b;
    r = a-q*b;
    cout<<q<<" "<<r<<" "<<"/"<<" "<<b<<"\n";
    return 0;
}

Я только что получил частное по a/b, а остаток получил по a-q*b. открыт для предложений, если таковые имеются.

person Akash    schedule 06.10.2015

Используйте понятие наибольшего общего делителя.

если мы разделим числа на gcd их чисел, мы получим наименьшее возможное значение этих чисел. пример: -

#define si long long
int main() {
si int total=4;
si int count=2;
si int g= __gcd(count,total);
count/=g;
total/=g;
cout<<count<<"/"<<total<<endl;
}
for more reference check out this:-https://www.codechef.com/viewsolution/17873537
person vikas bajpai    schedule 18.03.2018

Это программа для преобразования десятичного числа в дробь

#include<iostream>
using namespace std;

int main()
{

    float num, origNum, rem = 1;
    int den = 1, i, count=0, gcd=1;

    cout << "Enter any float number to convert it into mixed fraction: ";
    cin >> origNum;

    num = origNum - static_cast<int>(origNum);

    if (num > 0.1)
    {
        while ( (rem > 0.1) )
        {
            num = num * 10;
            rem = num - static_cast<int>(num);
            count++;
        }

        for (i = 1; i <= count; i++) // counter is for the calculation of denominator part of mixed fraction 
        {
            den = den * 10;
        }

        for (i = 2; i <= num|| i<=rem; i++)
        {
            if( (static_cast<int>(num) % i == 0) && (den % i == 0) )
            {
                gcd = i;
            }   
        }

        cout << (static_cast<int>(origNum)) << " and " << (static_cast<int>(num))/gcd << "/" << den/gcd;
    }
    else
        cout << (static_cast<int>(origNum));

    return 0;   
}
person osama khalid    schedule 22.02.2015