简体   繁体   English

用户定义类型C ++的添加

[英]Addition on user-defined types C++

I am writing my own class(called "Longer") such that it can hold a number without any upper bound unlike int. 我正在编写自己的类(称为“ Longer”),以便它可以容纳数字,而与int相比没有任何上限。 I am using std::string for this. 我为此使用std :: string。 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. 我曾考虑过将字符串转换为int然后执行加法,但是长字符串不能转换为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 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 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 main.cpp中

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

int main(){

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


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

}

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. std::string并不是要用作任意长数的容器,这就是为什么。

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. 您必须定义自己的方式来“添加”两个字符串,这应包括从两个字符串(从末尾开始)向后迭代,并通过将它们解释为数字来比较单个字符。

without any upper bound unlike int 与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. 我曾考虑过将字符串转换为int然后执行加法,但是长字符串不能转换为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). 即使是标准的int通常也应该绰绰有余,更不用说long long (自C ++ 11起为标准,但在此之前甚至可以实际使用)。

Perhaps what you really need is to detect invalid user input like "10000000000000000000000000" . 也许您真正需要的是检测无效的用户输入,例如“ 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 : 这是一个完整的示例供您使用,包括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 : 使用Boost.Multiprecision

http://www.boost.org/doc/libs/1_55_0/libs/multiprecision/doc/html/index.html 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 . 这实际上打印200000000000000000000000000000000

#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 但是,如果那不是家庭作业,请查看boost :: multiprecision :: cpp_int

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. 考虑到在类内部以相反的顺序存储字符串更方便。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM