2014-12-13 2 views
2

Я хочу округлить любое заданное число до восьмого или третьего в Ruby, в зависимости от того, что ближе всего.Округление числа до ближайшего дробного восьмого или третьего в Ruby

Я надеюсь на выход как 1/8 или 2/3.

Я попытался следующие:

scalar_in_eighths = (scalar * 8.0).round/8.0 
scalar_in_thirds = (scalar * 3.0).round/3.0 

thirds_difference = (scalar - scalar_in_thirds).abs 
eighths_difference = (scalar - scalar_in_eighths).abs 

compute_in_thirds = thirds_difference < eighths_difference 

if compute_in_thirds 
    less_than_eighth = false 
    rounded_scalar = scalar_in_thirds 
else 
    less_than_eighth = false 
    rounded_scalar = scalar_in_eighths 
end 

quotient, modulus = rounded_scalar.to_s.split '.' 
quotient = quotient.to_f 
modulus = ".#{modulus}".to_f 

Это хорошо работает для восьмерок, но и для чисел, как 1.32 она ломается.

Ведение modulus.numerator и modulus.denominator для дробных компонентов даст число, как 6004799503160661 и 18014398509481984.

Есть ли лучший способ решить эту проблему?

ответ

1

Вот один из способов его написания.

Код

def closest_fraction(f,*denominators) 
    n, frac = denominators.map { |n| [n, round_to_fraction(f,n)] } 
         .min_by { |_,g| (f-g).abs } 
    [(n*frac).round, n, frac] 
end 

def round_to_fraction(f,n) 
    (f*n).round/n.to_f 
end 

Примеры

closest_fraction(2.33, 3, 8) 
    #=> [7, 3, 2.3333333333333335] 
closest_fraction(2.12, 3, 8) 
    #=> [17, 8, 2.125] 
closest_fraction(2.46, 2, 3, 5) 
    #=> [5, 2, 2.5] 
closest_fraction(2.76, 2, 3, 5, 7, 11, 13, 17) 
    #=> [47, 17, 2.764705882352941] 
+0

Я не уверен, что это дает целые числа, как числитель и знаменатель для трети. –

+1

Первый пример возвращает 7/3. Разве это не то, что вы хотите? –

+0

А, моя ошибка. Я неправильно понял. Я думаю, что я применил бы это только к модулю, чтобы получить 1/3, 2/3, поскольку это было непонятно в моем вопросе. –