I looked hard at #min:max: some years ago and decided it
was way too confusing to ever use.�� My own library has
Magnitude>>
������ median: lower and: upper
���������� "I considered adding a method
�������������� clampedBetween: lower and: upper
������������������ ^self < lower ifTrue: [lower] ifFalse: [
�������������������� upper < self ifTrue: [upper] ifFalse: [self]]
������������ This sends #< once or twice.�� The only snag is that it
������������ doesn't make much sense unless lower <= upper, and it
������������ doesn't check that.
������������ Squeak has a method
���������������� min: min max: max
�������������������� ^(self min: min) max: max
������������ which could be simplified to
�������������� min: min max: max
������������������ |t|
������������������ t := min < self ifTrue: [min] ifFalse: [self].
������������������ ^max < t ifTrue: [max] ifFalse: [t]
���������� The name here is a little confusing.�� min: x max: y is
���������� pretty much the same as clampedBetween: y and: x.
���������� This version always does two comparisons, but still makes
���������� little or no sense unless min >= max, which it does not
���������� check.�� It would be easy enough for me to add the Squeak
���������� method, but I find it far too confusing to use.
���������� I wanted a method which gave the same result as
���������� clampedBetween:and: whenever that made sense, and which
���������� took no more than two comparisons whenever clampedBetween:and:
���������� or min:max: would have made sense, but which always makes
���������� sense as long as all the arguments are comparable.
���������� The answer is simple:�� the median.�� Actually, it isn't quite
���������� the answer.�� If the receiver lies between lower and upper, it
���������� takes two comparisons.���� If not, it takes a third comparison
���������� to decide which of the two end-points to return, which seems
���������� fair enough, because if we don't _assume_ the relative order
���������� of the end-points, we have to _find out_."
���������� ^self < lower
���������������� ifTrue:�� [�������������� "self < lower"
�������������������� self < upper
������������������������ ifFalse: [������ "upper <= self < lower" self]
������������������������ ifTrue:�� [������ "self < lower, self < upper"
���������������������������� upper < lower
�������������������������������� ifTrue:�� ["self < upper < lower"�� upper]
�������������������������������� ifFalse: ["self < lower <= upper" lower]]]
���������������� ifFalse: [�������������� "lower <= self"
�������������������� upper < self
������������������������ ifFalse: [������ "lower <= self <= upper" self]
������������������������ ifTrue:�� [������ "lower <= self, upper <= self"
���������������������������� upper < lower
�������������������������������� ifTrue:�� ["upper < lower <= self" lower]
�������������������������������� ifFalse: ["lower <= upper <= self" upper]]]
That is, (x median: y and: z) returns the middle value,
whatever order x y and z are in.