2015-04-27 21 views
8

Giả sử tôi có hai đối tượng if của các loại tương ứng IF. Tôi biết rằng std::is_integral<I>::value là đúng và std::is_floating_point<F>::value là đúng sự thật.Cách tuân thủ tiêu chuẩn để so sánh float với tích phân?

Có cách nào hoàn toàn tuân thủ tiêu chuẩn cách để tìm hiểu xem giá trị của i có nhỏ hơn giá trị f không? Lưu ý nhấn mạnh vào 'tuân thủ đầy đủ các tiêu chuẩn', đối với câu hỏi này, tôi chỉ quan tâm đến các câu trả lời được sao lưu bởi các đảm bảo từ tiêu chuẩn C++.


Việc thực hiện tầm thường i < I(f) không làm việc, bởi vì giá trị của f có thể không phù hợp với bên i. Việc thực hiện tầm thường F(i) < f không hoạt động, vì độ chính xác của f có thể không đủ để đại diện cho i, gây ra i để làm tròn thành giá trị bằng f (nếu bạn có IEEE754 nổi, 16777219 < 16777220.f không thành công).

Nhưng ở đây có tình trạng tiến thoái lưỡng nan thực sự: nếu bạn muốn sử dụng std::numeric_limits::max để giảm bớt những vấn đề này, bạn quay trở lại vấn đề ban đầu khi so sánh số nguyên và số nguyên! Điều này là do loại std::numeric_limits::max bằng loại ban đầu.

+0

Yêu cầu "cho câu hỏi này tôi chỉ quan tâm đến câu trả lời được sao lưu bằng cách đảm bảo từ C++ chuẩn" là không hợp lý và ngớ ngẩn cho câu hỏi này. Nó giống như yêu cầu một cách để thực hiện sắp xếp bong bóng và yêu cầu câu trả lời được sao lưu bằng tiêu chuẩn C++. Tiêu chuẩn C++ không có gì để nói về sắp xếp bong bóng. –

+0

'i Barry

+3

@ Cheersandhth.-Alf Tôi không đồng ý. Toàn bộ điểm của câu hỏi là tìm một phương thức được định nghĩa rõ ràng trên bất kỳ triển khai C++ nào. Bạn có thể làm điều này cho loại bong bóng, nhưng tôi không chắc chắn bạn có thể cho so sánh này, do đó câu hỏi của tôi. – orlp

Trả lời

0

Đây là cách tôi sẽ làm điều đó:

Tôi đoán rằng f là hữu hạn, các trường hợp vô hạn và NaN phải được xử lý ở những nơi khác.

  1. so sánh f và F (i), nếu không bằng nhau, bạn đã hoàn tất, e, i là một trong hai < hoặc>

  2. nếu bằng nhau, sau đó so sánh I (f) và i

các giả định chỉ là:

  • nếu có một phao có chính xác giá trị i, sau đó F (i) cho rằng v alue

  • nếu có một số nguyên có chính xác cùng một giá trị như f, sau đó tôi (f) cho rằng giá trị

  • đơn điệu của hàm F và tôi

EDIT

Để rõ ràng hơn, các thủ thuật trên là viết một hàm so sánh, không chỉ kiểm tra tính bình đẳng ...

floatType F(intType i); 
intType I(floatType f); 
int cmpfi(floatType f,intType i) 
{ 
    assert(isfinite(f)); 
    if(f < F(i)) return -1; 
    if(f == F(i)) 
    { 
    if(I(f) < i) return -1; 
    return I(f) > i; 
    } 
    return 1; 
} 

Up cho bạn để chuyển đổi dự thảo này vào một mã C++ có thể xử lý floatType khác nhau/intType

+1

Tôi đang tìm kiếm một thử nghiệm đặt hàng, không bình đẳng. – orlp

+0

@orlp, tôi không nêu chi tiết câu trả lời, nhưng những gợi ý này là viết một loại hàm cmp –

+1

Vâng, ở bước 1 bạn đã nói "bạn đã hoàn thành" sau khi tìm ra 'f! = I'. Điều đó rõ ràng không giải quyết được vấn đề :) – orlp

2
  1. Nếu f nằm ngoài phạm vi của I, bạn có thể nói kết quả chỉ bằng dấu hiệu của nó.

  2. Nếu f nằm trong phạm vi I nhưng quá lớn để có phần phân số, hãy so sánh nó như một số nguyên.

  3. Nếu không, nó an toàn để đúc i-F vì làm tròn sẽ không thay đổi kết quả của sự so sánh: f đã nhỏ hơn so với bất kỳ giá trị của I đó sẽ được làm tròn.

.

template< typename I, typename F > 
std::enable_if_t< std::is_integral_v<I> && std::is_floating_point_v<F>, 
bool > less(I i, F f) { 
    // Return early for operands of different signs. 
    if (i < 0 != f < 0) return i < 0; 

    bool rev = i >= 0; 
    if (rev) { 
     f = - f; // Make both operands non-positive. 
     i = - i; // (Negativity avoids integer overflow here.) 
    } 

    if (f < /* (F) */ std::numeric_limits<I>::min()) { 
     // |i| < |f| because f is outside the range of I. 
     return rev; 
    } 
    if (f * std::numeric_limits<F>::epsilon() <= -1) { 
     // f must be an integer (in I) because of limited precision in F. 
     I fi = f; 
     return rev? fi < i : i < fi; 
    } 
    // |f| has better than integer precision. 
    // If (F) |i| loses precision, it will still be greater than |f|. 
    return rev? f < i : i < f; 
} 

Demo: http://coliru.stacked-crooked.com/a/b5c4bea14bc09ee7

+0

… ehh, mã này chỉ hoạt động đối với * số nguyên * đã ký. Bạn có thể thêm một tình trạng quá tải cho các số nguyên không dấu bằng cách loại bỏ tất cả các dấu hiệu kinh doanh. – Potatoswatter

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