-4

I am trying to solve this simple problem. I developed such algorithm, and it seems to work for every possible input I could think of. The following is the exact problem statement on my universiy's online judge.

Task:
You are given two natural N numbers. Compare them by their digits and write the greater one.

Input:
Contains two natural numbers, which modules are not greater than 1018.

Output:
The greater of two numbers.

Code:

#include <iostream>   // Problem 61, comparing two numbers by their digits.
#include <cmath>
//#include <climits>

using namespace std;

int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    long long int n, k; cin >> n >> k;
    long long int x = n, y = k;
    if (n == 0) { cout << k; return 0; } //log(0) undefined
    if (k == 0) { cout << n; return 0; }
    long long int len_n = int(log10(n)) + 1, len_k = int(log10(k)) + 1;
    if (len_n > len_k) { cout << n; }
    else if (len_n < len_k) { cout << k; }
    else {
        long long int num_n, num_k, count_n = 0, count_k = 0;
        for (long long int i = 0; i < len_n; i++) { 
            num_n = n % 10; num_k = k % 10;
            count_n += num_n; count_k += num_k;
            n /= 10; k /= 10;
        }
        if (count_n > count_k) { cout << x; }
        else { cout << y; } 
    }
    return 0;
}

The problem is that it fails test case 4 on the online judge. What am I missing?

v_head
  • 759
  • 4
  • 13
  • What is your question? – Jabberwocky Oct 10 '19 at 10:51
  • 1
    If it works for every possible input you could think of, that's good, isn't it? Do you ask for a small code review or are there any problems with your code? – Lukas-T Oct 10 '19 at 10:51
  • Sorry I edited it the question. – v_head Oct 10 '19 at 10:57
  • What do you mean by "modules"? – molbdnilo Oct 10 '19 at 11:03
  • 1
    It's probably a problem that you're using `log10` (never introduce floating point in a problem about integers). You don't need it, and your code is unnecessarily complicated. Write a function that sums the digits in an integer, call it twice and compare the results. – molbdnilo Oct 10 '19 at 11:06
  • 1
    Unrelated: Since you are dealing with natural numbers, use an `unsigned` type. – Ted Lyngmo Oct 10 '19 at 11:07
  • 1
    @V_head If you want to compare the sums of the digits, you don't need to determine how many those digits are, you only need repeated division. – molbdnilo Oct 10 '19 at 11:23
  • I don't understand what "_Compare them by their digits and write the greater one_" means. Could it be `std::max(n, k);` ? If it's the number of digits they mean, then `1` and `2` would be equal, but the [site](https://ejudge.kreosoft.ru/en/tasks/task/51/) says the answer should be `2`. – Ted Lyngmo Oct 10 '19 at 11:24
  • 1
    @TedLyngmo There seems to be an issue with the translation: the problem is to find the greater sum of digits, not the greater number. – molbdnilo Oct 10 '19 at 11:26
  • 1
    What is test case 4? – mkrieger1 Oct 10 '19 at 20:57

2 Answers2

1

You could read the numbers as std::strings and compare them by lexicographical order:

#include <iostream>
#include <string>

int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    std::string number1;
    std::string number2; 
    std::cin >> number1 >> number2;
    std::cout << std::max(number1, number2) << '\n';

    return 0;
}
Thomas Sablik
  • 16,127
  • 7
  • 34
  • 62
  • Do you have an idea why the other answer is faster? I thought that parsing an input as an integer, the `%` and the `/` operations should take very long compared to accessing a `string`. – mch Oct 10 '19 at 12:06
  • No, I have no idea. I used http://quick-bench.com/GciBw5M9WFlBUwodMBo0wbw-hU0 to compare them. There you can find the disassembly. The other answer's disassembly is much shorter. – Thomas Sablik Oct 10 '19 at 12:09
  • I think it is not a fair test. Your reading of the input into `string`s is way faster than the reading into `unsigned long long`. If you have the number in a stream both functions are almost equal: http://quick-bench.com/WkRoptHdXuLkBBJ6NIBwvJgNOus – mch Oct 10 '19 at 12:22
  • @mch ok, I removed the performance comparison from my answer. – Thomas Sablik Oct 10 '19 at 12:47
  • @ThomasSablik,Thomas, Actually what is wanted is comparing numbers by single digits rather than the sum, so what you have if you have 1119 and 9000, the comparison would go 9>1, and so on, or there is some better way, should I use array to store, or just taking the input directly subjecting it to division? Thanks – v_head Oct 12 '19 at 08:15
  • @V_head ok I fixed my answer. That makes it much simpler. – Thomas Sablik Oct 12 '19 at 10:32
  • Yes, I just accepted it as a solution, generally. – v_head Oct 12 '19 at 17:06
  • I have just removed my acceptance. Sorry – v_head Oct 12 '19 at 17:22
  • BTW, I made my version and it passed the test. – v_head Oct 12 '19 at 17:22
  • 1
    @V_head why did you remove the acceptance. This answer and the other answer answers your question and solves your problem. Please accept one of these amswers – Thomas Sablik Oct 12 '19 at 17:41
  • @ThomasSablik I'm pretty sure it was because I questioned his/her decision to remove the acceptance from my answer and put it on yours. He/she revealed further restrictions (no `std::string` allowed) after the question was first posted. ... and now none of the answers is accepted :-D – Ted Lyngmo Oct 12 '19 at 18:07
