2008-11-20 44 views

Trả lời

5

Trước tiên, điều quan trọng cần biết là các số dấu phẩy động là gần đúng. Xem liên kết được cung cấp bởi @Greg Hewgill để hiểu tại sao vấn đề này không hoàn toàn có thể giải quyết được.

Nhưng dưới đây là một vài giải pháp cho vấn đề mà có lẽ sẽ đáp ứng nhu cầu của bạn:

lẽ là phương pháp tốt hơn nhưng kém hiệu quả:

char sz[64]; 
double lf = 0.600000002; 
sprintf(sz, "%.4lf\n", lf); //sz contains 0.6000 

double lf2 = atof(sz); 

//lf == 0.600000002; 
//lf2 == 0.6000 

printf("%.4lf", lf2); //print 0.6000 

Cách hiệu quả hơn, nhưng có lẽ ít chính xác:

double lf = 0.600000002; 
int iSigned = lf > 0? 1: -1; 
unsigned int uiTemp = (lf*pow(10, 4)) * iSigned; //Note I'm using unsigned int so that I can increase the precision of the truncate 
lf = (((double)uiTemp)/pow(10,4) * iSigned); 
6

Thực tế điều đó là không thể. Nó không phải là một giới hạn C++, mà chỉ là cách điểm trôi nổi hoạt động. Đối với nhiều giá trị không có biểu diễn chính xác, do đó bạn không thể chỉ cắt ngắn thành một số chữ số.

Bạn có thể cắt bớt khi in bằng các chuỗi định dạng printf.

Nếu bạn thực sự chỉ cần lưu trữ số lượng chữ số giới hạn, tôi khuyên bạn nên sử dụng loại dữ liệu có độ chính xác cố định thay thế.

12

Một tài liệu tham khảo tốt cho lý do tại sao điều này xảy ra có thể được tìm thấy trong What Every Computer Scientist Should Know About Floating Point Arithmetic bởi David Goldberg.

+0

Cảm ơn bạn đã đăng liên kết Greg, tôi đã nghĩ về tài liệu chính xác đó khi tôi viết câu trả lời nhưng không thể cho cuộc sống của tôi nhớ tiêu đề. –

3

tôi nghĩ câu hỏi cần được hỏi ở đây là: Tại sao bạn cần cắt bớt?

Nếu nó để so sánh giữa các giá trị, có lẽ bạn nên cân nhắc sử dụng phép thử epsilon. (với một giá trị khoan dung thêm, trong trường hợp của bạn, vì nó có vẻ là lớn hơn nhiều so với epsilon được chấp nhận chung).

Nếu bạn chỉ muốn in ra dưới dạng 0,6000, hãy sử dụng các phương pháp mà người khác đã đề xuất.

1
roundf(myfloat * powf(10, numDigits))/powf(10, numDigits); 

Ví dụ: trong trường hợp bạn cắt ngắn ba chữ số (numDigits). Bạn muốn sử dụng:

roundf(0.6000002 * 1000)/1000 
// And thus: 
roundf(600.0002)/1000 
600/1000 
0.6 

(Bạn có thể muốn lưu trữ các kết quả của powf nơi nào đó, kể từ khi bạn đang sử dụng nó hai lần.)

Do cách nổi thường được lưu trữ trên máy tính, có muốn có lẽ là không chính xác. Đó là những gì bạn nhận được để sử dụng phao, mặc dù.

1

Sử dụng này:

floor(0.6000002*10000)/10000 
0

Đây là một chức năng sử dụng những lời khuyên trong câu trả lời khác và một ví dụ về việc sử dụng nó:

#include <iostream> 
#include <cmath> 

static void Truncate(double& d, unsigned int numberOfDecimalsToKeep); 

int main(int, char*[]) 
{ 

    double a = 1.23456789; 
    unsigned int numDigits = 3; 

    std::cout << a << std::endl; 

    Truncate(a,3); 

    std::cout << a << std::endl; 

    return 0; 
} 

void Truncate(double& d, unsigned int numberOfDecimalsToKeep) 
{ 
    d = roundf(d * powf(10, numberOfDecimalsToKeep))/powf(10, numberOfDecimalsToKeep); 
} 
0

Tương tự như câu trả lời khác, NHƯNG bạn phải quên tròn , sàn và trunc là khác nhau theo định nghĩa.Xem định nghĩa và ví dụ đầu ra trong các cách sau:

http://www.cplusplus.com/reference/cmath/trunc/

Trong trường hợp này chúng ta cần phải trucate với một độ chính xác của 4 thập phân và thoát khỏi thập phân không đáng kể:

trunc(valueToTrunc*10000)/10000 

hoặc

value = (double)((int)(valueToTrunc*10000))/(double)10000 
0

Đối với C++ 11 bạn có thể sử dụng std::round được xác định trong tiêu đề <cmath>:

auto trunc_value = std::round(value_to_trunc * 10000)/10000; 
Các vấn đề liên quan