C++ 将双精度值四舍五入到(稍微)较低精度的好方法是什么?

C++ 将双精度值四舍五入到(稍微)较低精度的好方法是什么?,c++,rounding,floating-point-precision,C++,Rounding,Floating Point Precision,我的问题是,我必须使用第三方函数/算法,该算法将双精度值数组作为输入,但显然对输入数据的微小变化非常敏感。然而,对于我的应用程序,我必须为(几乎)相同的输入获得相同的结果!特别是我有两个测试输入数组,它们在小数点后的第5位是相同的,但我仍然得到不同的结果。因此,导致“问题”的原因必须位于小数点后的第5位 现在我的想法是将输入四舍五入到稍低的精度,以便从非常相似但并非100%相同的输入中获得相同的结果。因此,我正在寻找一种好的/有效的方法,将双精度值四舍五入到稍低的精度。到目前为止,我使用此代码将

我的问题是,我必须使用第三方函数/算法,该算法将双精度值数组作为输入,但显然对输入数据的微小变化非常敏感。然而,对于我的应用程序,我必须为(几乎)相同的输入获得相同的结果!特别是我有两个测试输入数组,它们在小数点后的第5位是相同的,但我仍然得到不同的结果。因此,导致“问题”的原因必须位于小数点后的第5位

现在我的想法是将输入四舍五入到稍低的精度,以便从非常相似但并非100%相同的输入中获得相同的结果。因此,我正在寻找一种好的/有效的方法,将双精度值四舍五入到稍低的精度。到目前为止,我使用此代码将小数点后的第9位四舍五入:

double x = original_input();
x = double(qRound(x * 1000000000.0)) / 1000000000.0;
这里qRound()是Qt中的正常双整数舍入函数。这段代码有效,它确实解决了我在两个“有问题”测试集上的问题。但是:有没有更有效的方法

还有什么困扰着我:对于-100.0到100.0范围内的输入数据,舍入到小数点后的第9位可能是合理的(就像我当前的输入数据一样)。但是,例如,对于-0.001到0.001范围内的输入数据,它可能太多(即,太多的精度损失)。不幸的是,我不知道在其他情况下我的输入值在什么范围内

毕竟,我认为我需要的是一个类似函数的东西,它可以执行以下操作:通过适当的舍入,将给定的double-精度值X截止到小数点后最多L-N个位置,其中L是double-精度可以存储(表示)的小数点后的位置数对于给定的值;N是固定的,就像3。这意味着对于“小”值,小数点后的位置比“大”值后的位置多。换句话说,我希望将64位浮点值四舍五入到(稍微)更小的精度,如60位或56位,然后将其存储回64位双精度值

这对你有意义吗?如果是这样,你能建议一种在C++??

中有效地执行这一操作的方法吗? 提前谢谢

如果您看一下,您可以看到如何将它与一点按位魔术结合起来,以实现快速(二进制)舍入到任意精度。您具有以下位布局:

SEEEEEEEEEEEFFFFFFFFFFF.......FFFFFFFFFF
其中,
S
是符号位,
E
S是指数位,
F
S是分数位。您可以制作如下的位掩码:

11111111111111111111111.......1111000000
和按位and(
&
)将两者结合在一起。结果是原始输入的四舍五入版本:

SEEEEEEEEEEEFFFFFFFFFFF.......FFFF000000
您可以通过更改尾随零的数量来控制截断的数据量。更多的零=更多的舍入;更少=更少。您还可以得到您想要的另一个效果:小输入值受影响的比例小于大输入值,因为每个位对应的“位置”由指数决定

希望有帮助


警告:从技术上讲,这是截断,而不是真正的舍入(所有值都将变得更接近零,无论它们与其他可能的结果有多接近),但希望它在您的情况下同样有用。

感谢您迄今为止的输入

然而,在进一步搜索之后,我发现了frexp()和ldexp()函数!通过这些函数,我可以访问给定双精度值的“尾数”和“指数”,还可以将尾数+指数转换回双精度。现在我只需要把尾数四舍五入

double value = original_input();
static const double FACTOR = 32.0;
int exponent;
double temp = double(round(frexp(value, &exponent) * FACTOR));
value = ldexp(temp / FACTOR, exponent);
我不知道这是否有效,但它给出了合理的结果:

0.000010000000000   0.000009765625000
0.000010100000000   0.000010375976563
0.000010200000000   0.000010375976563
0.000010300000000   0.000010375976563
0.000010400000000   0.000010375976563
0.000010500000000   0.000010375976563
0.000010600000000   0.000010375976563
0.000010700000000   0.000010986328125
0.000010800000000   0.000010986328125
0.000010900000000   0.000010986328125
0.000011000000000   0.000010986328125
0.000011100000000   0.000010986328125
0.000011200000000   0.000010986328125
0.000011300000000   0.000011596679688
0.000011400000000   0.000011596679688
0.000011500000000   0.000011596679688
0.000011600000000   0.000011596679688
0.000011700000000   0.000011596679688
0.000011800000000   0.000011596679688
0.000011900000000   0.000011596679688
0.000012000000000   0.000012207031250
0.000012100000000   0.000012207031250
0.000012200000000   0.000012207031250
0.000012300000000   0.000012207031250
0.000012400000000   0.000012207031250
0.000012500000000   0.000012207031250
0.000012600000000   0.000012817382813
0.000012700000000   0.000012817382813
0.000012800000000   0.000012817382813
0.000012900000000   0.000012817382813
0.000013000000000   0.000012817382813
0.000013100000000   0.000012817382813
0.000013200000000   0.000013427734375
0.000013300000000   0.000013427734375
0.000013400000000   0.000013427734375
0.000013500000000   0.000013427734375
0.000013600000000   0.000013427734375
0.000013700000000   0.000013427734375
0.000013800000000   0.000014038085938
0.000013900000000   0.000014038085938
0.000014000000000   0.000014038085938
0.000014100000000   0.000014038085938
0.000014200000000   0.000014038085938
0.000014300000000   0.000014038085938
0.000014400000000   0.000014648437500
0.000014500000000   0.000014648437500
0.000014600000000   0.000014648437500
0.000014700000000   0.000014648437500
0.000014800000000   0.000014648437500
0.000014900000000   0.000014648437500
0.000015000000000   0.000015258789063
0.000015100000000   0.000015258789063
0.000015200000000   0.000015258789063
0.000015300000000   0.000015869140625
0.000015400000000   0.000015869140625
0.000015500000000   0.000015869140625
0.000015600000000   0.000015869140625
0.000015700000000   0.000015869140625
0.000015800000000   0.000015869140625
0.000015900000000   0.000015869140625
0.000016000000000   0.000015869140625
0.000016100000000   0.000015869140625
0.000016200000000   0.000015869140625
0.000016300000000   0.000015869140625
0.000016400000000   0.000015869140625
0.000016500000000   0.000017089843750
0.000016600000000   0.000017089843750
0.000016700000000   0.000017089843750
0.000016800000000   0.000017089843750
0.000016900000000   0.000017089843750
0.000017000000000   0.000017089843750
0.000017100000000   0.000017089843750
0.000017200000000   0.000017089843750
0.000017300000000   0.000017089843750
0.000017400000000   0.000017089843750
0.000017500000000   0.000017089843750
0.000017600000000   0.000017089843750
0.000017700000000   0.000017089843750
0.000017800000000   0.000018310546875
0.000017900000000   0.000018310546875
0.000018000000000   0.000018310546875
0.000018100000000   0.000018310546875
0.000018200000000   0.000018310546875
0.000018300000000   0.000018310546875
0.000018400000000   0.000018310546875
0.000018500000000   0.000018310546875
0.000018600000000   0.000018310546875
0.000018700000000   0.000018310546875
0.000018800000000   0.000018310546875
0.000018900000000   0.000018310546875
0.000019000000000   0.000019531250000
0.000019100000000   0.000019531250000
0.000019200000000   0.000019531250000
0.000019300000000   0.000019531250000
0.000019400000000   0.000019531250000
0.000019500000000   0.000019531250000
0.000019600000000   0.000019531250000
0.000019700000000   0.000019531250000
0.000019800000000   0.000019531250000
0.000019900000000   0.000019531250000
0.000020000000000   0.000019531250000
0.000020100000000   0.000019531250000
似乎很喜欢我一直在寻找的东西:

现在我只需要为我的函数找到好的因子值


有什么意见或建议吗?

从问题中看不出业务场景;我仍然觉得你在试图看到数值在可接受的范围内。您可以检查第二个值是否在某个百分比范围内(例如+/-0.001%),而不是==


如果范围百分比无法固定(平均值根据精度长度而变化;例如,对于小数点后2位,0.001%可以,但是对于小数点后4位,需要0.000001%),则,你可以在1/尾数前到达它。

我知道这个问题已经很老了,但我也在寻找一种方法,将
双倍
值舍入到较低的精度。也许,这个答案有助于其他人

double value = original_input();
static const double FACTOR = 32.0;
int exponent;
double temp = double(round(frexp(value, &exponent) * FACTOR));
value = ldexp(temp / FACTOR, exponent);
想象一个二进制表示的浮点数。例如
1101.101
。位
1101
表示数字的整数部分,并从左到右用
2^3
2^2
2^1
2^0
加权。小数部分上的位
101
2^-1
2^-2
2^-3
加权,等于
1/2
1/4
1/8


那么,当你把小数点后的两位数字切掉时,会产生什么样的小数错误呢?由于位已设置,因此在本例中为
0.125
。如果不设置该位,则错误为
0
。所以,错误是
你想把它四舍五入10进制,还是2进制也可以?嗨。我认为2进制也可以,只要它能适应输入。这个想法根本上是有缺陷的。所有数字都是“几乎相同”的,即1.00与1.01几乎相同,1.01与1.02几乎相同,等等。因此,如果
f(1.00)=f(1.01)
f(1.01)==f(1.02)
那么
f(1.00)==f(1.02)
以及
f(1.00)==f(1E7)
MSalters,我理解你的意思。当然,实际上我要做的是将输入值“量化”成若干