在Java中处理浮点值时,调用toString()
方法会给出一个具有正确浮点有效位数的打印值。但是,在C++中,通过stringstream
打印浮点值将使值在5位或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
我想您谈论的是如何打印最小数量的浮点数字,使您能够读取完全相同的浮点数字。这篇论文很好地介绍了这个棘手的问题。
http://grouper.ieee.org/groups/754/email/pdfq3pavhBfih.pdf
dtoa函数看起来像David Gay的作品,你可以在这里找到来源http://www.netlib.org/fp/dtoa.c(尽管这是C而非Java)。
盖伊还写了一篇关于他的方法的论文。我没有链接,但上面的文章中提到了它,所以你可能可以在谷歌上搜索它。
有没有办法";漂亮的印刷品;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中那样提供往返保证。
由于这是一个新功能,可能还没有得到一些标准库的支持,您可以使用std::format
所基于的{fmt}库。{fmt}还提供了print
函数,使其更容易、更高效(godbolt):
fmt::print("{}", 1.2593);
免责声明:我是{fmt}和C++20 std::format
的作者。
您可以使用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
有一个名为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);