1

If the problem is indeed to find the greater sum of the digits in two natural numbers, you could make a helper function out of your inner loop, but skip the log10 operation to get the length. Just check if your value is not 0:

inline unsigned sum_digits(unsigned long long x) {
    unsigned result = 0;
    while(x) { // loop for as long as "x" still carries a digit
        result += static_cast<unsigned>(x % 10);
        x /= 10;
    }
    return result;
}

Doing the comparison will then be easy. if(sum_digits(n) < sum_digits(k)) ...

If you want to find the largest of the numbers by comparing them digit by digit, the below approach can work.

#include <iostream>
#include <numeric>
#include <string>

const std::string& comp(const std::string& n, const std::string& k) {
    if(k.size() < n.size())
        return n;
    else if(n.size() < k.size())
        return k;
    else
        for(size_t i = 0; i < n.size(); ++i) {
            if(n[i] < k[i])
                return k;
            else if(k[i] < n[i])
                return n;
        }
    return n; // or k, they are equal
}

int main() {
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    unsigned long long n;
    unsigned long long k;
    if(std::cin >> n >> k) {
        std::cout << comp(std::to_string(n), std::to_string(k)) << "\n";
    }
}

If you for any reason can't use std::string, build what you need for the task at hand. Example:

#include <cstdint>
#include <iostream>

// Convert a number to a reversed character array and return the length.
// Only acccept destination arrays exactly fit to store the largest
// possible number for uint64_t (18446744073709551615) which is 20 chars
// plus a zero terminator.
size_t to_reversed_char_array(std::uint64_t x, char (&dest)[21]) {
    char* d_ptr = dest;

    // 0 isn't a natural number, but we'll deal with it anyway
    if(x > 0) {
        // loop for as long as "x" still carries a digit
        for(; x; x /= 10, ++d_ptr)
            // make a char out of the last 10-based digit in "x"
            *d_ptr = static_cast<char>(x % 10 + '0');
    } else { // special case if x == 0
        d_ptr[0] = '0';
        ++d_ptr;
    }
    // null termiator - It's not needed for this to work
    // but if you'd like to print the result out, it is.
    *d_ptr = '\0';

    // Cast from the signed std::ptrdiff_t (the type of the result when subtracting
    // a pointer from another) to size_t, which is safe since we know d_ptr can't
    // be less than dest.
    // The length is also guaranteed to be at least 1
    return static_cast<size_t>(d_ptr - dest);
}

