0

A program takes two long fractions, and performs addition, subtraction, multiplication and comparison operations on them. In the standard CLion compiler (MinGW) the code is executed correctly, but in order to check it you need to pass the code in a compiler where the multiplication method (Prouz) does not work correctly.

MinGW:

input:
698768322001934555.698489123321899
0.347657908264796
output:
698768322001934556.046147031586695
698768322001934555.350831215057103
242932333188893996.179870469985582542826437567604
greater

Visual C++ 2013:

input:
698768322001934555.698489123321899
0.347657908264796
output:
698768322001934556.046147031586695
698768322001934555.350831215057103
24293233318889066-379-766-1096-1463-1510-1242.-906-653-28680-187-204-449-707-851
-632-774-1078-1248-1204-1452-1646-1308-975-980-715-362-347-698-1073-1421-1323-127
4-882-441
greater

What could be the problem and what is the best way to fix it?

#include <iostream>
#include <cmath>
#include <iomanip>

using namespace std;

class Fraction
{
private:
    int a, b;
    char* after;
    char* before;
public:
    Fraction()
    {
        a = 0, b = 0;
        char* before = new char[b + 1];
        char* after = new char[a + 1];
    }
    char Read()
    {
        for (int i = 0; i < 20; i++)
        {
            char h;
            cin >> h;
            if ((h != '.')||(h=='0'))
            {
                before = AddStruct(before, b);
                before[i] = h;
                b++;
            }
            else
                break;
        }
        for (int i = 0; i < 20; i++)
        {
            char h;
            h = cin.get();
            if (isspace(h))
            {
                break;
            }
            else
            {
                after = AddStruct(after, a);
                after[i] = h;
                a++;
            }
        }
        return before[b], after[a];
    }
    char* AddStruct(char* after, const int a)
    {
        if (a == 0)
            after = new char[a + 1];
        else
        {
            char* tempnumber = new char[a + 1];
            for (int i = 0; i < a; i++)
                tempnumber[i] = after[i];
            delete[] after;
            after = tempnumber;
        }
        return after;
    }
    int Plus(Fraction chislo1, Fraction chislo2)
    {
        int ostatok = 0;
        int* summaafter = new int[chislo1.a];
        int* summabefore = new int[chislo1.b];
        int ost = 0;
        for (int i = (a - 1); i >= 0; i--)
        {
            const char h1 = chislo1.after[i];
            int sum1 = static_cast<int>(h1) - 48;
            const char h2 = chislo2.after[i];
            int sum2 = static_cast<int>(h2) - 48;
            int summa = sum1 + sum2 + ostatok;
            ostatok = 0;
            if (summa > 9)
            {
                summa -= 10;
                ostatok++;
            }
            summaafter[i] = summa;
            ost = ostatok;
        }
        if (chislo2.before[0] == '0')
            for (int i = (chislo1.b - 1); i >= 0; i--)
            {
                summabefore[i] = static_cast<int>(chislo1.before[i])-48;
                if (i == (chislo1.b - 1))
                    summabefore[i] += ost;
            }
        else
        {
            for (int i = (b - 1); i >= 0; i--)
            {
                const char h1 = chislo1.before[i];
                int sum1 = static_cast<int>(h1) - 48;
                const char h2 = chislo2.before[i];
                int sum2 = static_cast<int>(h2) - 48;
                int summa = sum1 + sum2 + ostatok;
                ostatok = 0;
                if (summa > 9)
                {
                    summa -= 10;
                    ostatok++;
                }
                summabefore[i] = summa;
            }
        }
        for (int i = 0; i < b; i++)
        {
            cout << summabefore[i];
        }
        cout << ".";
        for (int i = 0; i < a; i++)
        {
            cout << summaafter[i];
        }
        cout << endl;
        return summaafter[a], summabefore[b];
    }
    int Minus(Fraction chislo1, Fraction chislo2)
    {
        int proverka = 0;
        if (chislo1.before[0] < chislo2.before[0])
            proverka = 1;
        int ostatok = 0;
        int* minusafter = new int[chislo1.a];
        int* minusbefore = new int[chislo1.b];
        int ost = 0;
        for (int i = (a - 1); i >= 0; i--)
        {
            const char h1 = chislo1.after[i];
            int min1 = static_cast<int>(h1) - 48;
            const char h2 = chislo2.after[i];
            int min2 = static_cast<int>(h2) - 48;
            if (proverka == 1)
            {
                int kk = min1;
                min1 = min2;
                min2 = kk;
            }
            int minus = min1 - min2 + ostatok;
            ostatok = 0;
            if (minus < 0)
            {
                minus += 10;
                ostatok--;
            }
            minusafter[i] = minus;
            ost = ostatok;
        }
        if (chislo2.before[0] == '0')
        {
            for (int i = (chislo1.b - 1); i >= 0; i--)
            {
                minusbefore[i] = static_cast<int>(chislo1.before[i]) - 48;
                if (i == (chislo1.b - 1))
                    minusbefore[i] += ost;
            }
        }
        else
        {
            for (int i = (b - 1); i >= 0; i--)
            {
                const char h1 = chislo1.before[i];
                int min1 = static_cast<int>(h1) - 48;
                const char h2 = chislo2.before[i];
                int min2 = static_cast<int>(h2) - 48;
                if (proverka == 1)
                {
                    int kk = min1;
                    min1 = min2;
                    min2 = kk;
                }
                int minus = min1 - min2 + ostatok;
                ostatok = 0;
                if (minus < 0)
                {
                    minus += 10;
                    ostatok--;
                }
                minusbefore[i] = minus;
            }
        }
        if (proverka == 1)
            cout << "-";
        for (int i = 0; i < b; i++)
        {
            cout << minusbefore[i];
        }
        cout << ".";
        for (int i = 0; i < a; i++)
        {
            cout << minusafter[i];
        }
        cout << endl;
        return minusafter[a], minusbefore[b];
    }
    int Prouz(Fraction chislo1, Fraction chislo2)
    {
        int ostatok = 0;
        int* prouz1 = new int[chislo1.a + chislo1.b];
        int* prouz2 = new int[chislo2.a + chislo2.b];
        int* prouzsum = new int[(chislo1.a + chislo1.b) * 2 + 3];

        for (int i = 0; i < chislo1.b; i++)
        {
            prouz1[i] = static_cast<int>(chislo1.before[i]) - 48;
        }
        int n = 0;
        for (int i = chislo1.b; i < (chislo1.a + chislo1.b); i++)
        {
            prouz1[i] = static_cast<int>(chislo1.after[n]) - 48;
            n++;
            if (n >= chislo1.a)
                break;
        }
        for (int i = 0; i < chislo2.b; i++)
        {
            prouz2[i] = static_cast<int>(chislo2.before[i]) - 48;
        }
        n = 0;
        for (int i = chislo2.b; i < (chislo2.a + chislo2.b); i++)
        {
            prouz2[i] = static_cast<int>(chislo2.after[n]) - 48;
            n++;
            if (n >= chislo2.a)
                break;
        }

        int k = (chislo1.a + chislo1.b) * 2; int t = 0;
        for (int k1 = 0; k1 < (k); k1++)
        {
            prouzsum[k1] = 0;
        }
        for (int i = ((chislo2.a + chislo2.b) - 1); i >= 0; i--)
        {
            for (int j = ((chislo1.a + chislo1.b) - 1); j >= 0; j--)
            {
                prouzsum[k - t - 1] += prouz2[i] * prouz1[j] + ostatok;
                ostatok = 0;
                while (prouzsum[k - t - 1] > 9)
                {
                    prouzsum[k - t - 1] -= 10;
                    ostatok++;
                }
                k--;
                if (j == 0)
                    prouzsum[k - t - 1] += ostatok;
            }
            ostatok = 0;
            t++;
            k = (chislo1.a + chislo1.b) * 2;
        }
        int prpr = 0;
        for (int i = 0; i < ((chislo1.a + chislo1.b) * 2); i++)
        {
            if (prouzsum[i] != 0)
            {
                prpr++;
                if (i == ((chislo1.b) * 2))
                    cout << ".";
                cout << prouzsum[i];
            }
            else
            {
                if (prpr != 0)
                    cout << prouzsum[i];
            }
        }
        delete[] prouz1;
        delete[] prouz2;
        delete[] prouzsum;
        return 0;
    }
    void Srav(Fraction chislo1, Fraction chislo2)
    {
        cout << endl;
        if (chislo1.before[0] > chislo2.before[0])
        {
            cout << "greater";
        }
        else
        {
            if (chislo1.before[0] < chislo2.before[0])
                cout << "less";
            else
                cout << "equal";
        }

    }
};

int main()
{
    Fraction chislo1, chislo2;
    chislo1.Read(); chislo2.Read();
    chislo1.Plus(chislo1, chislo2);
    chislo1.Minus(chislo1, chislo2);
    chislo1.Prouz(chislo1, chislo2);
    chislo1.Srav(chislo1, chislo2);
    return 0;
}

How the Prouz method works: First, the method converts each long fraction into an array of integers, where each digit is stored in a separate array element. Then it creates three arrays: prouz1, prouz2, and prouzsum. Prouz1 and prouz2 are arrays that store the digits of the first and second long fraction, respectively. Prouzsum is the array that will store the result of multiplication.

The method then performs the multiplication itself by multiplying each digit of the first long fraction with all digits of the second long fraction, starting with the last and ending with the first. The multiplication results are added to the prouzsum array using the carry method.

Finally, the method outputs the result of the multiplication, which is stored in the prouzsum array, converting the array back to a long fraction. At the end, the method frees the memory allocated to the arrays.

I tried to rewrite the method using vectors, but nothing really changed, everything worked correctly on me as usual, and on visual 2013, the output remained the same

    void Prouz(Fraction chislo1, Fraction chislo2)
    {
        vector<int> prouz1(chislo1.a + chislo1.b);
        vector<int> prouz2(chislo2.a + chislo2.b);
        vector<int> prouzsum((chislo1.a + chislo1.b) * 2 + 3);

        for (int i = 0; i < chislo1.b; i++)
        {
            prouz1[i] = static_cast<int>(chislo1.before[i]) - 48;
        }
        int n = 0;
        for (int i = chislo1.b; i < (chislo1.a + chislo1.b); i++)
        {
            prouz1[i] = static_cast<int>(chislo1.after[n]) - 48;
            n++;
            if (n >= chislo1.a)
                break;
        }
        for (int i = 0; i < chislo2.b; i++)
        {
            prouz2[i] = static_cast<int>(chislo2.before[i]) - 48;
        }
        n = 0;
        for (int i = chislo2.b; i < (chislo2.a + chislo2.b); i++)
        {
            prouz2[i] = static_cast<int>(chislo2.after[n]) - 48;
            n++;
            if (n >= chislo2.a)
                break;
        }

        int k = (chislo1.a + chislo1.b) * 2; int t = 0;
        for (int k1 = 0; k1 < (k); k1++)
        {
            prouzsum[k1] = 0;
        }
        int ostatok = 0;
        for (int i = ((chislo2.a + chislo2.b) - 1); i >= 0; i--)
        {
            for (int j = ((chislo1.a + chislo1.b) - 1); j >= 0; j--)
            {
                prouzsum[k - t - 1] += prouz2[i] * prouz1[j] + ostatok;
                ostatok = 0;
                while (prouzsum[k - t - 1] > 9)
                {
                    prouzsum[k - t - 1] -= 10;
                    ostatok++;
                }
                k--;
                if (j == 0)
                    prouzsum[k - t - 1] += ostatok;
            }
            ostatok = 0;
            t++;
            k = (chislo1.a + chislo1.b) * 2;
        }
        int prpr = 0;
        for (int i = 0; i < ((chislo1.a + chislo1.b) * 2); i++)
        {
            if (prouzsum[i] != 0)
            {
                prpr++;
                if (i == ((chislo1.b) * 2))
                    cout << ".";
                cout << prouzsum[i];
            }
            else
            {
                if (prpr != 0)
                    cout << prouzsum[i];
            }
        }
    }

