1

I'm trying to subtract strings where each ASCII character is treated as a decimal digit. For instance:

"1000000000001" - "0100000000001" = "900000000000"

How would I get started on an implementation of this if my function prototype looked like:

char* get_sub(char* a, char* b)

user997683
  • 13
  • 1
  • 4
  • In the same way you would do it on paper? – xanatos Oct 16 '11 at 09:55
  • try with `boost::lexical_cast`, if it is a homework your teacher probably what a loop over the digits – Ruggero Turra Oct 16 '11 at 09:56
  • 3
    C or C++ ? They are two different languages. – Paul R Oct 16 '11 at 10:01
  • 2
    At least one of "everything" must be the solution, so you have by definition not tried everything. Everything you can *think of* perhaps? Since this is homework, you should post what you have tried - or at least the most promising attempts so far. Also what methods have you covered in class; for example is a recursive solution acceptable, to must it be iterative? Many CS classes like to teach recursion, even though in the real world it should be used with more caution that is usually advised in such classes. – Clifford Oct 16 '11 at 10:15

4 Answers4

6

Just remember how you learned to do subtraction of large numbers in your Algorithms 001 class, the primary school. Subtract the least significant digits of both numbers, add 10 if smaller than 0, remember carry, go on to next digit pair.

thiton
  • 35,651
  • 4
  • 70
  • 100
  • this is not so a "large number" – Ruggero Turra Oct 16 '11 at 09:57
  • 3
    @wiso: When I was in primary school, the definition of "large number" was "anything so large you can't reliably subtract it within your head", which means for a computer working with char arrays "anything larger than one digit". – thiton Oct 16 '11 at 09:59
  • @wiso: Really; what sort of numbers did you deal with in primary school!? In the context described in the answer it is a "large number", even if it is not "large" in a computational sense. – Clifford Oct 16 '11 at 10:11
  • @Clifford: this is a programming Q&A website not a primary school Q&A – Ruggero Turra Oct 16 '11 at 10:23
  • 1
    @wiso: So? A legitimate teaching technique is to relate the unfamiliar to the familiar, the answer was helpfully attempting to do that. Your comment in that context was pedantic, irrelevant, unnecessary and unhelpful, and suggests that you may have entirely missed the point. – Clifford Oct 16 '11 at 10:32
1

It doesn't seems, but it's a quite complex problem (unless I'm getting too much old). This works only in N. So it must be true that a >= 0, b >= 0, a >= b. I won't explain how does it works. As I've written, it's quite complex :-) (and I'm not even happy of what I've written. I'm sure there is something I haven't thought)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* get_sub(const char* a, const char* b);

#define MAX(a, b) (((a) > (b)) ? (a) : (b))

int main(int argc, char* argv[])
{
    char *res = get_sub("10000","9999");
    printf("%s\n", res);
    free(res);
    return 0;
}

char* get_sub(const char* a, const char* b)
{
    size_t a1len = strlen(a);
    size_t a2len = strlen(b);

    size_t max = MAX(a1len, a2len);

    /* I'm using calloc to make it easier to debug. You could use malloc, but you'll have to uncomment a line below */
    char *res = (char*)calloc(max + 1, sizeof(char));

    int carry = 0;

    char *pres = res;
    for (const char *pa = a + a1len - 1, *pb = b + a2len - 1; pa >= a || pb >= b; pa--, pb--, pres++)
    {
        int val1 = pa >= a ? (*pa - '0') : 0;
        int val2 = pb >= b ? (*pb - '0') : 0;

        int diff = val1 - carry - val2;

        if (diff >= 0)
        {
            *pres = (char)(diff + '0');
            carry = 0;
        }
        else
        {
            *pres = (char)(10 + diff + '0');
            carry = 1;
        }
    }

    if (carry != 0)
    {
        free(res);
        return (char*)calloc(1, 1);
    }

    /* *pres = '\0'; */ /* Uncomment this line to use malloc */

    pres--;

    while (pres > res && *pres == '0')
    {
        *pres = '\0';
        pres--;
    }

    strrev(res);

    return res;
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • 2
    For homework questions it is preferable to give helpful hints and suggestions rather than complete solutions, otherwise the student does not learn anything. – Paul R Oct 16 '11 at 10:33
  • @PaulR If I have to tell the truth, the problem IS very complex. Even looking at the code, I'm not sure he will comprehend what it's written. I'm very sad I wasn't even able to make it work in `Z` instead of `N` (at least for the result) (technically I had a version that simply switched `A` and `B` and added a minus if the first subtraction was < 0, but I don't think it's the solution) – xanatos Oct 16 '11 at 10:36
  • Possibly - but he can just copy and paste this and submit it as a solution to his homework problem and thereby learn nothing in the process. If you give general hints and suggestions then he has to write some actual code himself. – Paul R Oct 16 '11 at 10:38
  • 1
    @PaulR I'm of the school of thought that we should give the rope to the persons and then let them decide if they want to hang themselves. I can't save them. Only they can save themselves. Simply reading this code he could ask himself questions he wouldn't have asked himself, like "why was the macro MAX written in that way?" or "what is a `const char*` and why is he using it so often? Or "what is a `size_t`"? Or "what is `calloc`"? I DO think that these questions are more interesting than a stupid problem. But in the end, right and wrong are in the eye of the observer. – xanatos Oct 16 '11 at 10:43
  • @PaulR Now... If this will make you feel better, you can downvote my post to make a point. I will let it remain for a week to make my point and then I'll delete it, so I'll get back my points, the student will have his homework done and no one else will be able to copy the code :-) – xanatos Oct 16 '11 at 10:47
  • @user997683 Be aware that if you don't **really** comprehend this code, it's quite probable your teacher will notice quite quickly (even because this code, as written, is quite "well done"). As a suggestion you should study it and then try to rewrite it. – xanatos Oct 16 '11 at 10:55
  • Agree the burden should be on the teachers...their job is to vet for understanding. Otherwise it's academic laziness, re-emphasized by the un-enlightening nature of many assignments that show up here. So I don't see giving a solution that "works" as being bad for "ruining the academic integrity"...screw that model, time to set the controls for the heart of the sun on factory education. The bad part though is you're kind of ruining the student's ability to experience the enthusiasm they get from the first moment they see their program work because of their ingenuity. (Contrast w/my answer.) – HostileFork says dont trust SE Oct 16 '11 at 11:03
  • @xanatos: I haven't down-voted your answer (I don't think anyone has ?) - I was just pointing out that complete solutions probably aren't the best way of helping people with their homework. – Paul R Oct 16 '11 at 14:48
