2009-06-18 32 views
6

Tôi đang gặp phải sự cố và không thể giải quyết vấn đề. Cần sự giúp đỡ từ rất kinh nghiệm. Dưới đây là mã mẫu: -C++: Làm thế nào để chuyển đổi từ phao sang chuỗi mà không làm tròn, cắt xén hoặc đệm?

float f=0.01f; 
printf("%f",f); 

nếu chúng tôi kiểm tra giá trị biến trong khi gỡ lỗi f chứa '0.0099999998' giá trị và đầu ra của printf là 0.010000.

a. Có cách nào mà chúng ta có thể buộc trình biên dịch gán các giá trị giống nhau cho biến kiểu float không?

b. Tôi muốn chuyển đổi float thành chuỗi ký tự/chuỗi ký tự. Làm thế nào là nó có thể chỉ có và chỉ chính xác cùng một giá trị được chuyển đổi thành chuỗi ký tự/chuỗi ký tự. Tôi muốn đảm bảo rằng không có số không được đệm, không có giá trị không mong muốn nào được đệm, không có thay đổi về chữ số như trong ví dụ trên.

Trả lời

2

Hãy xem điều này C++ reference. Cụ thể là phần về độ chính xác:

float blah = 0.01; 
printf ("%.2f\n", blah); 
+0

Tôi nghĩ anh ấy đang đối mặt với vấn đề với phao không tăng gấp đôi – Aamir

+0

hehe ... thật tuyệt. Tôi tìm downvote ban đầu có thể là do câu trả lời đầu tiên, rất ngắn gọn của tôi (sans sourcecode), và đủ công bằng quá;). – RedBlueThing

+0

Cũng có thể là vì tôi đã phớt lờ toàn bộ vấn đề đại diện của điểm phao và trả lời câu hỏi ở cấp độ khá hời hợt. – RedBlueThing

2

Có vô số số thực.

Chỉ có một số lượng hữu hạn các giá trị mà các loại dữ liệu float, doublelong double có thể thực hiện.

Tức là, sẽ có vô số nhiều số thực không thể đại diện chính xác bằng cách sử dụng các loại dữ liệu đó.

6

Không thể biểu diễn chính xác số thập phân cơ sở 10 sử dụng giá trị cơ số 2, ngoại trừ một số lượng rất nhỏ các giá trị (chẳng hạn như 0,25). Để có được những gì bạn cần, bạn phải chuyển từ kiểu tích hợp float/double thành một số loại gói số thập phân.

1

Lý do trình gỡ rối cung cấp cho bạn một giá trị khác cũng được giải thích rõ ràng trong bài đăng của Mark Ransom.

Về việc in nổi mà không làm tròn, cắt ngắn và có độ chính xác cao hơn, bạn thiếu thông số chính xác - độ chính xác mặc định cho printf thường là 6 chữ số thập phân.

thử cách sau để có được một độ chính xác 10 chữ số:

float amount = 0.0099999998; 
printf("%.10f", amount); 

Là một lưu ý phụ, C++ cách hơn (so với C-style) để làm điều là với cout:

float amount = 0.0099999998; 
cout.precision(10); 
cout << amount << endl; 
0

Bạn cần tham khảo các tiêu chuẩn nền tảng để xác định cách xác định đúng định dạng chính xác, bạn cần hiển thị nó dưới dạng * b^C, trong đó 'a' là thành phần không thể thiếu giữ ký hiệu 'b' là thực hiện được xác định (Có thể được cố định bởi một tiêu chuẩn) và 'C' là số mũ được sử dụng cho số đó.

Ngoài ra, bạn chỉ có thể hiển thị nó trong hex, nó có nghĩa là không có gì cho một con người, mặc dù, và nó vẫn sẽ là nhị phân cho tất cả các mục đích thực tế. (! Và cũng giống như di động)

0

Để trả lời câu hỏi thứ hai của bạn:

nó IS có thể chính xác và rõ ràng đại diện nổi như dây đàn. Tuy nhiên, điều này đòi hỏi một đại diện hệ thập lục phân. Ví dụ: 1/16 = 0,1 và 10/16 là 0,A.

Với phao thập lục phân, bạn có thể xác định biểu diễn chính tắc.Cá nhân tôi sử dụng một số cố định các chữ số đại diện cho số bit cơ bản, nhưng bạn cũng có thể quyết định loại bỏ các số 0. Không có sự nhầm lẫn nào có thể xảy ra khi các chữ số cuối không bằng 0.

Kể từ khi đại diện là chính xác, sự chuyển đổi có thể đảo ngược: f==hexstring2float(float2hexstring(f))

3

Bạn có thể sử dụng boost::lexical_cast theo cách này:

float blah = 0.01; 
string w = boost::lexical_cast<string>(blah); 

Biến w sẽ chứa giá trị văn bản ,00999999978. Nhưng tôi không thể nhìn thấy khi bạn thực sự cần nó.

Được ưu tiên sử dụng boost::format để định dạng chính xác thả nổi dưới dạng chuỗi. Các mã sau đây cho thấy làm thế nào để làm điều đó:

float blah = 0.01; 
string w = str(boost::format("%d") % blah); // w contains exactly "0.01" now 
0

Đối với (b), bạn có thể làm

std::ostringstream os; 
os << f; 
std::string s = os.str(); 
1

Tương tự, bạn có thể sử dụng stdlib.h, trong đó là những sprintf, ecvtfcvt chức năng (hoặc ít nhất, nên có!).

int sprintf(char* dst,const char* fmt,...); 

char *ecvt(double value, int ndig, int *dec, int *sign); 

char *fcvt(double value, int ndig, int *dec, int *sign); 

sprintf trả về số ký tự nó đã viết thư cho chuỗi, ví dụ

float f=12.00; 
char buffer[32]; 
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1 

ecvtfcvt ký tự trở lại char tĩnh * địa điểm chứa null chấm dứt đại diện thập phân của các số, không có dấu thập phân, số quan trọng nhất đầu tiên, độ lệch của dấu thập phân được lưu trữ trong tháng mười hai, dấu trong "dấu" (1 = -, 0 = +) ndig là số chữ số có nghĩa để lưu trữ e. Nếu tháng < 0 thì bạn phải pad bằng -dec zeros pror đến dấu thập phân. Tôi eyou không chắc chắn, và bạn không làm việc trên một hệ thống Windows7 (mà sẽ không chạy các chương trình DOS3 cũ đôi khi) tìm TurboC phiên bản 2 cho Dos 3, vẫn còn một hoặc hai tải có sẵn, đó là một chương trình tương đối nhỏ từ Borland là một trình soạn thảo/biên dịch Dos C/C++ nhỏ và thậm chí đi kèm với TASM, mã máy tính 16 bit 386/486, nó được bao gồm trong các tệp trợ giúp cũng như nhiều thông tin hữu ích khác.

Tất cả ba thủ tục đều nằm trong "stdlib.h", hoặc phải là, mặc dù tôi thấy rằng trên VisualStudio2010 chúng là gì nhưng tiêu chuẩn, thường bị quá tải với hàm xử lý ký tự có kích cỡ WORD và yêu cầu bạn sử dụng các hàm cụ thể của riêng nó thay vào đó ... "rất nhiều cho thư viện tiêu chuẩn", tôi lẩm bẩm với bản thân mình gần như mọi lần, "Có thể họ ra ngoài để có được một từ điển tốt hơn!"

1

Sự thật khi sử dụng bộ xử lý điểm động hoặc bộ xử lý hoặc phần của chip (phần lớn được tích hợp vào CPU) sẽ không bao giờ dẫn đến kết quả toán học chính xác, nhưng chúng mang lại độ chính xác khá thô. kết quả chính xác, bạn có thể xem xét định nghĩa một lớp "DecimalString", sử dụng nybbles làm ký tự thập phân và ký hiệu ... và cố gắng bắt chước toán học cơ sở 10 bằng chuỗi ... trong trường hợp đó, tùy thuộc vào thời gian bạn muốn tạo chuỗi , bạn thậm chí có thể bỏ đi phần exponent một chuỗi 256 có thể đại diện cho 1x10^-254 tối đa 1^+ 255 theo số thập phân thẳng sử dụng ASCII thực, ngắn hơn nếu bạn muốn có dấu, nhưng điều này có thể chậm hơn đáng kể. Bạn có thể tăng tốc độ này bằng cách đảo ngược thứ tự chữ số, do đó từ trái sang phải họ đọc đơn vị, hàng chục, hàng trăm, hàng nghìn ....

Ví dụ đơn giản ví dụ: "0021" trở thành 1200 Điều này sẽ cần "dịch chuyển" sang trái và sang phải để làm cho các điểm thập phân xếp hàng trước các thường trình, đặt cược tốt nhất là bắt đầu với các hàm ADD và SUB, sau đó bạn sẽ xây dựng chúng trong MUL và chức năng DIV. Nếu bạn đang ở trên một cỗ máy lớn, bạn có thể làm cho chúng về mặt lý thuyết miễn là trái tim bạn mong muốn!

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