// find the largest number by comparing them digit by digit
std::uint64_t extremely_slow_max(std::uint64_t n, std::uint64_t k) {
    char n_str[21], k_str[21];

    size_t n_len = to_reversed_char_array(n, n_str);
    size_t k_len = to_reversed_char_array(k, k_str);

    if(n_len < k_len)
        return k;
    else if(k_len < n_len)
        return n;

    do {
        // loop from the end of the arrays and compare the numbers digit by digit
        --n_len; // or k_len, they are equal
        if(n_str[n_len] < k_str[n_len])
            return k;
        else if(k_str[n_len] < n_str[n_len])
            return n;
    } while(n_len);

    return n; // or k ... they are equal
}

int main() {
    std::uint64_t n;
    std::uint64_t k;

    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);

    if(std::cin >> n >> k) {
        // std::cout << std::max(n, k) << "\n";
        std::cout << extremely_slow_max(n, k) << "\n";
    }
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Actually what is wanted is comparing numbers by single digits rather than the sum, so what you have if you have 1119 and 9000, the comparison would go 9>1, and so on, or there is some better way, should I use array to store, or just taking the input directly subjecting it to division? Thanks – v_head Oct 12 '19 at 10:11
  • @V_head That's the alternative solution I just added. – Ted Lyngmo Oct 12 '19 at 10:12
  • I can't use strings. The problem is in the arrays section and strings yet to come. – v_head Oct 12 '19 at 10:14
  • @V_head What do you mean by "_I can't use strings_"? What is stopping you? – Ted Lyngmo Oct 12 '19 at 10:16
  • Because the problem is in an array section, and it comes before the string one, and if a section comes before another one, then, you can't use the the after section. – v_head Oct 12 '19 at 10:25
  • @V_head What "_array section_"? There's no "_array section_" in the question. – Ted Lyngmo Oct 12 '19 at 10:27
  • @V_head I'm not sure I understood what you meant by that last restriction you posed, but I added a solution to what I think you meant. – Ted Lyngmo Oct 12 '19 at 12:08
  • @It is, I'll update a solution soon that doesn't use strings. But yours does it too. Thanks – v_head Oct 12 '19 at 12:24
  • @V_head You are welcome, but "_update a solution_"? If a proposed answer answers the question you posed, you should accept it. If you have a solution to your question that is entirely different than any of the proposed solutions, post it as an answer to your own question. Don't update your question and put a solution in it. – Ted Lyngmo Oct 12 '19 at 12:29
  • Understood! I ll try this – v_head Oct 12 '19 at 12:47
  • @V_head I noticed that you've only accepted answers to two of the questions you've asked here - and most of your questions have actuallly gotten pretty solid answers as I see it. This may affect people's willingness to answer your questions in the future. – Ted Lyngmo Oct 12 '19 at 13:13
  • I haven't accepted any answers. – v_head Oct 12 '19 at 13:21
  • @V_head That would make it even worse, but you've actually accepted [this one](https://stackoverflow.com/a/58143383/7582247) and [this too](https://stackoverflow.com/a/58156032/7582247). – Ted Lyngmo Oct 12 '19 at 13:25
  • Right right! I am going to accept. – v_head Oct 12 '19 at 13:32
  • @V_head Thanks, but I think the other questions answer's deserve acceptance more than this. :-) This question (and our answers) will be purged from SO soon since the question was put on hold (and that is unlikely to change). The other questions, and their answers, will be here ~ _forever_. – Ted Lyngmo Oct 12 '19 at 13:34
  • I see. You re right, I am just so stressed with study, so I don't give much attention. Thanks – v_head Oct 12 '19 at 14:14
  • @V_head I get it :-) I'd wish you good luck, but that's hardly needed since you're obviously working hard. – Ted Lyngmo Oct 12 '19 at 14:17
  • Absolutely, it is just scores makes stressing :( But it ll be all fine, like Disney World :D – v_head Oct 12 '19 at 14:26
  • @V_head I see that you are back to having only accepted two answers here at SO. Take 2 minutes and go though the questions and the answers you've gotten. The people taking the time to write answers to your questions deserve it. – Ted Lyngmo Oct 12 '19 at 17:25