문제

cpp_dec_float 임의의 정밀도를 위해 훌륭하지만 모든 중요한 자리를 인쇄하는 방법을 알아내는 데 문제가 있습니다.

예를 들어이 코드를 설정하려면

using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<100>> mp_type;

mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
.

단순히

로 인쇄하는 경우
std::cout << std::scientific << test_num << std::endl;
.

결과는 7.071068e-01이므로 꺼져 있습니다.

에 파산되면

std::cout << std::setprecision(std::numeric_limits<mp_type>::digits) << std::scientific << test_num << std::endl;
.

7.0710678118654752440084436210484903928483593768847403658833986900000000000000000000000000000000000000e-01를 얻습니다. 나는 정확성을 잃지 않아도 행복하지만, 보수적 인 것은 매우 공간이 아닙니다.

기존 도구가있는 모든 정밀도를 잃지 않고 후행 0을 제거하는 방법이 있습니까? 그렇지 않은 경우 어떻게 후행 0이 결과 문자열에서 제거 될 수 있습니까?

기존의 도구를 사용하여 내 의도를 만족시키는 경우 정밀도가 없어지지 않고 과류가 끊어지지 않고 잃어버린 정밀도가 없어지지 않고 과학 표기법에서 cpp_dec_float가 어떻게 될 수 있습니까? 스트림 예제 .

를 찾을 수 있습니다.

더 가깝게

mockinterface 덕분에, 나는 훨씬 더 가깝습니다.

코드를이 코드를 변경했습니다.

using boost::multiprecision::cpp_dec_float;
typedef boost::multiprecision::number<cpp_dec_float<0>> mp_type;
mp_type test_num("7.0710678118654752440084436210484903928483593768847403658833986900e-01");
std::cout << test_num.str(0, std::ios_base::scientific) << std::endl;
.

잠재적으로 무제한 길이를 갖는다. 그러나 이것은 인쇄됩니다.

7.0710678118654752440084436210484903928480e-01
.

가깝지만 이상한 것 같습니다. Source mockinterface가 너무 몹시 지적했다. 나는이 선을 발견

if(number_of_digits == 0)
    number_of_digits = cpp_dec_float_total_digits10;
.

은 기본적으로 무제한의 길이로 인해 입력 된 것을 기본적으로 출력 해야하는 모든 중요한 숫자를 고려해야한다고 제안합니다.

소스 cpp_dec_float_total_digits10 그리고 나는 그것이 무엇인지 정확하게 결정할 수 없습니다. 이 코드 섹션을 찾은 것 같지만

private:
   static const boost::int32_t cpp_dec_float_elem_digits10 = 8L;
   static const boost::int32_t cpp_dec_float_elem_mask     = 100000000L;

   BOOST_STATIC_ASSERT(0 == cpp_dec_float_max_exp10 % cpp_dec_float_elem_digits10);

   // There are three guard limbs.
   // 1) The first limb has 'play' from 1...8 decimal digits.
   // 2) The last limb also has 'play' from 1...8 decimal digits.
   // 3) One limb can get lost when justifying after multiply,
   //    as only half of the triangle is multiplied and a carry
   //    from below is missing.
   static const boost::int32_t cpp_dec_float_elem_number_request = static_cast<boost::int32_t>((cpp_dec_float_digits10 / cpp_dec_float_elem_digits10) + (((cpp_dec_float_digits10 % cpp_dec_float_elem_digits10) != 0) ? 1 : 0));

   // The number of elements needed (with a minimum of two) plus three added guard limbs.
   static const boost::int32_t cpp_dec_float_elem_number = static_cast<boost::int32_t>(((cpp_dec_float_elem_number_request < 2L) ? 2L : cpp_dec_float_elem_number_request) + 3L);

public:
   static const boost::int32_t cpp_dec_float_total_digits10 = static_cast<boost::int32_t>(cpp_dec_float_elem_number * cpp_dec_float_elem_digits10);
.

유효 숫자의 수가 결정되고 boost::multiprecision::cpp_dec_float::str()의 첫 번째 인수로 사용될 수 있습니까?

도움이 되었습니까?

해결책

이것은 힘든 것으로 밝혀졌습니다.

짧은 이야기는 다음과 같습니다. CPP_DEC_FLOAT에 그러한 기능이 없습니다. 더 나쁜 것은, CPP_DEC_FLOAT는 설정된 중요한 자릿수의 수를 추적하지 않으므로 분수를 인쇄하는 데 필요한 길이를 찾는 "저렴한"방법이 없습니다.

아이디어 :

  • 일부 경계의 경우 (예 : 123.000000000000001) 하나는 정수 부분의 분수 부분 + LOG10의 상호 탐색의 log10을 취할 수 있습니다. 이것은 완전히 일반적으로 적용 할 수 없습니다.

  • 구현 세부 정보를 사용하려면 백엔드 배열에서 '마지막 거주지'요소를 찾아서 수학을 수행 할 수 있습니다. 그러나 이것은 예쁜 관련이 있습니다 (cpp_dec_float.hpp 수정 및 많은 테스트가 필요함).

  • 마지막으로, .str()의 현재 구현은 효율적으로 0 노력을 명확하게 만듭니다. 전혀.

그래서 모든 것이 다음과 같은 제안이 있습니다.

  1. gmp 백엔드로 전환하십시오 (당신이 그것을 감당할 수있는 경우). 참고

    • 이것은 소수점 부유물 표현이 아닙니다
    • 추가 라이브러리 (libgmp)를 링크 할 필요가 있습니다
    • gmp_float
    • 임의의 정밀도를 가지고 있습니까?
    • str() 구현 은 mantissa
    • 의 0의 중요성을 고려합니다.

    coliru

    #include <boost/multiprecision/number.hpp>
    #include <boost/multiprecision/gmp.hpp>
    #include <iostream>
    
    namespace mp = boost::multiprecision;
    
    int main()
    {
        typedef mp::number<mp::gmp_float<100>> mp_type;
        mp_type test_num("7.071067811865475244008443621048490392848359376884740365883398690000000000000000000e-01");
    
        std::cout << test_num.str(0, std::ios_base::scientific) << '\n';
    }
    
    .

    더 이상의 조치가 필요없이 7.071067811865475244008443621048490392848359376884740365883398690e-01를 인쇄합니다.

  2. 옵션이 아니라면 출력을 후 처리하여 후행 0을 제거합니다.

    template <typename T>
    std::string to_pretty_string(T const& v)
    {
        std::string s = v.str(0, std::ios_base::scientific);
        assert(s.length()>3); // min: 0.e
        switch (s[0])
        { // normalized scientific always has #.####### form of mantissa
            case '-':
            case '+': assert(s[2] == '.'); break;
            default:  assert(s[1] == '.'); break;
        }
    
        auto exp = s.find('e');
        if (std::string::npos != exp && exp > 0)
        {
            for(size_t pos = exp-1; pos; --pos)
            {
                if (s[pos] != '0')
                {
                    // remove run of 0s if applicable
                    s.erase(pos+1, exp-pos-1); 
                    break;
                }
            }
        }
        return std::move(s);
    }
    
  3. coliru

다른 팁

cpp_dec_float::str() 메소드로 출력 해야하는 숫자 수를 명시 적으로 상태로 지정할 수 있습니다.

std::cout << std::scientific << test_num.str(75) << std::endl;
// output: 0.707106781186547524400844362104849039284835937688474036588339869
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top