8
\$\begingroup\$

Newbie here :) I have been working on a program that reads a pair of numbers from standard input, along with a mathematical operation and an initial capacity for storing the numbers; and using this input, the program produces the desired result.

The example output should simply be a big number that shows the result of applying the operation to the two given big numbers.

How can I make this code simpler, condensed, and readable?

Now that I look at it, it looks a bit too much and I'll like to condense the code in any way possible, so I would love extra eyes! Also, it may look a little more complicated because I am limited to just the basic libraries, but I would rather not go out the boundaries to use premade functions from libraries.

/*
A program that will read a pair of numbers from
standard input, along with a mathematical operation and an initial capacity for
storing the numbers; using this input, this program will produce the desired
result */

#include <iostream>

using namespace std;

/**
 * Return the value of the digit represented by the given character
 * @param the_char the character to convert to a digit
 * @return the numerical value of the digit representated by the given character
 */
short to_digit(const char the_char) {
    return the_char - '0';
}

/**
 * Increase the capacity (doubling it) of the given array with the given capacity
 * @param p_number an dynamically allocated array of shorts to double
 * @param current_capacity the current capacity of p_number
 */
void increase_capacity(short * & p_number, size_t & current_capacity) {
    const size_t new_capacity = current_capacity * 2;
    short * p_new_number = new short[new_capacity];
    for (size_t digit_index = 0; digit_index < current_capacity; digit_index++)
        p_new_number[digit_index] = p_number[digit_index];
    delete[] p_number;
    p_number = p_new_number;
    current_capacity = new_capacity;
}

/**
 * Read a big number from the standard input
 * @param initial_capacity the initial capacity for the array storing the big number
 * @param num_digits the number of digits in the big number after reading it
 * @return a pointer to dynamically allocated memory storing the big number
 */
short * read_number(const size_t initial_capacity, size_t & num_digits) {
    short * p_number = new short[initial_capacity];
    size_t current_capacity = initial_capacity;
    num_digits = 0;
    char current_char = cin.get();
    while (current_char != '\n') {
        if (current_capacity == num_digits) {
            increase_capacity(p_number, current_capacity);
        }
        p_number[num_digits++] = to_digit(current_char);
        current_char = cin.get();
    }
    return p_number;
}

/**
 * Print the big number with the given number of digits
 * @param p_number the big number to print
 * @param digits_in_number the number of digits in the big number
 */
void print_number(short * p_number, const size_t digits_in_number) {
    for (size_t digit_index = 0; digit_index < digits_in_number; digit_index++) {
        cout << p_number[digit_index];
    }
    cout << endl;
}
/**
* Function to add given numbers
* @param first_number is first number on the second row of input file
* @param sec_number is the second number on the third row of input file
* @param digits_in_number holds the size of the dynamic array
*/
short * add_numbers(short * first_number, short * sec_number, const size_t digits_in_number) {
    short * number = new short[digits_in_number];
    int carry_over = 0;
    for (int i = digits_in_number - 1; i >= 0; i--) {
      int sum = first_number[i] + sec_number[i] + carry_over;
      if(sum >= 10 && digits_in_number > 2) {
        number[i] = sum - 10;
        carry_over = 1;

      } else {
        number[i] = sum;
        carry_over = 0;
      }
    }
    return number;
}
/**
* Function to subtract given numbers
* @param first_number is the first number of the second row from input
* @param sec_number is the second number of the third row from input
* @param digits_in_number holds the size of the dynamic array
*/
short * sub_numbers (short * first_number, short * sec_number, const size_t digits_in_number) {
    short * number = new short[digits_in_number];
    int take_away = 0; //takes away 1 from next number(right to left)
    for (int i = digits_in_number - 1; i >= 0; i--) {
      first_number[i] -= take_away;
      int diff = first_number[i] - sec_number[i];
      if(diff < 0) {
        number[i] = diff + 10;
        take_away = 1;
      } else {
        number[i] = diff;
        take_away = 0;
      }
    }
    return number;
}
/**
 * Reads symbol after given capacity and executes correct thing for it
 * @param symbol reads the mathematical operation
 * @param first_number is first number on the second row of input file
 * @param sec_number is the second number of the third row from input
 * @param digits_in_number holds the size of the dynamic array
 */

short * read_symbol(char symbol, short * first_number, short * sec_number, const size_t digits_in_number) {

    if (symbol == '+') {
        return add_numbers(first_number, sec_number, digits_in_number);
    }
    if (symbol == '-') {
      return sub_numbers(first_number, sec_number, digits_in_number);
    }
    if (symbol == '%') {
      return first_number;
    }
}
/**
 * Pad the given big number with zeros until it has a new length
 * @param p_number the big number to pad
 * @param digits_in_number the number of digits in the big number
 * @param new_digits the number of digits the padded number should have
 */
