LINUX.ORG.RU

Определение «веса» дробной части при округлении чисел до определенного знака

 ,


0

1

Задача простая: нужно округлять числа до N знаков после запятой. Делаю это классическим способом (Rust):

static POW_VEC: &'static [f64] = &[
    0.0,
    10.0,
    100.0,
    1000.0,
    10000.0,
    100000.0,
    1000000.0,
    10000000.0,
    100000000.0,
];

fn round(num: f64, precision: u8) -> f64 {
    let multiplier = POW_VEC[precision as usize];
    let tmp_value = (num * multiplier).round().abs() as u64;
    ((tmp_value as f64) / multiplier) * num.signum()
}

fn main() {
    println!("{}", round(123.456789, 3)); // 123.457
}
Всё хорошо работает, до тех пор, пока не попадаются числа вида: 123.001. Мне эти 0.001 совсем не нужны, но при точности в 3-и знака - они остаются.

Также нужно учитывать, что 0.001 вполне себе число, просто маленькое. И у него дробную часть округлять нельзя.

То есть мне нужен алгоритм, которые определит, что дробная часть незначительна относительно целой части.

Примеры (при условии что точность 3-и знака):

1000000.001 -> 1000000

1000000.4 -> 1000000

80.005 -> 80

123.015 -> 123

1.001 -> 1.001

0.001 -> 0.001

0.0005 -> 0.001

Уверен, что-то подобное уже существует, только хз в какую сторону гуглить.

То есть мне нужен алгоритм, которые определит, что дробная часть незначительна относительно целой части.

Из примеров получается, что при точности до 3-го знака незначительной считается дробная часть, которая более, чем в 1000 раз меньше целой.

const threshold = power(0.1,3);
value=round(value,3);
if (value-floor(value))/value<threshold
value=floor(value)
sholom ()

Как вариант делить целочисленную часть на дробную и действовать исходя из коэффициента.

kravzo ★★ ()
Ответ на: комментарий от RazrFalcon

Ну определи сам, исходя из задачи, где заканчивается «незначительность».

kravzo ★★ ()
Ответ на: комментарий от sholom

Походу оно. Спасибо.

Как минимум на моих выборках все обработало верно.

RazrFalcon ★★★★★ ()

в какую сторону гуглить.

Граница относительной погрешности. ©

quickquest ★★★★★ ()

Тебе нужны логарифмы. Если твоё N = 100500.0001, посчитай что-то вроде

log10(int(N)) + log10(frac(N))


где int() - функция, возвращающая целую часть N, frac() - дробную, а log10() - логарифм по основанию 10.

Логарифм от дробной части будет отрицательным, поэтому если их сумма будет, скажем, больше -1 (ведь ты хотел «учитывать, что 0.001 вполне себе число, просто маленькое» для 123) тогда дробную часть можно отбрасывать.

blexey ★★★★★ ()

Если больше 50, то округлять до целого. Или что понимать под словом «незначительного»?

monk ★★★★★ ()
Ответ на: комментарий от monk

Почему именно 50? 50.99 вполне 51. Или вы о .5? Тогда см. примеры. Особенно сам код. Там не просто округление до целого.

RazrFalcon ★★★★★ ()
Ответ на: комментарий от RazrFalcon

В примерах начиная с 80 округления до целого, до 1.001  — округление в 3 знака. Предположил, что граница где-то на 50 (можно любую другую от 2 до 79).

Поэтому можно просто писать if(x>50) round(x,0) else round(x,3)

monk ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.