Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Ruby.docx
Скачиваний:
18
Добавлен:
06.09.2019
Размер:
1.74 Mб
Скачать

5.1. Представление чисел в языке Ruby

Если вы знакомы с любым другим языком программирования, то представление чисел в Ruby не вызовет у вас никакого удивления. Объект класса Fixnum может представлять число со знаком или без знака:

237  # Число без знака (положительное).

+237 # То же, что и выше.

-237 # Отрицательное число.

Если число длинное, то между любыми цифрами можно вставлять знак подчеркивания. Это сделано исключительно для удобства, назначении константы никак не сказывается. Обычно подчерки вставляются в те же места, где бухгалтеры вставляют пробелы:

1048576   # Число в обычной записи.

1_048_576 # То же самое значение.

Целые числа можно представлять и в других системах счисления (по основанию 2, 8 и 16). Для этого в начале ставятся префиксы 0b, 0 и 0х соответственно.

0b10010110 # Двоичное.

0b1211     # Ошибка!

01234      # Восьмеричное (основание 8).

01823      # Ошибка!

0xdeadbeef # Шестнадцатеричное (основание 16) .

0xDEADBEEF # То же самое.

0xdeadpork # Ошибка!

В числах с плавающей точкой десятичная точка должна присутствовать, а показатель степени, возможно со знаком, необязателен:

3.14         # Число пи, округленное до сотых.

-0.628       # -2*pi, поделенное на 10, округленное до тысячных.

6.02е23      # Число Авогадро.

6.626068е-34 # Постоянная Планка.

В классе Float есть константы, определяющие минимальные и максимальные значения чисел с плавающей точкой. Они машиннозависимы. Вот некоторые наиболее важные:

Float::MIN     # 2.2250738585072е-308 (на конкретной машине)

Float::МАХ     # 1.79769313486232е+308

Float::EPSILON # 2.22044604925031е-16

5.2. Основные операции над числами

Обычные операции сложения, вычитания, умножения и деления в Ruby, как и во всех распространенных языках программирования, обозначаются операторами +, -, *, /. Операторы в большинстве своем реализованы в виде методов (и потому могут быть переопределены).

Возведение в степень обозначается оператором **, как в языках BASIC и FORTRAN. Эта операция подчиняется обычным математическим правилам.

а = 64**2   # 4096

b = 64**0.5 # 8.0

с = 64**0   # 1

d = 64**-1  # 0.015625

При делении одного целого числа на другое дробная часть результата отбрасывается. Это не ошибка, так и задумано. Если вы хотите получить результат с плавающей точкой, позаботьтесь о том, чтобы хотя бы один из операндов был числом c плавающей точкой.

3 / 3     # 3

5 / 3     # 1

3 / 4     # 0

3.0 / 4   # 0.75

3 / 4.0   # 0.75

3.0 / 4.0 # 0.75

Если вы работаете с переменными и сомневаетесь относительно их типа, воспользуйтесь приведением типа к Float или методом to_f:

z = x.to_f / у z = Float(x) / y

См. также раздел 5.17 «Поразрядные операции над числами».

5.3. Округление чисел с плавающей точкой

Кирк: Какие, вы говорите, у нас шансы выбраться отсюда?

Спок: Трудно сказать точно, капитан. Приблизительно 7824.7 к одному.

Стар Трек, «Миссия милосердия»

Метод round округляет число с плавающей точкой до целого:

pi = 3.14159

new_pi = pi.round  # 3

temp = -47.6

temp2 = temp.round # -48

Иногда бывает нужно округлить не до целого, а до заданного числа знаков после запятой. В таком случае можно воспользоваться функциями sprintf (которая умеет округлять) и eval:

pi = 3.1415926535

pi6 = eval(sprintf("%8.6f",pi)) # 3.141593

pi5 = eval(sprintf("%8.5f",pi)) # 3.14159

pi4 = eval(sprintf("%8.4f",pi)) # 3.1416

Это не слишком красиво. Поэтому инкапсулируем оба вызова функций в метод, который добавим в класс Float:

class Float

 def roundf(places)

  temp = self.to_s.length

  sprintf("%#{temp}.#{places}f",self).to_f

 end

end

Иногда требуется округлять до целого по-другому. Традиционное округление n+0.5 с избытком со временем приводит к небольшим ошибкам; ведь n+0.5 все-таки ближе к n+1, чем к n. Есть другое соглашение: округлять до ближайшего четного числа, если дробная часть равна 0.5. Для реализации такого правила можно было бы расширить класс Float, добавив в него метод round2:

class Float

 def round2

  whole = self.floor

  fraction = self — whole

  if fraction == 0.5

   if (whole % 2) == 0

    whole

   else

    whole+1

   end

  else

   self.round

  end

 end

end

a = (33.4).round2 # 33

b = (33.5).round2 # 34

с = (33.6).round2 # 34

d = (34.4).round2 # 34

e = (34.5).round2 # 34

f = (34.6).round2 # 35

Видно, что round2 отличается от round только в том случае, когда дробная часть в точности равна 0.5. Отметим, кстати, что число 0.5 можно точно представить в двоичном виде. Не так очевидно, что этот метод правильно работает и для отрицательных чисел (попробуйте!). Отметим еще, что скобки в данном случае необязательны и включены в запись только для удобства восприятия.

Ну а если мы хотим округлять до заданного числа знаков после запятой, но при этом использовать метод «округления до четного»? Тогда нужно добавить в класс Float также метод roundf2:

class Float

 # Определение round2 такое же, как и выше.

 def roundf2(places)

  shift = 10**places

  (self * shift).round2 / shift.to_f

 end

end

a = 6.125

b = 6.135

x = a.roundf2(a) #6.12

y = b.roundf2(b) #6.13

У методов roundf и roundf2 есть ограничение: большое число с плавающей точкой может стать непредставимым при умножении на большую степень 10. На этот случай следовало бы предусмотреть проверку ошибок.