10

在 Java 中处理浮点值时,调用该toString()方法会给出一个打印值,该值具有正确数量的浮点有效数字。但是,在 C++ 中,通过打印浮点数stringstream将在 5 位或更少位后舍入该值。有没有办法将 C++ 中的浮点数“漂亮地打印”到(假设的)正确数量的有效数字?


编辑:我想我被误解了。我希望输出具有动态长度,而不是固定精度。我熟悉setprecision。如果您查看 Double 的 java 源代码,它会以某种方式计算有效位数,我真的很想了解它是如何工作的和/或在 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 );
}

在这个函数之后,它会调用dtoa( binExp, fractBits, nSignificantBits );处理一堆案例 - 这是来自 OpenJDK6


为了更清楚,一个例子: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);

输出:

1.2593
0.004963
1.55558742563

C++:

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

输出:

1.2593
0.004963
1.55559
4

4 回答 4

6

我认为您正在谈论如何打印允许您读取完全相同的浮点数的最小浮点数。这篇论文很好地介绍了这个棘手的问题。

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

dtoa 函数看起来像 David Gay 的作品,您可以在此处找到源代码http://www.netlib.org/fp/dtoa.c(虽然这是 C 而不是 Java)。

盖伊还写了一篇关于他的方法的论文。我没有链接,但在上面的论文中引用了它,所以你可以用谷歌搜索它。

于 2012-07-27T22:02:42.863 回答
1

有没有办法将 C++ 中的浮点数“漂亮地打印”到(假设的)正确数量的有效数字?

是的,你可以用 C++20 来做std::format,例如:

double test1 = 1.2593;
double test2 = 0.004963;
double test3 = 1.55558742563;
std::cout << std::format("{}", test1) << "\n";
std::cout << std::format("{}", test2) << "\n";
std::cout << std::format("{}", test3) << "\n";

印刷

1.2593
0.004963
1.55558742563

默认格式将为您提供最短的十进制表示形式,并提供 Java 中的往返保证。

由于这是一项新功能,某些标准库可能还不支持,因此您可以使用基于的 {fmt} 库std::format。{fmt} 还提供了print使这更容易和更高效的功能(godbolt):

fmt::print("{}", 1.2593);

免责声明:我是 {fmt} 和 C++20 的作者std::format

于 2020-12-20T16:39:29.410 回答
-1

您可以使用 ios_base::precision 技术,您可以在其中指定所需的位数

例如

#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;

上面的代码输出
3.1416
3.14159
3.1415900000

于 2012-07-27T20:35:46.560 回答
-1

有一个名为 numeric_limits 的实用程序:

#include <limits>

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

请注意,IEEE 数字不完全由十进制数字表示。这些是二进制量。更准确的数字是二进制位数:

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

要漂亮地打印所有有效数字,请使用 setprecision :

out.setprecision(std::numeric_limits<double>::digits10);
于 2012-07-27T22:30:10.253 回答