void pad_number(short * & p_number, size_t & digits_in_number, const size_t new_digits) {
    short * p_new_number = new short[new_digits];
    const size_t num_zeros = new_digits - digits_in_number;
    for (size_t pad_index = 0; pad_index < num_zeros; pad_index++) {
        p_new_number[pad_index] = 0;
    }
    for (size_t digit_index = 0; digit_index < digits_in_number; digit_index++) {
        p_new_number[num_zeros + digit_index] = p_number[digit_index];
    }

    delete[] p_number;
    p_number = p_new_number;
    digits_in_number = new_digits;
}

/**
 * Given two big numbers, padd the smaller one.
 * @param p_number1 the first big number
 * @param digits_in_number1 the number of digits in the first big number
 * @param p_number2 the second big number
 * @param digits_in_number2 the number of digits in the second big number
 */
void pad_numbers(short * & p_number1, size_t & digits_in_number1,
                 short * & p_number2, size_t & digits_in_number2) {
    if (digits_in_number1 > digits_in_number2) {
        const size_t new_digits = digits_in_number1;
        pad_number(p_number2, digits_in_number2, new_digits);
    } else {
        const size_t new_digits = digits_in_number2;
        pad_number(p_number1, digits_in_number1, new_digits);
    }
}

// Controls execution of program
int main() {
    size_t initial_capacity = 0;
    cin >> initial_capacity;
    cin.get();
    char for_symbol = cin.get();
    cin.get();
    size_t digits_in_number1 = 0, digits_in_number2 = 0;
    short *p_number1 = read_number(initial_capacity, digits_in_number1);
    short *p_number2 = read_number(initial_capacity, digits_in_number2);

    pad_numbers(p_number1, digits_in_number1, p_number2, digits_in_number2);
    short * result = read_symbol(for_symbol, p_number1,p_number2,digits_in_number1);

    print_number(result, digits_in_number1);

    delete[] p_number1;
    delete[] p_number2;
    delete[] result;
    return 0;
}
\$\endgroup\$
1
  • \$\begingroup\$ I repeated: do not vandalize your posts by removing (parts of) the code after receiving answers. \$\endgroup\$
    – Mast
    Commented Feb 27, 2022 at 20:02

1 Answer 1

9
\$\begingroup\$

Make use of the standard library

How can I make this code simpler, condensed, and readable?

The best way to make the code simpler, condensed and readable is by not writing it. C++ comes with a very nice standard library which has all sorts of functionality.

For example, instead of using new and delete to allocate memory for big numbers, and writing an increase_capacity() function to allow those numbers to grow, consider using std::vector<short> to store numbers.

[...] but I would rather not go out the boundaries to use premade functions from libraries.

You definitely should learn to use libraries, especially the standard library. Think of it as standing on the shoulders of giants. Without them, you will be reinventing the wheel all the time, and will spend much more time creating something that does the same as something that uses library functions. Of course, there might be some drawbacks using libraries, for example there might be licensing restrictions, portability issues and so on, those are valid reasons not to use a particular library even if it has the functionality you need.

Create a class representing big numbers

Another way to make the code more concise is to create a class that represents a big number, along with member functions that operate on them. You can start simple by just having a std::vector<short> member variable holding the numbers, and have public member functions that add, subtract, read and print. But ideally, you can turn the functions that add and subtract into arithmetic operator overloads, and the read and print functions into std::ostream operator overloads, so that your main() function would end up looking like this:

int main() {
    BigNum a, b, result;
    std::string operation;

    std::cin >> a >> b >> operation;

    if (operation == "+") {
        result = a + b;
    } else if (operation == "-") {
        result = a - b;
    } else {
        ...
    }

    std::cout << result << '\n';
};

Negative numbers

Your program doesn't deal correctly with negative numbers. Even if you don't allow them in the input, consider that you could subtract a bigger positive number from a smaller positive number.

Efficiency

A short is typically 16 bits. That's quite a lot to store a number from 0 to 9. Apart from using more memory, it's also quite inefficient to let the computer deal with small digits. If you could use the full 16 bits of a short and treat those as binary numbers, then the operations on them could be done much faster. The drawback of course is that your read and print functions would need to convert from decimal to the internal format, but usually it ends up being an overall performance win.

\$\endgroup\$
1
  • \$\begingroup\$ Could you elaborate on the Efficiency section? What do you mean by "full 16 bits of a short"? \$\endgroup\$ Commented Mar 2, 2022 at 8:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.