2010-04-06 27 views
6

Đúp có phạm vi nhiều hơn số nguyên 64 bit, nhưng độ chính xác của nó thấp hơn giá trị biểu diễn của nó (vì đôi là 64 bit, nó có thể không phù hợp với giá trị thực tế hơn). Vì vậy, khi đại diện cho các số nguyên lớn hơn, bạn bắt đầu mất độ chính xác trong phần nguyên.Tìm số nguyên tối đa mà một loại dấu phẩy động có thể xử lý mà không mất độ chính xác

#include <boost/cstdint.hpp> 
#include <limits> 

template<typename T, typename TFloat> 
void 
maxint_to_double() 
{ 
    T i = std::numeric_limits<T>::max(); 
    TFloat d = i; 
    std::cout 
     << std::fixed 
     << i << std::endl 
     << d << std::endl; 
} 

int 
main() 
{ 
    maxint_to_double<int, double>(); 
    maxint_to_double<boost::intmax_t, double>(); 
    maxint_to_double<int, float>(); 
    return 0; 
} 

in này:

2147483647 
2147483647.000000 
9223372036854775807 
9223372036854775800.000000 
2147483647 
2147483648.000000 

Lưu ý cách tối đa int có thể phù hợp với một double mà không làm mất độ chính xác và boost::intmax_t (64-bit trong trường hợp này) thì không thể. float thậm chí không thể giữ int.

Bây giờ, câu hỏi: có cách nào trong C++ để kiểm tra xem toàn bộ phạm vi của một loại số nguyên nhất định có thể vừa với loại điểm loanh mà không mất độ chính xác không?

Tốt,

  • nó sẽ là một tấm séc thời gian biên dịch có thể được sử dụng trong một sự khẳng định tĩnh,
  • và sẽ không liên quan đến liệt kê các hằng số trình biên dịch nên biết hoặc có thể tính toán.
+1

Tại sao bạn phải kiểm tra? Phần nguyên có độ chính xác 52 bit, vì vậy đó là số tiền bạn nhận được. –

+0

Khi bạn đã xác định giới hạn, bạn không thể chỉ định một CONST? –

+2

@Billy: _Technically_ C++ không yêu cầu điểm nổi IEEE 754, vì vậy giả sử việc triển khai sử dụng IEEE 754 không phải là di động (thực tế là IEEE 754 có mặt khắp mọi nơi). –

Trả lời

6

Chỉ cần một chút vị:

#include <limits> 

template <typename T, typename U> 
struct can_fit 
{ 
    static const bool value = std::numeric_limits<T>::digits 
          <= std::numeric_limits<U>::digits; 
}; 

#include <iostream> 

int main(void) 
{ 
    std::cout << std::boolalpha; 

    std::cout << can_fit<short, float>::value << std::endl; 
    std::cout << can_fit<int, float>::value << std::endl; 

    std::cout << can_fit<int, double>::value << std::endl; 
    std::cout << can_fit<long long, double>::value << std::endl; 

    std::cout << can_fit<short, int>::value << std::endl; 
    std::cout << can_fit<int, short>::value << std::endl; 
} 

thử nghiệm nếu độ chính xác nhị phân có sẵn trong một T tồn tại trong một U. Hoạt động trên tất cả các loại.


"Boostified":

// this is just stuff I use 
#include <boost/type_traits/integral_constant.hpp> 

template <bool B> 
struct bool_type : boost::integral_constant<bool, B> 
{ 
    static const bool value = B; 
}; 

typedef const boost::true_type& true_tag; 
typedef const boost::false_type& false_tag; 

// can_fit type traits 
#include <limits> 

namespace detail 
{ 
    template <typename T, typename U> 
    struct can_fit 
    { 
     static const bool value = std::numeric_limits<T>::digits 
           <= std::numeric_limits<U>::digits; 
    }; 
} 

template <typename T, typename U> 
struct can_fit : bool_type<detail::can_fit<T, U>::value> 
{ 
    typedef T type1; 
    typedef U type2; 

    static const bool value = detail::can_fit<T, U>::value; 
}; 

// test 
#include <iostream> 

namespace detail 
{ 
    void foo(true_tag) 
    { 
     std::cout << "T fits in U" << std::endl; 
    } 

    void foo(false_tag) 
    { 
     std::cout << "T does not fit in U" << std::endl; 
    } 
} 

// just an example 
template <typename T, typename U> 
void foo(void) 
{ 
    detail::foo(can_fit<T, U>()); 
} 

int main(void) 
{ 
    foo<int, double>(); 
} 
+0

+1 cho 'can_fit'. – AraK

5

Bạn có thể sử dụng std::numeric_limits<T>::digits để biết bạn có bao nhiêu độ chính xác nhị phân. ví dụ:

int binary_digits_double = numeric_limits<double>::digits;  // 53 
int binary_digits_long_long = numeric_limits<long long>::digits; // 63 
int binary_digits_uint = numeric_limits<unsigned int>::digits; // 32 
+0

Tôi đang sử dụng VC, đó là lý do tại sao bạn thấy 'long long' trong câu trả lời của tôi mặc dù nó không phải là tiêu chuẩn được nêu ra. – AraK

+1

'long long' cũng được GCC và ICC chấp nhận. Tôi chắc chắn DMC và một vài người khác cũng vậy. Đó là một phần mở rộng * rất * phổ biến. – greyfade

+0

Ít nhất nó tốt hơn sử dụng, nói __int64. –

Các vấn đề liên quan