0

Taking the least significant digit of a and b, convert them to an integer by subtracting the value of the character '0'. (Some will correctly state that this is not portable, to which I say get back to me when you have found a practical system in modern use on which this will not work!). If the a digit is less than the b digit, add 10 to the a digit, set a "borrow flag", and subtract the a digit from the b digit. This value is the least significant digit of the answer.

Move to the next least significant digit, if the borrow flag is set, subtract 1 from the a digit, and clear the borrow flag, then repeat as above.

If one string runs out of digits before the other (i.e. is shorter), then the corresponding digit should be taken as being equal to zero.

This can be performed iteratively or recursively; I would not attempt recursion unless it has been specifically taught in the class and is therefore likely to be accepted as a solution, or even the required solution.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

Here is a scaffold for a C++ solution, that doesn't solve the problem, but throws you some linguistic tinker-toys you'd need for a fairly straightforward implementation. It iterates backward through the digits and builds up a result which just has 1s where both numbers have nonzero digits, and 0s otherwise:

#include <string>
#include <iostream>

using namespace std;

// For a more circumspect treatment of the digit/char conversion, read up:
// http://stackoverflow.com/questions/439573/how-to-convert-a-single-char-into-an-int

char charFromDigit(int d) {
    return d + '0';
}

int digitFromChar(char c) {
    return c - '0';
}

// all this routine does is iterate backward through the digits of both
// numbers and build up a result which has a 1 digit if both numbers are
// non-zero for that place value, and a 0 digit if they're both 0

string get_something(const string& a, const string& b) {

    // get reverse ("r"begin) iterators so we can index backwards
    // across the two strings.  This way we look at the last digits
    // first

    string::const_reverse_iterator a_iterator = a.rbegin();
    string::const_reverse_iterator b_iterator = b.rbegin();

    // this variable holds the result that we build

    string result;

    // simple loop that just prints digits as long as the iterators
    // haven't indicated we're out of characters by reaching their
    // respective "r"ends...

    while (a_iterator != a.rend() || b_iterator != b.rend()) {

       int a_digit = 0;
       if (a_iterator != a.rend()) {
           a_digit = digitFromChar(*a_iterator);
           a_iterator++;
       }

       int b_digit = 0;
       if (b_iterator != b.rend()) {
           b_digit = digitFromChar(*b_iterator);
           b_iterator++;
       }

       cout << "A digit " << a_digit << ", B digit " << b_digit << endl;

       int out_digit = 0;
       if ((a_digit != 0) && (b_digit !=0))
           out_digit = 1;

       result.insert(result.begin(), charFromDigit(out_digit));
    }

    return result;
}

int main(int argc, char* argv[]) {
    string a ("1000000000001");
    string b ("0100000000001");

    cout << "A is " << a << endl;
    cout << "B is " << b << endl;

    cout << "Return Value = " << get_something(a, b) << endl;

    return 0;
}

The output of the program is:

A is 1000000000001
B is 0100000000001
A digit 1, B digit 1
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 0
A digit 0, B digit 1
A digit 1, B digit 0
Return Value = 0000000000001

Really it makes a big difference, if you're in a class, if you're solving it in the framework they're teaching you about. If everything you're learning is char* and strlen() and such, you're learning C... not idiomatic C++. In C++ you have a lot more automatic management of memory and an encouragement to use more generic algorithmic approaches.