Floating point 如何对非常小的负数进行四舍五入?

Floating point 如何对非常小的负数进行四舍五入?,floating-point,rounding,Floating Point,Rounding,有一个非常非常小的负数,例如我们从以前的计算中得到的-0.123e-35。 该数字可用于其他一些公式中。把这个数字四舍五入到小数点后十位到零“0”是正确的方法吗? 如果这个数字只用于加法运算也可以,但在乘法运算中会给出错误的结果。 怎样做才是正确的方法 UPD 为什么它需要我?在矩阵上实现了DCT方法。在测试矩阵8x8上,由“1”填充。我明白了: 8 -7.49778027488703e-13 7.64321008887262e-13 -7.90698562193149e-13 8.261826

有一个非常非常小的负数,例如我们从以前的计算中得到的
-0.123e-35
。 该数字可用于其他一些公式中。把这个数字四舍五入到小数点后十位到零“0”是正确的方法吗? 如果这个数字只用于加法运算也可以,但在乘法运算中会给出错误的结果。 怎样做才是正确的方法

UPD

为什么它需要我?在矩阵上实现了DCT方法。在测试矩阵8x8上,由“1”填充。我明白了:

8 -7.49778027488703e-13 7.64321008887262e-13 -7.90698562193149e-13 8.26182651759402e-13 -8.78937758371177e-13 9.51152198392764e-13 -1.04158952401295e-12
-7.51721016906324e-13 1.66533453693773e-16 -2.77555756156289e-17 2.77555756156289e-17 2.77555756156289e-17 2.77555756156289e-17 -2.77555756156289e-17 1.38777878078145e-17
7.65773344411544e-13 2.77555756156289e-17 -1.38777878078145e-16 -2.77555756156289e-17 0 0 0 -1.38777878078145e-17
-7.91522860733958e-13 0 5.55111512312578e-17 -5.55111512312578e-17 -2.77555756156289e-17 -2.77555756156289e-17 -1.38777878078145e-17 -1.38777878078145e-17
8.26025642513534e-13 8.32667268468867e-17 -2.77555756156289e-17 0 0 5.55111512312578e-17 -6.93889390390723e-17 -6.93889390390723e-18
-8.78466730633572e-13 8.32667268468867e-17 -2.77555756156289e-17 -4.16333634234434e-17 1.11022302462516e-16 4.16333634234434e-17 -1.38777878078145e-17 5.55111512312578e-17
9.50946123757562e-13 -1.66533453693773e-16 -9.71445146547012e-17 2.77555756156289e-17 -9.71445146547012e-17 -1.38777878078145e-17 1.38777878078145e-17 -1.73472347597681e-17
-1.04131475783268e-12 -8.32667268468867e-17 4.16333634234434e-17 -4.16333634234434e-17 -1.38777878078145e-17 5.55111512312578e-17 2.77555756156289e-17 -4.16333634234434e-17
我也做了同样的事情,但在Scilab中,它给了我以下信息:


正如你看到的,只有零。我想了解我是否可以将这些非常小的负数四舍五入为零?

要在JavaScript中四舍五入为10位小数(正如问题最初标记的那样),只需执行以下操作

var num = 0.0000000000000000000000000000000000123; // 1.23e-35
num = Math.round(num * 10000000000) / 10000000000;  // 0

var num = 0.000000000123; // 1.23e-10
num = Math.round(num * 10000000000) / 10000000000;  // 1e-10
请注意,尽管上面的操作会产生您想要的结果,但浮点值不是真正的十进制值,在某些情况下,尝试对它们进行“舍入”可能会产生意外的结果。但是,此解决方案将确保任何小于0.00000000005的数字都将四舍五入为0,我认为这正是您需要的

如果该值小于0.00000000005,则有条件地将该值设置为0可能是比将所有数字四舍五入更好的解决方案

if (num < 0.00000000005) num = 0;
如果(num<0.0000000000 5)num=0;
在python中,这是

round(n*(1e10))/(1e10)

