алгоритм округления до следующего порядка величины в R - PullRequest
7 голосов
/ 26 октября 2011

Я прошу прощения, если название не ясно, но я не мог объяснить это кратко.

Учитывая вектор концентраций, я бы хотел округлить максимальное значение до следующего порядка (т.е. от 345 до 1000). Кроме того, я хотел бы округлить минимальное значение до более низкого порядка (т.е. от 3,2 до 1). Эти концентрации также могут быть ниже 1, поэтому, например, 0,034 необходимо округлить до 0,01.

Есть идеи?

Ответы [ 5 ]

15 голосов
/ 26 октября 2011

Я не уверен насчет R, но это простой процесс для алгоритмического описания.

Возьмите логарифм числа 10 и примените к результату потолок или пол.Поднимите 10 до этой силы.Готово.

Вам нужен специальный случай для 0, потому что вы не можете взять логарифм 0.

12 голосов
/ 26 октября 2011

Вот простая функция, которая делает то, что вы ищете:

log10_ceiling <- function(x) {
    10^(ceiling(log10(x)))
}

log10_ceiling(c(345, 3.2, 0.034))
# [1] 1000.0   10.0    0.1
2 голосов
/ 09 февраля 2012

Принятый ответ Марка Рэнсома в основном правильный. Внедрив это в Java, я нашел еще несколько областей, которые необходимо решить:

  • Отрицательные числа должны обрабатываться специально, если вы хотите, чтобы -375 давал -1000
  • Потолок для положительных логарифмов, пол + 1 для отрицательных логарифмов (плюс очень важно, если вы хотите, чтобы 0,456 давало 1).

Вот моя реализация на Java с прохождением модульных тестов

static double roundUpToNearestMagnitude(double n) {
    if (n == 0d) return 1d; 
    boolean negative = n < 0; 
    double log = Math.log10(Math.abs(n));
    double decimalPlaces = ((log > 0)) ? (Math.ceil(log)) : (Math.floor(log) + 1);
    double rounded = Math.pow(10, decimalPlaces);
    return negative ? -rounded : rounded;
}

@Test public void roundUpToNearestMagnitudeFifty() {
    Assert.assertEquals(100d, roundUpToNearestMagnitude(50d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeFive() {
    Assert.assertEquals(10d, roundUpToNearestMagnitude(5d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeZeroPointFive() {
    Assert.assertEquals(1d, roundUpToNearestMagnitude(0.5d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeZeroPointZeroFive() {
    Assert.assertEquals(.1d, roundUpToNearestMagnitude(0.05d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeZeroPointZeroZeroFive() {
    Assert.assertEquals(.01d, roundUpToNearestMagnitude(0.005d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeNegativeFifty() {
    Assert.assertEquals(-100d, roundUpToNearestMagnitude(-50d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeNegativeFive() {
    Assert.assertEquals(-10d, roundUpToNearestMagnitude(-5d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeNegativeZeroPointFive() {
    Assert.assertEquals(-1d, roundUpToNearestMagnitude(-0.5d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeNegativeZeroPointZeroFive() {
    Assert.assertEquals(-.1d, roundUpToNearestMagnitude(-0.05d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeNegativeZeroPointZeroZeroFive() {
    Assert.assertEquals(-.01d, roundUpToNearestMagnitude(-0.005d), 0.000001);
}

@Test public void roundUpToNearestMagnitudeZero() {
    Assert.assertEquals(1, roundUpToNearestMagnitude(0d), 0.000001);
}
2 голосов
/ 26 октября 2011

Пакет Hadley plyr имеет чрезвычайно гибкую функцию, называемую round_any, которая делает это элегантно. Вот как бы вы назвали функцию

round_any(x, accuracy, f = round)

В вашем случае x = 345, accuracy = 1000 и вы хотите f = ceiling. Так зовут

round_any(x = 345, accuracy = 1000, f = ceiling) 

сделает работу

EDIT. Только что увидел, что вы хотите, чтобы maximum было округлено до ceiling, а минимальные значения округлены до floor. измените f в вызове функции для достижения этого.

1 голос
/ 20 июля 2018

Если кому-то интересно, то решение Остермиллера переведено на Python:

def roundUpToNearestMagnitude(n):
    if n == 0:
        return 1
    negative = n < 0
    log = np.log10(abs(n))
    if log > 0:
        decimalPlaces = np.ceil(log)
    else:
        decimalPlaces = np.floor(log) + 1
    rounded = np.power(10, decimalPlaces)
    if negative:
        return -rounded
    else:
        return rounded

def test_roundUpToNearestMagnitude():
    assert(100 == roundUpToNearestMagnitude(50))
    assert(10 == roundUpToNearestMagnitude(5))
    assert(1 == roundUpToNearestMagnitude(0.5))
    assert(.1 == roundUpToNearestMagnitude(0.05))
    assert(.01 == roundUpToNearestMagnitude(0.005))
    assert(-100 == roundUpToNearestMagnitude(-50))
    assert(-10 == roundUpToNearestMagnitude(-5))
    assert(-1 == roundUpToNearestMagnitude(-0.5))
    assert(-.1 == roundUpToNearestMagnitude(-0.05))
    assert(-.01 == roundUpToNearestMagnitude(-0.005))
    assert(1 == roundUpToNearestMagnitude(0))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...