nklobas
  • 13
  • 1
  • [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – 463035818_is_not_an_ai Mar 16 '23 at 08:34
  • 2
    you'll need to fix your buffer overflows: https://godbolt.org/z/1c5jrvh8M, `before` and `after` are never initialised. What is `return before[b], after[a]` supposed to do? – Alan Birtles Mar 16 '23 at 08:34
  • 2
    different compilers producing different outcome is a common symptom of undefined behavior – 463035818_is_not_an_ai Mar 16 '23 at 08:34
  • 1
    Don't complicate unnecessarily: `static_cast(x) - 48` --> `x - '0'`. – molbdnilo Mar 16 '23 at 08:36
  • 1
    you should get rid of all `new` and all `delete` by using `std::string` or `std::vector`. Then let the container manage the sizes for you. eg `for (int i = 0; i < chislo1.b; i++)` should be `for (int i = 0; i < prouz1.size(); i++)`. Most likely this will already fix the bugs. If not, it will make the bugs much simpler to spot – 463035818_is_not_an_ai Mar 16 '23 at 08:36
  • btw this will fix one of your next issues: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – 463035818_is_not_an_ai Mar 16 '23 at 08:38
  • 1
    fixing the obvious bugs gives the same output as visual studio in gcc: https://godbolt.org/z/q3oo3rPrq – Alan Birtles Mar 16 '23 at 08:42
  • @AlanBirtles wrong link? I see same wrong output and report from the sanitizer on https://godbolt.org/z/e5jbK9PKT – 463035818_is_not_an_ai Mar 16 '23 at 08:43
  • @463035818_is_not_a_number its the right link, the wrong output is the same as the VS output? In the question the mingw/gcc output is correct – Alan Birtles Mar 16 '23 at 08:46
  • @AlanBirtles I see the faulty `24293233318889066-379-766-1096-1463-1510-1242.-906-653-28680-187-204-449-707-851-632-774-1078-1248-1204-1452-1646-1308-975-980-715-362-347-698-1073-1421-1323-1274-882-441` in your version of the code (and the reports from the address sanitizer i mentioned is only about lleaks) – 463035818_is_not_an_ai Mar 16 '23 at 08:49
  • @AlanBirtles, before and after store values before and after the point, you are right, there is not much point in returning these values. – nklobas Mar 16 '23 at 09:07
  • 1
    @463035818_is_not_a_number yes, that was my intention, I've fixed the crashes and now the output is the same (at least approximately) as the incorrect output from visual studio in the question which suggests that if the mingw code really does work its largely by chance – Alan Birtles Mar 16 '23 at 09:51
  • In your `Fraction` struct you could simply use `std::string` or `std::vector` for `a` and `b`. You are wasting a lot of effort just for manual memory management now. Since you are clearly not familiar with basics of resource management, you'd better stay away from manual dynamic memroy management. Redesign your code, so that you can focus on the numeric logic - instead of memory management. – Red.Wave Mar 16 '23 at 10:10

1 Answers1

1

input.get() returns eof if there are no more characters available. As your second number is at the end of input, if it is less than 20 characters and there is no trailing space you keep reading into the eof appending the eof value cast to a character into your array. Adding a space to the end of your input makes it work: https://godbolt.org/z/bY6zb5M9n. You should never use a value read from a stream without checking that the read was successful, the minimum change is to add a check for eof:

int h;
h = cin.get();
if (std::char_traits<char>::eof() == h || isspace(h))
{
  break;
}

Your code still has many issues with memory leaks and accessing out of the bounds of the arrays. It'd be much simpler to use std::string, for example your Read function could just be:

std::getline(cin, before, '.');
std::getline(cin, after);

where before and after are std::string member variables, the members a and b can be replaced with before.size() and after.size(). e.g.: https://godbolt.org/z/onvY4154j

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60