0

I am writing my own class(called "Longer") such that it can hold a number without any upper bound unlike int. I am using std::string for this. I am having problem on performing addition.

  1. If i simply add two string, i can't get correct result.
  2. I thought of converting string to int and then performing addition, but long string can't be converted to int.

How can i define my own way of adding two strings so that i get the desired result? Here is the code:

Longer.h

#pragma once
#include <string>

class Longer
{
public:
   Longer(std::string number);
   Longer add(Longer num2);
   void print();
private:
   std::string number;
};

Longer.cpp

#include "Longer.h"
#include <iostream>
#include <string>

Longer::Longer(std::string num): number(num)
{
}

Longer Longer::add(Longer num2){
  return Longer(number+num2.number);
}

void Longer::print(){
std::cout<<number<<"\n";
}

main.cpp

#include <iostream>
#include "Longer.h"

int main(){

Longer num1("123456789101112");
Longer num2("121110987654321");


Longer num3 = num1.add(num2);
num3.print();

}
6
  • You would be better off using the datatype long long int or unsigned long long int. It's unlikely that you'll need a variable longer than that, to hold a number. There's also long double. Commented Aug 10, 2014 at 9:50
  • 3
    @Nav How would that fix the general problem? It is bounded, just like any other built-in integer type. Commented Aug 10, 2014 at 9:50
  • @juan: There was a time when even I had thought of creating such a program. But then I learnt that string operations are much slower, and about the existence of long long int etc. If a programmer thinks a user might type an unusually long number, then I feel the algorithm should be more focused on splitting the number into more workable components (using number datatypes) which can perform calculations faster than a string, rather than use the number as a string and try performing calculations on it. Commented Aug 10, 2014 at 9:56
  • Perhaps some other container holding intmax_t, like std::vector<intmax_t> would be more suitable. String seems entirely the wrong container for this work. Commented Aug 10, 2014 at 9:58
  • @Nav as long as you're already performing string operations, you may as well use a dynamic container. Nobody said this would be used for high performance operations. Commented Aug 10, 2014 at 10:00

4 Answers 4

4

I don't wonder addition doesn't work like you intended. std::string is not meant to be used as an arbitrary-long number container, that's why.

You must define your own way to "add" two strings, which should consist into iterating backwards both strings (from the end) and compare single characters, by interpreting them as numbers.

Sign up to request clarification or add additional context in comments.

2 Comments

+1 It's amazing how addition becomes so natural to people that they "forget" how it's actually done :)
@FredOverflow +1 One of the most interesting student project is to do an any-base, unlimited digit size calculator for the 4 basic integer operation. Often enlighten your comprehension of arithmetic.
0

without any upper bound unlike int

Be careful with such things. There will always be some upper bound with any solution, at the very least when your machine's memory is exhausted. A robust application should always have some kind of error checking.

If i simply add two string, i can't get correct result.

Well, that's obvious, isn't it? String concatentation doesn't know anything about mathematical semantics.

I thought of converting string to int and then performing addition, but long string can't be converted to int.

Exactly. Internally converting the string to a built-in type would defeat the whole purpose of the solution.

How can i define my own way of adding two strings so that i get the desired result?

The goal is apparently to support numbers bigger than what the built-in types provide.

First of all, are you really sure that your application needs to work with such huge numbers? Even a standard int should usually be more than enough, not to mention long long (standard since C++11 but practically usable even before that).

Perhaps what you really need is to detect invalid user input like "10000000000000000000000000".

String streams provide this error detection for you. Here is a complete example for you to play with, including exemplary usage of std::numeric_limits:

#include <iostream>
#include <stdexcept>
#include <exception>
#include <limits>

int ReadInt()
{
    int result;
    std::cin >> result;
    if (!std::cin)
    {
        throw std::runtime_error("Illegal number");
    }
    return result;
}

int main()
{
    try
    {
        std::cout << "Enter number (max: " << std::numeric_limits<int>::max() << ") > ";
        int input = ReadInt();
        std::cout << "You entered the following number: " << input << "\n";
    }
    catch (std::exception const &exc)
    {
        std::cerr << exc.what() << "\n";
    }
}

Here are three example runs on my machine. The first with a "normal" small number, the second just barely larger than the maximum possible, the third exactly the largest possible integer:

Enter number (max: 2147483647) > 1000
You entered the following number: 1000

Enter number (max: 2147483647) > 2147483648
Illegal number

