Округление до произвольного числа значащих цифр - PullRequest
78 голосов
/ 14 октября 2008

Как можно округлить любое число (не только целые числа> 0) до N значащих цифр?

Например, если я хочу округлить до трех значащих цифр, я ищу формулу, которая может принять:

1 239 451 и возврат 1 240 000

12,1257 и возврат 12,1

.0681 и возврат .0681

5 и возврат 5

Естественно, алгоритм не должен быть жестко закодирован, чтобы обрабатывать только N из 3, хотя это было бы началом.

Ответы [ 17 ]

1 голос
/ 17 октября 2009

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

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

& бык; Умножьте число на 10 N
& Бык; Добавить 0.5
& Бык; Усечение цифр дроби (то есть усечение результата в целое число)
& Бык; Разделите на 10 N

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

& бык; Разделите число на 10 N
& Бык; Добавить 0.5
& Бык; Усечение цифр дроби (то есть усечение результата в целое число)
& Бык; Умножьте на 10 N

Это можно сделать на любом калькуляторе, например, с оператором INT (целочисленное усечение).

1 голос
/ 14 октября 2008

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

  1. Преобразовать число в строку
  2. Начиная с начала строка, количество цифр - ведущие нули не все остальное имеет значение.
  3. Когда вы доберетесь до "n" цифры, заглянуть вперед на следующую цифру, и если это 5 или выше, округлить вверх.
  4. Заменить все завершающие цифры нулями.
1 голос
/ 22 июня 2010
/**
 * 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);
}
0 голосов
/ 28 января 2018

Мне нужно было это в Go, что было немного сложно из-за отсутствия стандартной библиотеки Go в math.Round() (до go1.10). Так что мне тоже пришлось это взбить. Вот мой перевод Отличный ответ Пиролистика :

// TODO: replace in go1.10 with math.Round()
func round(x float64) float64 {
    return float64(int64(x + 0.5))
}

// SignificantDigits rounds a float64 to digits significant digits.
// Translated from Java at https://stackoverflow.com/a/1581007/1068283
func SignificantDigits(x float64, digits int) float64 {
    if x == 0 {
        return 0
    }

    power := digits - int(math.Ceil(math.Log10(math.Abs(x))))
    magnitude := math.Pow(10, float64(power))
    shifted := round(x * magnitude)
    return shifted / magnitude
}
0 голосов
/ 27 марта 2017

return new BigDecimal(value, new MathContext(significantFigures, RoundingMode.HALF_UP)).doubleValue();

0 голосов
/ 01 июня 2013

Это тот, который я придумал в VB:

Function SF(n As Double, SigFigs As Integer)
    Dim l As Integer = n.ToString.Length
    n = n / 10 ^ (l - SigFigs)
    n = Math.Round(n)
    n = n * 10 ^ (l - SigFigs)
    Return n
End Function
0 голосов
/ 19 мая 2013
public static double roundToSignificantDigits(double num, int n) {
    return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString());
}

Этот код использует встроенную функцию форматирования, которая превращается в функцию округления

...