将小数位数四舍五入到N位的最简单方法是使用“四舍五入”,请注意,这将返回一个
long
,因此您必须除以一个双精度值,或者可以得到整数除法

double rounded = Math.round(d * 1e10) / 1e10;
使用1eN表示法可以更清楚地显示您要舍入到的数字可能是多少。为了确保不会溢出,需要进行边界检查

public static double round10(double d) {
    final double factor = 1e10;
    return d > Long.MAX_VALUE / factor || d < -Long.MAX_VALUE / factor ?
            (long) (d < 0 ? d * factor - 0.5 : d * factor + 0.5) / factor : d;
}
公共静态双循环10(双d){
最终双因素=1e10;
返回d>Long.MAX_值/因子| d<-Long.MAX_值/因子?
(长)(d<0?d*因子-0.5:d*因子+0.5)/因子:d;
}

这里我使用了铸造而不是四舍五入,因为它几乎同样精确,但速度更快。

这里有很多答案建议你按照
(x*10^n)/10^n
的思路做一些事情。但是,通常情况下,不会四舍五入到
n
小数位

二进制浮点不能精确表示大多数有限十进制值,例如0.1实际上是0.10000001490116…*因此,如果您的目标是获得有限十进制展开的精确表示(用于后续计算),此方法将不起作用;它只会为您提供与您的目标最接近的可表示值。为了精确表示,您需要研究
BigDecimal
库/类(其详细信息因语言而异)

但是,如果您只想显示小数点后10位的值,那么您的语言可能会提供类似于C的
printf(“%.10f\n”,x)。为了便于显示,这实际上会四舍五入到小数点后10位



*有关这一重要问题的初学者介绍,请参阅。

您所显示的信息不能证明需要舍入到零。最有可能的情况是,您应该忽略某些结果很小的事实,继续正常工作

完美的测试数据不是DCT的良好演示。真实世界的数据很少导致DCT的值正好为零。此外,如果将DCT应用于实际数据并获得一个较小的值,则该值可能较小,因为这是数学上正确的结果,或者因为数学上正确的结果为零,但存在一些错误。这意味着您将无法确定是否应将DCT结果中的小值更正为零或单独保留。因此,试图将值更改为零实际上会使数据更糟

此外,较小的值不太可能影响工作。您的应用程序将使用DCT的结果修改或分析信号,然后继续执行逆变换或以其他方式使用结果。一般来说,数据中存在的微小错误不会显著影响这种进一步的使用。(麦克风或其他传感器或环境噪声的误差可能大于这些误差。)


换句话说,这些小数值只会困扰你,人类,而不是电脑。忽略它们。

为什么需要对值进行四舍五入?您需要四舍五入到特定的有效位数,而不是小数点后的特定位数。这里有很多答案表面上解决了问题,但您没有足够清楚地说明问题,因此它们可能没有用。所以我再次问,你到底想达到什么目的?只有当你知道一个微小的数字不能是微小的,除非精确计算的值(没有算术舍入误差)为零,或者如果你能从数学上证明它改善了你的最终结果,你才应该将它“修正”为零。这就是为什么我们要求你解释为什么你需要轮换。正确的答案取决于具体情况。@EricPostChil我已经更新了这个问题。二进制浮点实际上没有小数位数的概念,所以这通常不起作用。有否定的原因吗?对于给定的问题,这绝对是正确的解决方案。我投了反对票,因为这给人一种误导性的印象,即小数点在浮点运算中是有意义的。@OliCharlesworth-不,它没有意义。浮点值仍然遵守数学规则。@OliCharlesworth不管你怎么说它都能工作。我是stackoverflow的新手,它在哪里说的?有些答案是用java语言写的。我不能完全赞同这个答案。OP表示他们担心小数字在乘法时会产生错误的结果
public static double round10(double d) {
    final double factor = 1e10;
    return d > Long.MAX_VALUE / factor || d < -Long.MAX_VALUE / factor ?
            (long) (d < 0 ? d * factor - 0.5 : d * factor + 0.5) / factor : d;
}