当前位置:  开发笔记 > 编程语言 > 正文

舍入到任意数量的有效数字

如何解决《舍入到任意数量的有效数字》经验,为你挑选了6个好方法。

你怎么能将任何数字(不只是整数> 0)舍入到N位有效数字?

例如,如果我想要舍入到三位有效数字,我正在寻找一个可以采用的公式:

1,239,451并返回1,240,000

12.1257并​​返回12.1

.0681并返回.0681

5并返回5

当然,算法不应该被硬编码为仅处理3的N,尽管这将是一个开始.



1> Pyrolistical..:

这里是Java中的相同代码,没有其他答案所具有的12.100000000000001错误

我还删除了重复的代码,更改power为类型整数以防止浮动问题n - d完成,并使长中间更清晰

该错误是由一个较大的数字乘以一个小数字引起的.相反,我划分两个相似大小的数字.

编辑
修正了更多错误.添加了0的检查,因为它会导致NaN.使该函数实际上使用负数(原始代码不处理负数,因为负数的对数是一个复数)

public static double roundToSignificantFigures(double num, int n) {
    if(num == 0) {
        return 0;
    }

    final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
    final int power = n - (int) d;

    final double magnitude = Math.pow(10, power);
    final long shifted = Math.round(num*magnitude);
    return shifted/magnitude;
}


这个java片段最终在官方的android示例中https://android.googlesource.com/platform/development/+/fcf4286/samples/training/InteractiveChart/src/com/example/android/interactivechart/InteractiveLineGraphView.java
谢谢你接受我的回答.我刚刚意识到我的答案是问题后一年多.这就是stackoverflow如此酷的原因之一.你可以找到有用的信息!
请注意,对于接近圆形限制的值,这可能会略微失败.例如,舍入1.255到3位有效数字应返回1.26但返回1.25.那是因为1.255*100.0是125.499999 ...但是在使用双打时这是可以预料的

2> Claudiu..:

摘要:

double roundit(double num, double N)
{
    double d = log10(num);
    double power;
    if (num > 0)
    {
        d = ceil(d);
        power = -(d-N);
    }
    else
    {
        d = floor(d); 
        power = -(d-N);
    }

    return (int)(num * pow(10.0, power) + 0.5) * pow(10.0, -power);
}

因此,您需要找到第一个非零数字的小数位,然后保存下一个N-1个数字,然后根据其余数字舍入第N个数字.

我们可以使用log来做第一个.

log 1239451 = 6.09
log 12.1257 = 1.08
log 0.0681  = -1.16

所以对于数字> 0,取日志的ceil.对于数字<0,请记录日志.

现在我们有数字d:第一种情况下为7,第二种情况下为2,第3种情况下为-2.

我们必须绕过这个(d-N)数字.就像是:

double roundedrest = num * pow(10, -(d-N));

pow(1239451, -4) = 123.9451
pow(12.1257, 1)  = 121.257
pow(0.0681, 4)   = 681

那么做标准的舍入事情:

roundedrest = (int)(roundedrest + 0.5);

并撤消战俘.

roundednum = pow(roundedrest, -(power))

其中功率是上面计算的功率.


关于准确性:Pyrolistical的答案确实更接近实际结果.但请注意,在任何情况下都不能完全代表12.1.如果您打印答案如下:

System.out.println(new BigDecimal(n));

答案是:

Pyro's: 12.0999999999999996447286321199499070644378662109375
Mine: 12.10000000000000142108547152020037174224853515625
Printing 12.1 directly: 12.0999999999999996447286321199499070644378662109375

所以,使用Pyro的答案!


它是64位还是128位并不重要.您不能使用有限的2的幂和来表示分数1/10,这就是浮点数的表示方式
对于那些人来说,基本上Pyrolistical的答案比我的更精确,因此浮点数打印算法打印'12 .1'而不是'12 .100000000000001'.他的答案更好,即使我在技术上是正确的,你也不能完全代表'12 .1'.

3> Ates Goral..:

这是一个简短而又甜蜜的JavaScript实现:

function sigFigs(n, sig) {
    var mult = Math.pow(10, sig - Math.floor(Math.log(n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
}

alert(sigFigs(1234567, 3)); // Gives 1230000
alert(sigFigs(0.06805, 3)); // Gives 0.0681
alert(sigFigs(5, 3)); // Gives 5



4> Justin Wigna..:

不是"短而甜蜜"的JavaScript实现

Number(n).toPrecision(sig)

例如

alert(Number(12345).toPrecision(3)

对不起,我在这里不是很滑稽,只是使用Claudiu的"roundit"函数和JavaScript中的.toPrecision给出了不同的结果,但只是在最后一位数的四舍五入.

JavaScript的:

Number(8.14301).toPrecision(4) == 8.143

.净

roundit(8.14301,4) == 8.144



5> 小智..:

Pyrolistical(非常好!)解决方案仍有问题.Java中的最大double值大约为10 ^ 308,而最小值大约为10 ^ -324.因此,将函数roundToSignificantFigures应用于十分之一的幂时,可能会遇到麻烦Double.MIN_VALUE.例如,当你打电话时

roundToSignificantFigures(1.234E-310, 3);

然后变量power将具有值3 - (-309)= 312.因此,变量magnitude将变为Infinity,从那时起它就是垃圾.幸运的是,这不是一个不可逾越的问题:它只是溢出的因素 magnitude.真正重要的是产品 num * magnitude,而且不会溢出.解决这个问题的一种方法是将因子乘以magintude两个步骤:


 public static double roundToNumberOfSignificantDigits(double num, int n) {

    final double maxPowerOfTen = Math.floor(Math.log10(Double.MAX_VALUE));

    if(num == 0) {
        return 0;
    }

    final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
    final int power = n - (int) d;

    double firstMagnitudeFactor = 1.0;
    double secondMagnitudeFactor = 1.0;
    if (power > maxPowerOfTen) {
        firstMagnitudeFactor = Math.pow(10.0, maxPowerOfTen);
        secondMagnitudeFactor = Math.pow(10.0, (double) power - maxPowerOfTen);
    } else {
        firstMagnitudeFactor = Math.pow(10.0, (double) power);
    }

    double toBeRounded = num * firstMagnitudeFactor;
    toBeRounded *= secondMagnitudeFactor;

    final long shifted = Math.round(toBeRounded);
    double rounded = ((double) shifted) / firstMagnitudeFactor;
    rounded /= secondMagnitudeFactor;
    return rounded;
}



6> 小智..:

这个java解决方案怎么样:

double roundToSignificantFigure(double num, int precision){
 return new BigDecimal(num)
            .round(new MathContext(precision, RoundingMode.HALF_EVEN))
            .doubleValue(); 
}

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有