Округление к произвольному числу значащих цифр

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

79
задан Peter Mortensen 4 May 2017 в 20:18
поделиться

9 ответов

Вот тот же код на 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;
}
102
ответ дан 24 November 2019 в 10:12
поделиться

СВОДКА:

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 цифры, затем вокруг Энной цифры на основе остальных.

Мы можем использовать журнал, чтобы сделать первое.

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

Так для чисел> 0, возьмите перекрытие журнала. Для чисел < 0, получите слово журнала.

Теперь у нас есть цифра d: 7 в первом случае, 2 в 2-м,-2 в 3-м.

Мы имеем к раунду (d-N) th цифра. Что-то как:

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

Так, используйте ответ Пиротехнического средства!

15
ответ дан Claudiu 24 November 2019 в 10:12
поделиться

Вот короткая и сладкая реализация 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
15
ответ дан Ates Goral 24 November 2019 в 10:12
поделиться

Вы попытались просто кодировать его способ, которым Вы сделали бы это вручную?

  1. Преобразовывают число в строку
  2. Запуск в начале строки, цифр количества - продвижение обнуляет, не являются значительными, все остальное.
  3. , Когда Вы добираетесь до "энной" цифры, посмотрите вперед на следующую цифру и если это 5 или выше, окружить.
  4. Замена все запаздывающие цифры с обнуляют.
1
ответ дан Mark Bessey 24 November 2019 в 10:12
поделиться

Разве это не «короткая и приятная» реализация JavaScript

Number(n).toPrecision(sig)

, например,

alert(Number(12345).toPrecision(3)

?

Извините, Здесь я не шучу, просто использование функции "roundit" из Claudiu и .toPrecision в JavaScript дает мне другие результаты, но только при округлении последней цифры.

JavaScript:

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

.NET

roundit(8.14301,4) == 8.144
10
ответ дан Justin Wignall 24 November 2019 в 10:12
поделиться

[Исправлено, 2009-10-26]

По сути, для N значащих дробных цифр:

• Умножьте число на 10 N
• Добавить 0,5
• Усекать дробные цифры (т. Е. Усекать результат до целого числа)
• Разделить на 10 N

Для N значащих целых (недробных) цифр:

• Разделить число на 10 N
• Добавить 0,5
• Усекать дробные цифры (т. Е. Усекать результат до целого числа)
• Умножение на 10 N

Вы можете сделать это на любом калькуляторе, например, который имеет оператор «INT» (целочисленное усечение).

1
ответ дан 24 November 2019 в 10:12
поделиться

Вот модифицированная версия JavaScript Атеса, которая работает с отрицательными числами.

function sigFigs(n, sig) {
    if ( n === 0 )
        return 0
    var mult = Math.pow(10,
        sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
 }
3
ответ дан 24 November 2019 в 10:12
поделиться
/**
 * Set Significant Digits.
 * @param value value
 * @param digits digits
 * @return
 */
public static BigDecimal setSignificantDigits(BigDecimal value, int digits) {
    //# Start with the leftmost non-zero digit (e.g. the "1" in 1200, or the "2" in 0.0256).
    //# Keep n digits. Replace the rest with zeros.
    //# Round up by one if appropriate.
    int p = value.precision();
    int s = value.scale();
    if (p < digits) {
        value = value.setScale(s + digits - p); //, RoundingMode.HALF_UP
    }
    value = value.movePointRight(s).movePointLeft(p - digits).setScale(0, RoundingMode.HALF_UP)
        .movePointRight(p - digits).movePointLeft(s);
    s = (s > (p - digits)) ? (s - (p - digits)) : 0;
    return value.setScale(s);
}
1
ответ дан 24 November 2019 в 10:12
поделиться

Как насчет этого решения Java:

double roundToSignificantFigure(double num, int precision){
 return new BigDecimal(num)
            .round(new MathContext(precision, RoundingMode.HALF_EVEN))
            .doubleValue(); 
}
6
ответ дан 24 November 2019 в 10:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: