Tiêu chuẩn C ++ 03 dựa trên tiêu chuẩn C90 cho tiêu chuẩn gọi Thư viện C tiêu chuẩn được nêu trong dự thảo tiêu chuẩn C ++ 03 ( tiêu chuẩn dự thảo có sẵn công khai gần nhất với C ++ 03 là N1804 ) phần 1.2
Tham khảo quy định :
Thư viện được mô tả trong khoản 7 của ISO / IEC 9899: 1990 và khoản 7 của ISO / IEC 9899 / Amd.1: 1995 sau đây được gọi là Thư viện C tiêu chuẩn. 1)
Nếu chúng ta đi đến tài liệu C cho vòng, lround, llround trên cppreference, chúng ta có thể thấy rằng các hàm tròn và các hàm liên quan là một phần của C99 và do đó sẽ không có sẵn trong C ++ 03 hoặc trước đó.
Trong C ++ 11, điều này thay đổi do C ++ 11 dựa trên tiêu chuẩn dự thảo C99 cho thư viện chuẩn C và do đó cung cấp std :: round và cho các kiểu trả về tích phân std :: lround, std :: llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Một tùy chọn khác từ C99 sẽ là std :: trunc :
Tính số nguyên gần nhất không lớn hơn độ lớn.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
Nếu bạn cần hỗ trợ các ứng dụng không phải C ++ 11, cách tốt nhất của bạn là sử dụng boost round, iround, lround, llround hoặc boost trunc .
Xoay vòng phiên bản của riêng bạn là khó
Việc tự lăn của bạn có lẽ không đáng để nỗ lực hơn so với vẻ ngoài của nó: làm tròn số phao đến số nguyên gần nhất, phần 1 , Làm tròn số nổi đến số nguyên gần nhất, phần 2 và Làm tròn số nổi với số nguyên gần nhất, phần 3 giải thích:
Ví dụ, một cuộn phổ biến mà việc triển khai của bạn sử dụng std::floor
và thêm 0.5
không hoạt động đối với tất cả các đầu vào:
double myround(double d)
{
return std::floor(d + 0.5);
}
Một đầu vào này sẽ thất bại cho 0.49999999999999994
, ( xem nó trực tiếp ).
Một cách thực hiện phổ biến khác liên quan đến việc chuyển một loại dấu phẩy động thành một kiểu tích phân, có thể gọi hành vi không xác định trong trường hợp phần không thể được biểu diễn trong loại đích. Chúng ta có thể thấy điều này từ bản dự thảo C ++ 4.9
chuyển đổi tích phân nổi có nội dung ( nhấn mạnh của tôi ):
Giá trị của loại dấu phẩy động có thể được chuyển đổi thành giá trị của loại số nguyên. Việc cắt giảm chuyển đổi; đó là, phần phân đoạn bị loại bỏ. Hành vi không được xác định nếu giá trị bị cắt không thể được biểu diễn trong loại đích. [...]
Ví dụ:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Đưa ra std::numeric_limits<unsigned int>::max()
là 4294967295
cuộc gọi sau:
myround( 4294967296.5f )
sẽ gây ra tràn, ( xem nó trực tiếp ).
Chúng ta có thể thấy điều này thực sự khó khăn như thế nào bằng cách xem câu trả lời này cho cách ngắn gọn để thực hiện vòng () trong C? trong đó tham chiếu phiên bản newlibs của vòng nổi chính xác duy nhất. Đó là một chức năng rất dài cho một cái gì đó có vẻ đơn giản. Dường như bất kỳ ai mà không có kiến thức sâu sắc về việc triển khai dấu phẩy động đều có thể thực hiện chính xác chức năng này:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
Mặt khác, nếu không có giải pháp nào khác có thể sử dụng thì newlib có thể có khả năng là một lựa chọn vì đây là một triển khai được thử nghiệm tốt.
std::cout << std::fixed << std::setprecision(0) << -0.9
.