2016-07-20 10 views
3

문자열이 유효한 정수인지 확인하고 싶습니다. 난 그냥 std::stoull 또는 std::stoll 같은 64 비트 정수 및 함수를 사용할 수 있지만 값이 주어진 범위 사이에 있는지 확인할 수 없습니다.올바른 방법으로 문자열을 정수로 변환

예를 들어, 0과 UINT64_MAX 사이의 정수를 원합니다. 문자열이 "-1" 인 경우이를 long long으로 변환 할 수 있으며 부정적인 것으로 나타납니다. 그러나 문자열이 최대 길이가 인 (일반적으로 INT64_MAX) 인 경우 문자열이 양의 정수인 동안 오버플로가 다시 음수가됩니다.

친구가 먼저 빼기 기호를 확인하도록 권유했지만이 솔루션이 마음에 들지 않았다면 이중을 사용하는 것에 대해 생각했지만 두 배를 사용하는 비교는 까다로운 일일 수 있음을 알고 있으므로 이 해결책.

template <typename T> 
inline bool is_between(const string &str, 
         T min = numeric_limits<T>::min(), 
         T max = numeric_limits<T>::max()) noexcept 
{ 
    try { 
     double value = stod(str); 

     if (value < min || value > max) 
      return false; 
    } catch (...) { 
     return false; 
    } 

    return true; 
} 

이 기능은 안전한가요? 나는 "1"의 문자열 "0.9999999999"의 두 배 값을 반환 할 수 있다는 것을 두려워하기 때문에, 그것은 그 다음 우리는 다음과 같은 기능을 사용할 수있는 1

(100) 사이의 간격에 맞지 않는 것 :

cout << is_between<uint16_t>("0") << endl; 
cout << is_between<uint16_t>("65535") << endl; 
cout << is_between<uint16_t>("65535", 0, 2000) << endl; 
cout << is_between<uint16_t>("-1") << endl; 
cout << is_between<uint16_t>("800000") << endl; 
+3

'min'과'max'를 문자열로 변환하고 문자열 비교를 해보지 않겠습니까? – NathanOliver

+0

[std :: stoull] (http://en.cppreference.com/w/cpp/string/basic_string/stoul)에서 예외가 발생하지 않습니까? – IInspectable

+0

@IInspectable 만약 입력이 부정적이라면,'std :: stoull'은 올바르게 기억됩니다. – NathanOliver

답변

2

함수는 부동 소수점 숫자로 정확하게 표현할 수있는 정수만큼 작기 때문에 설명하는 오류가 발생하지 않아도 안전합니다. 따라서 1의 변환은 0.99999을 두 배로 표현할 수있는 경우 다른 수이기 때문에 0.99999이 될 수 없습니다. 0.99999에서 1으로의 변환이 가능합니다.

그러나 충분한 수의 숫자가있는 경우 64 비트 배정도는 64 비트 정수보다 소수 부분의 비트 수가 적은 (일반적으로 54이지만 표준에서는 정의되지 않음)이기 때문에 한계 검사가 작동하지 않습니다. 예를 들어 다음 프로그램의 출력은 이고 정확도가 더 높은 것처럼 0이 아닙니다.

#include <iostream> 
#include <string> 

int main(){ 
    long long v=(1l << 54) +1; 
    std::cout << v-static_cast<long long>(std::stod(std::to_string(v))) << std::endl; 
} 

당신이 정말 Boost multiprecision 같은 몇 가지 라이브러리를 사용하는 것이 좋습니다 UINT64_MAX에 가까운 숫자가 필요한 경우

. 임의의 정밀도 정수 cpp_int을 가지며, std::string에서 구성 할 수 있습니다.

+0

에 대한 Dúthomhas의 주장을 재현 할 수 없습니다. 어떻게 가능합니까? 최대 double 값은 부호없는 64 비트의 최대 값보다 훨씬 큽니다. 귀하의 프로그램도 [ideone] (0ideone.com/adPr0v)에 0을 출력합니다. – markand

+0

'long double'과'stold'를 유효한 해결책으로 사용하고 있습니까?그것은이 코드에서 작동하는 것 같다 (http://ideone.com/LVxweZ) – markand

+0

@mark 최대 두 배가 크지 만 일부 비트는 지수를 나타내는 것으로 이동하기 때문에 모든 숫자를 나타낼 수는 없다. . 즉, 충분히 큰 두 배의 경우 두 연속 숫자의 차이가 1보다 큽니다. 이상이있는 이상한 것이 있습니다. 'long long v = (1l << 54) +1;의 결과는'1'입니다. 그 계산 결과를 방금 대신 사용하면 기대 한 것을 줄 것 같습니다. [ideone] (http://ideone.com/k3aoHP)을 참조하십시오. 'long double'이 128 비트이고 가수가 시스템에서 64 비트 이상인 경우 작동합니다. –