2016-12-10 17 views
3

그래서 간단한 정수 클래스를 만들려고 노력 중이며 인터넷과 일부 페이지를 읽었지만 막혀 있습니다. . 나는 이론을 알고 있고 나는 캐리가 필요하다는 것을 안다. 그러나 내가 본 모든 예들, 그들은 문자들과 10 진법에 더 많이 촛점을 맞추었고, 나는 좀 더 빨라진 다른 접근법을 사용하고있다. 더하기 대입 연산자에 대한 도움을 주시면 감사하겠습니다. 나머지는 직접 알아볼 것입니다.빅 정수 또한 이론을 알고 있습니다 ... 실제로는 녹슬지 않습니다.

#include <iostream> 
#include <string> 
#include <vector> 

using std::cout; 
using std::endl; 

class big_integer { 
    using box = std::vector<int unsigned>; 
    box data {0}; 

    box split(std::string const & p_input) const { 
     box output; 
     for (size_t i {}; i < p_input.size(); i += 8) { 
      output.push_back(stoi(p_input.substr(i, 8))); 
     } 
     return output; 
    } 

public: 
    big_integer(std::string const & p_data) 
     : data {split(p_data)} 
    {} 

    big_integer(int unsigned const p_data) 
     : data {p_data} 
    {} 

    big_integer & operator +=(big_integer const & p_input) { 
     int carry {}; 

     for (size_t i {}; i < data.size(); ++i) { 

      //Need help here! 
      //All examples I see either use primitive arrays 
      //or are too esoteric for me to understand.    
      //data[i] += p_input.data[i] + carry; 

     } 

     return *this; 
    } 

    std::string to_string() const { 
     std::string output; 
     output.reserve(data.size() * 8); 
     for (auto const i : data) { 
      output.append(std::to_string(i)); 
     } 
     return output; 
    } 
}; 

std::ostream & operator <<(std::ostream & p_output, big_integer const & p_input) { 
    return p_output << p_input.to_string(); 
} 

int main() { 
    big_integer test1 {"126355316523"}; 
    big_integer test2 {255}; 

    test1 += test1; 

    cout << test1 << endl; 
    cout << test2 << endl; 
    return 0; 
} 
+3

정확히 무엇이 문제입니까? 벡터는 그 점에서 단순한 배열과 매우 흡사합니다. 또한 기본은별로 중요하지 않습니다. 접근 방식은 동일하게 유지됩니다. –

+1

10이 아니라면 어떤 기반을 사용하기로 결정 했습니까? –

+0

아, 나는 그렇게 바보 같은 사람이다. (그렇다면'data [i] = (data [i] + p_input.data [i] + carry) % 10; carry = (data [i] ] + p_input.data [i] + carry)/10'이 그 속임수를 사용합니까? –

답변

4

오른쪽. 그래서 기본적인 문제는 unsignedcarry을주는 unsigned + unsigned + carry하는 방법입니다. 16 비트 정수를 고려하면 (32 비트에서 동일하게 작동하지만 입력이 더 많음) 첫 번째 숫자에서 0xFFFF + 0xFFFF == 0xFFFE + 1의 자리 올림 다음의 숫자 0xFFFF + 0xFFFF + carry == 0xFFFF + 캐리. 따라서 캐리는 오직 하나 일 수 있습니다. 이 알고리즘은 다음

unsigned lhs, rhs, carry_in; // Input 
    unsigned sum, carry_out;  // Output 

    sum = lhs + rhs; 
    carry_out = sum < lhs ; 
    sum += carry_in; 
    carry_out = carry_out || sum < lhs; 

기본적 아이디어는 unsigned의 첨가를 수행하고 배치를 검출 (따라서 수행)하는 것이다. 매우 성가신 것은 이것이 내가 사용했던 모든 명령어 세트의 명령어 인 "carry with add"를 구현하기위한 조건부 로직과 다중 명령어의 대량이라는 것입니다. (참고 : 오히려 ||보다 carry_out 사용 |의 최종 계산을 가치가있을 수 있습니다 - 그것은 성능 불량 인 분기 저장 도움이된다면 언제나처럼, 프로필을 볼 수 있습니다..)

당신은 결국에가는 경우 곱셈을 지원하려면 "자리"의 두 배인 유형이 필요합니다.이 경우 추가 할 수도 있습니다. 위의 변수를 사용하고 "부호 오래 오래"가정하는 것은 당신의 "폭"유형 :

const auto temp = (unsigned long long)lhs + rhs + carry_in; 
    sum = temp; // Will truncate. 
    carry_out = temp > UINT_MAX; 

당신의 "폭"유형을 선택하는 것은 까다로운 일이 될 수 있습니다. 첫 번째 단계에서 숫자에 uint32_t, 넓은 유형에 uint64_t을 사용하는 것이 가장 좋습니다.

다중 정밀도 산술을 구현하는 방법에 대한 자세한 내용은 Chapter 14 from Handbook of Applied Cryptography이 유용합니다.

+0

'||'대신'| '를 사용하면 위의 분기가 제거됩니다. 이것은 여분의 데이터 읽기 및 쓰기의 가치가있을 수도 있고 없을 수도 있지만 성능을보다 일관되게 만듭니다. – Yakk

+0

@BeyelerStudios : 아, 고마워. 나는 머리 꼭대기에서 이것을하고 있었고 오직 하나만 필요하다는 것을 자신에게 확신시킬 수 없었다. 나는 캐리를 추가 한 후에 *와 *를 모두 확인해야한다고 확신한다. –

+0

사실, 나는 어떤 기지에서 (10-1) + (10-1) == 20-2이므로 첫 번째 숫자의 최대 자리수는 1이므로 (10-1) + (10- 1) +1 == 20 - 1, 캐리는 1을 초과 할 수 없습니다. –