Take the 2008 Git User's Survey and help out! [ hide ]

public
Description: Rubinius, the Ruby VM
Homepage: http://rubini.us
Clone URL: git://github.com/evanphx/rubinius.git
Search Repo:
NoKarma (author)
Tue May 13 01:43:22 -0700 2008
commit  7d249bcf4949a387a0bd26487a87129c4e1372e6
tree    d09b0066dce53c18ce1c08556b63e94b808dff1b
parent  40dcef8eb366750f795c6825fedeb9e8073f0bc1
rubinius / kernel / core / numeric.rb
100644 226 lines (186 sloc) 4.21 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# depends on: class.rb comparable.rb
 
class Numeric
  include Comparable
 
  # Numeric and sub-classes do not have ivars
  def __ivars__ ; nil ; end
 
  def +@
    self
  end
 
  def -@
    0 - self
  end
 
  def +(other)
    b, a = math_coerce other
    a + b
  end
  
  def -(other)
    b, a = math_coerce other
    a - b
  end
  
  def *(other)
    b, a = math_coerce other
    a * b
  end
  
  def %(other)
    b, a = math_coerce other
    raise ZeroDivisionError, "divided by 0" unless b.__kind_of__(Float) or b != 0
    a % b
  end
 
  #--
  # see README-DEVELOPERS regarding safe math compiler plugin
  #++
 
  def divide(other)
    b, a = math_coerce other
    raise ZeroDivisionError, "divided by 0" unless b.__kind_of__(Float) or b != 0
    a / b
  end
  alias_method :/, :divide
  
  def **(other)
    b, a = math_coerce other
    a ** b
  end
  
  def divmod(other)
    b, a = math_coerce other
    
    if other == 0
      raise FloatDomainError, "NaN" if other.__kind_of__ Float
      raise ZeroDivisionError, "divided by 0"
    end
    
    a.divmod b
  end
  
  def div(other)
    raise FloatDomainError, "NaN" if self == 0 && other.__kind_of__(Float) && other == 0
    b, a = math_coerce other
    (a / b).floor
  end
 
  def quo(other)
    if other.__kind_of__ Integer
      self / Float(other)
    else
      b, a = math_coerce other
      a / b
    end
  end
 
  def <(other)
    b, a = math_coerce other, :compare_error
    a < b
  end
  
  def <=(other)
    b, a = math_coerce other, :compare_error
    a <= b
  end
  
  def >(other)
    b, a = math_coerce other, :compare_error
    a > b
  end
  
  def >=(other)
    b, a = math_coerce other, :compare_error
    a >= b
  end
 
  def ==(other)
    !!(other == self)
  end
  
  def <=>(other)
    begin
      b, a = math_coerce other, :compare_error
      return a <=> b
    rescue ArgumentError
      return nil
    end
  end
 
  def integer?
    false
  end
 
  def zero?
    self == 0
  end
 
  def nonzero?
    zero? ? nil : self
  end
 
  def round
    self.to_f.round
  end
  
  def abs
    self < 0 ? -self : self
  end
 
  def floor
    int = self.to_i
    if self == int or self > 0
      int
    else
      int - 1
    end
  end
 
  def ceil
    int = self.to_i
    if self == int or self < 0
      int
    else
      int + 1
    end
  end
 
  def remainder(other)
    b, a = math_coerce other
    mod = a % b
 
    if mod != 0 && (a < 0 && b > 0 || a > 0 && b < 0)
      mod - b
    else
      mod
    end
  end
 
  #--
  # We deviate from MRI behavior here because we ensure that Fixnum op Bignum
  # => Bignum (possibly normalized to Fixnum)
  #
  # Note these differences on MRI, where a is a Fixnum, b is a Bignum
  #
  # a.coerce b => [Float, Float]
  # b.coerce a => [Bignum, Bignum]
  #++
 
  def coerce(other)
    Ruby.primitive :numeric_coerce
    [Float(other), Float(self)]
  end
 
  ##
  # This method mimics the semantics of MRI's do_coerce function
  # in numeric.c. Note these differences between it and #coerce:
  #
  # 1.2.coerce("2") => [2.0, 1.2]
  # 1.2 + "2" => TypeError: String can't be coerced into Float
  #
  # See also Integer#coerce
 
  def math_coerce(other, error=:coerce_error)
    begin
      values = other.coerce(self)
    rescue
      send error, other
    end
    
    unless values.__kind_of__(Array) && values.length == 2
      raise TypeError, "coerce must return [x, y]"
    end
 
    return values[1], values[0]
  end
  private :math_coerce
  
  def coerce_error(other)
    raise TypeError, "#{other.class} can't be coerced into #{self.class}"
  end
  private :coerce_error
  
  def compare_error(other)
    raise ArgumentError, "comparison of #{self.class} with #{other.class} failed"
  end
  private :compare_error
 
  def step(limit, step=1, &block)
    raise ArgumentError, "step cannot be 0" if step == 0
    limit,step = step.coerce(limit)
    # FIXME: why is this not covered by the block parameter above?
    raise LocalJumpError, "no block given" unless block_given?
    idx,step = step.coerce(self)
    cmp = step > 0 ? :<= : :>=
    while (idx.send(cmp,limit))
      yield(idx)
      idx += step
    end
    return self
  rescue TypeError => e
    raise ArgumentError, e.message
  end
end