(←) предыдущая запись ; следующая запись (→)
Ладно… Давайте теперь сломаем сортировку ещё чуть-чуть. Предположим, что у вас есть неупорядоченный набор координат иксов, в котором нет никаких NaN. Вы решили их упорядочить и отрезочками нарисовать по ним гиперболу. Она состоит из двух ветвей, нарисуем их отдельно, чтобы было точнее. Казалось бы, что может пойти не так?
xs = [4, -4, 2, -2, 1, -1, 0.5, -0.5, 0.25, -0.25, 0.0, -0.0]
````xs.sort!
ys = xs.map{|x| 1.0 / x }
points` =
xs.zip(ys)
puts(“Points with x < 0”)
left_side_points = points.select{|x, y| x < 0 }
left_side_points.each{|x,y| puts ”(#{x}, #{y})” }
puts(“Points with x >= 0”)
right_side_points = points.select{|x, y| x >= 0 }
right_side_points.each{|x,y| puts ”(#{x}, #{y})” }
Points with x < 0
(-4, -0.25)
(-2, -0.5)
(-1, -1.0)
(-0.5, -2.0)
(-0.25, -4.0)
Points with x >= 0
(0.0, Infinity)
(-0.0, -Infinity)
(0.25, 4.0)
(0.5, 2.0)
(1, 1.0)
(2, 0.5)
(4, 0.25)
```И вот мы получили правую ветвь гиперболы 1/x
, которая от +∞
ныряет в -∞
, и затем выскакивает в точку (0.25, 4) снизу, а не сверху. Глупость какая-то!
Обратите внимание на список иксов. Там есть x = 0, причём дважды. В некоторых языках (например, в ruby) деление на ноль разрешено. Стандарт разрешает не бросать исключение при такой операции. Ненулевое число, делённое на ноль — это бесконечность. Вот только стандарт определяет две разные бесконечности: положительную и отрицательную. И нулей тоже есть два разных (хотя и равных): +0.0
и -0.0
.
При сортировке они могут оказаться в любом порядке, ведь они равны.
[1, +0.0, -1, -0.0].sort # => [-1, 0.0, -0.0, 1]
```Ещё раз подчеркну, что это разные числа, которые по-разному себя ведут: `1 / 0.0 = +Infinity`, а `1 / -0.0 = -Infinity`.
Именно поэтому мы получили «отсортированный» набор иксов, идущих сначала в +0.0, затем в -0.0. И гипербола вслед за иксами уходит в соответствующую область.