繁体   English   中英

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

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

我正在编写自己的类(称为“ Longer”),以便它可以容纳数字,而与int相比没有任何上限。 我为此使用std :: string。 我在执行加法时遇到问题。

  1. 如果我仅添加两个字符串,则无法获得正确的结果。
  2. 我曾考虑过将字符串转换为int然后执行加法,但是长字符串不能转换为int。

如何定义自己添加两个字符串的方式,以便获得所需的结果? 这是代码:

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();

}

我毫不奇怪加法不会像您预期的那样起作用。 std::string并不是要用作任意长数的容器,这就是为什么。

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

与int不同,没有任何上限

小心这些事情。 任何解决方案都将始终存在一些上限,至少在计算机的内存耗尽时。 健壮的应用程序应始终进行某种错误检查。

如果我仅添加两个字符串,则无法获得正确的结果。

好吧,这很明显,不是吗? 字符串连接对数学语义一无所知。

我曾考虑过将字符串转换为int然后执行加法,但是长字符串不能转换为int。

究竟。 在内部将字符串转换为内置类型会破坏解决方案的全部目的。

如何定义自己添加两个字符串的方式,以便获得所需的结果?

显然,目标是支持大于内置类型提供的数量的数字。

首先,您真的确定您的应用程序需要使用如此庞大的数量吗? 即使是标准的int通常也应该绰绰有余,更不用说long long (自C ++ 11起为标准,但在此之前甚至可以实际使用)。

也许您真正需要的是检测无效的用户输入,例如“ 10000000000000000000000000”

字符串流为您提供此错误检测。 这是一个完整的示例供您使用,包括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";
    }
}

这是我的机器上运行的三个示例。 第一个具有“正常”的小数字,第二个仅略大于最大可能的值,第三个恰好是最大可能的整数:

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

现在,如果您真的必须在内部支持大整数,请不要重新发明轮子。 使用Boost.Multiprecision

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

由于该特定库的文档可能有点难以理解,因此以下是一个超简单的示例,可帮助您入门:

#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";
    }
}

这实际上打印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();
}

输出:

123456789101112
121110987654321
244567776755433

但是,如果那不是家庭作业,请查看boost :: multiprecision :: cpp_int

这是一个现成的解决方案

#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;
}

输出是

12345678912345678
1123
2000
9999999999
10000000000

考虑到在类内部以相反的顺序存储字符串更方便。

暂无
暂无

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

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