2012-07-27 19 views
7

Khi xử lý các giá trị dấu phẩy động trong Java, việc gọi phương thức toString() cho một giá trị được in có số lượng dấu phẩy động chính xác. Tuy nhiên, trong C++, việc in phao qua chuỗi sẽ làm tròn giá trị sau 5 hoặc ít hơn chữ số. Có cách nào để "in đẹp" một phao trong C++ đến (giả định) số chính xác của các số liệu quan trọng?Làm thế nào để tính toán số chữ số thập phân có ý nghĩa của một C++ gấp đôi?


EDIT: Tôi nghĩ rằng tôi đang bị hiểu lầm. Tôi muốn đầu ra có độ dài động, không phải độ chính xác cố định. Tôi quen thuộc với việc quyết định. Nếu bạn nhìn vào nguồn java cho Double, nó tính toán số lượng chữ số có nghĩa bằng cách nào đó, và tôi thực sự muốn hiểu nó hoạt động như thế nào và/hoặc khả thi như thế nào để tái tạo điều này một cách dễ dàng trong C++.

/* 
* FIRST IMPORTANT CONSTRUCTOR: DOUBLE 
*/ 
public FloatingDecimal(double d) 
{ 
    long dBits = Double.doubleToLongBits(d); 
    long fractBits; 
    int  binExp; 
    int  nSignificantBits; 

    // discover and delete sign 
    if ((dBits&signMask) != 0){ 
     isNegative = true; 
     dBits ^= signMask; 
    } else { 
     isNegative = false; 
    } 
    // Begin to unpack 
    // Discover obvious special cases of NaN and Infinity. 
    binExp = (int)((dBits&expMask) >> expShift); 
    fractBits = dBits&fractMask; 
    if (binExp == (int)(expMask>>expShift)) { 
     isExceptional = true; 
     if (fractBits == 0L){ 
      digits = infinity; 
     } else { 
      digits = notANumber; 
      isNegative = false; // NaN has no sign! 
     } 
     nDigits = digits.length; 
     return; 
    } 
    isExceptional = false; 
    // Finish unpacking 
    // Normalize denormalized numbers. 
    // Insert assumed high-order bit for normalized numbers. 
    // Subtract exponent bias. 
    if (binExp == 0){ 
     if (fractBits == 0L){ 
      // not a denorm, just a 0! 
      decExponent = 0; 
      digits = zero; 
      nDigits = 1; 
      return; 
     } 
     while ((fractBits&fractHOB) == 0L){ 
      fractBits <<= 1; 
      binExp -= 1; 
     } 
     nSignificantBits = expShift + binExp +1; // recall binExp is - shift count. 
     binExp += 1; 
    } else { 
     fractBits |= fractHOB; 
     nSignificantBits = expShift+1; 
    } 
    binExp -= expBias; 
    // call the routine that actually does all the hard work. 
    dtoa(binExp, fractBits, nSignificantBits); 
} 

Sau khi chức năng này, nó gọi dtoa(binExp, fractBits, nSignificantBits); mà xử lý một loạt các trường hợp - đây là từ OpenJDK6


Để rõ ràng hơn, ví dụ: Java:

double test1 = 1.2593; 
double test2 = 0.004963; 
double test3 = 1.55558742563; 

System.out.println(test1); 
System.out.println(test2); 
System.out.println(test3); 

Output :

1.2593 
0.004963 
1.55558742563 

C++:

std::cout << test1 << "\n"; 
std::cout << test2 << "\n"; 
std::cout << test3 << "\n"; 

Output:

1.2593 
0.004963 
1.55559 
+3

Lệnh 'phương pháp toString' không cung cấp cho các "con số chính xác" của số liệu quan trọng; nó không có cách nào biết được số liệu nào là quan trọng. Số dấu phẩy động IEEE không đại diện cho thông tin đó. –

+0

Để tham khảo, đây là một cách tiếp cận Java phổ biến cho [* Tùy chỉnh Định dạng *] (http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html). – trashgod

+0

Java thực hiện một loạt các phép tính trên giá trị kép khi in - Tôi chỉ không hiểu biết đủ để hiểu nó đang làm gì. Xem chỉnh sửa – dave

Trả lời

5

Tôi nghĩ rằng bạn đang nói về làm thế nào để in số lượng tối thiểu là nổi chữ số điểm cho phép bạn đọc cùng một số dấu chấm động chính xác trở lại. Bài viết này là một giới thiệu tốt cho vấn đề phức tạp này.

http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf

Chức năng dtoa trông giống như công việc David Gay, bạn có thể tìm ra nguồn đây http://www.netlib.org/fp/dtoa.c (mặc dù điều này là C không Java).

Đồng tính cũng đã viết một bài báo về phương pháp của anh ấy. Tôi không có một liên kết nhưng nó được tham chiếu trong bài báo trên để bạn có thể google nó.

+0

Cảm ơn! Tôi cảm thấy như bạn là người duy nhất để có được những gì tôi đã nói về. – dave

0

Bạn có thể sử dụng kỹ thuật ios_base :: chính xác nơi bạn có thể xác định số chữ số bạn muốn

Ví dụ

#include <iostream> 
using namespace std; 

int main() { 
double f = 3.14159; 
cout.unsetf(ios::floatfield);   // floatfield not set 
cout.precision(5); 
cout << f << endl; 
cout.precision(10); 
cout << f << endl; 
cout.setf(ios::fixed,ios::floatfield); // floatfield set to fixed 
cout << f << endl; 
return 0; 

Đoạn mã trên với đầu ra
3,1416
3,14159
3,1415900000

+0

Điều tôi đang cố gắng tránh là các số 0 trong ví dụ của bạn. Tôi không muốn một giá trị cố định cho đầu ra của tôi. – dave

0

Có một tiện ích gọi là numeric_limits:

#include <limits> 

    ... 
    int num10 = std::numeric_limits<double>::digits10; 
    int max_num10 = std::numeric_limits<double>::max_digits10; 

Lưu ý rằng số IEEE không đại diện cho chữ số chính xác bydecimal. Đây là số lượng nhị phân.Một số chính xác hơn là số lượng các bit nhị phân:

int bits = std::numeric_limits<double>::digits; 

Để khá in tất cả các chữ số có nghĩa sử dụng setprecision với điều này:

out.setprecision(std::numeric_limits<double>::digits10); 
+0

đây không phải là những gì tôi đang tìm kiếm – dave

+0

OK, tôi hiểu rồi. Bạn muốn các con số theo dõi độ chính xác từ việc xây dựng thông qua các phép toán số? C + + tiêu chuẩn không có điều này. Có những nỗ lực để thêm các con số đa chính xác. Tôi nghĩ rằng yêu cầu của bạn là hợp lý cho những con số như vậy. Về cơ bản, các số dấu phẩy động cơ bản chỉ không có thông minh cho điều này và sẽ không bao giờ. – emsr

+0

Kiểm tra điều này: http://www.holoborodko.com/pavel/mpfr/. Tôi nghĩ rằng đây là những gì bạn muốn. Chúc may mắn. – emsr