Enter number (max: 2147483647) > 2147483647
You entered the following number: 2147483647

Now, if you really really must support large integer numbers internally, don't reinvent the wheel. Use Boost.Multiprecision:

http://www.boost.org/doc/libs/1_55_0/libs/multiprecision/doc/html/index.html

Since the documentation of that particular library may be a bit hard to swallow, here is an ultra-simple example to get you started:

#include <iostream>
#include <stdexcept>
#include <exception>
#include <boost/multiprecision/cpp_int.hpp>

int main()
{
    try
    {
        boost::multiprecision::int128_t number("100000000000000000000000000000000");

        number *= 2;

        std::cout << number << "\n";
    }
    catch (std::exception const &exc)
    {
        std::cerr << exc.what() << "\n";
    }
}

This actually prints 200000000000000000000000000000000.

Comments

0
#include <iostream>
using namespace std;

class Longer {
public:
    Longer(std::string number): number(number) {}
    void print() { cout << number << endl; }
    Longer add(Longer num2) {
        char over = '0'; string it;
        for(int i = number.size() - 1,
          j = num2.number.size() - 1;
          i >= 0 || j >= 0; i--, j--) {
            char one = i >= 0 ? number[i] : '0';
            char two = j >= 0 ? num2.number[j] : '0';
            char dig = one-'0' + two-'0' + over;
            over = '0'; if(dig > '9') {
                dig -= 10; over = '1'; }
            it.insert(0, 1, dig);
        }
        if(over != '0') it.insert(0, 1, over);
        return Longer(it);
    }
private:
   std::string number;
};

int main() {
    Longer num1("123456789101112"); num1.print();
    Longer num2("121110987654321"); num2.print();
    Longer num3 = num1.add(num2);   num3.print();
}

Output:

123456789101112
121110987654321
244567776755433

But if that was not homework, look at boost::multiprecision::cpp_int

Comments

0

Here is a ready to use solution

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <iterator>

class Longer
{
public:
    Longer() : value( 1, '0' ) {}

    Longer (std::string s ) 
        : value( s.rbegin(), s.rend() )
    {}

    Longer( const char *s ) 
        : value( std::reverse_iterator<const char *>( s + std::strlen( s ) ),
                 std::reverse_iterator<const char *>( s ) )
    {}             

    const Longer add( const Longer &number ) const;

    void print( std::ostream &os = std::cout ) const
    {
        os << std::string( value.rbegin(), value.rend() );
    }

private:
    std::string value;
};

const Longer Longer::add( const Longer &number ) const
{
    std::pair<std::string::size_type, std::string::size_type> sizes = 
        std::minmax( this->value.size(), number.value.size() );

    std::string result;
    result.reserve( sizes.second + 1 );

    int overflow = 0;

    auto out = std::transform( this->value.begin(), 
                               std::next( this->value.begin(), sizes.first ),
                               number.value.begin(), 
                               std::back_inserter( result ),
                               [&] ( char c1, char c2 ) ->char
                               {
                                   char c = ( c1 - '0' ) + ( c2 -'0' ) + overflow;
                                   overflow = c / 10;
                                   return c % 10 + '0';
                               } );

    std::string::const_iterator first, last;

    if ( this->value.size() < number.value.size() )
    {
        first = std::next( number.value.begin(), sizes.first );
        last  = number.value.end();
    }
    else
    {
        first = std::next( this->value.begin(), sizes.first );
        last  = this->value.end();
    }

    std::transform(first, last, out,
                   [&]( char c )
                   {
                       return ( c = c - '0' + overflow ), 
                              ( overflow = c / 10 ),
                              ( c % 10 + '0' );  
                   } );

    if ( overflow ) result.push_back( overflow + '0' );

    Longer n;
    n.value = result;

    return n;
}



int main() 
{
    Longer n1( "12345678912345678" );

    n1.print();
    std::cout << std::endl;

    Longer n2( "1123" );

    n2.print();
    std::cout << std::endl;

    Longer n3 = n2.add( "877" );

    n3.print();
    std::cout << std::endl;

    Longer n4( "9999999999" );

    n4.print();
    std::cout << std::endl;

    Longer n5 = n4.add( "1" );

    n5.print();
    std::cout << std::endl;

    return 0;
}

The output is

12345678912345678
1123
2000
9999999999
10000000000

Take into account that it is more convinient to store the string in the reverse order inside the class.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.