-
Notifications
You must be signed in to change notification settings - Fork 606
/
math.rb
250 lines (199 loc) · 5.64 KB
/
math.rb
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
module Math
def atan2(y, x)
y = Rubinius::Type.coerce_to_float y
x = Rubinius::Type.coerce_to_float x
FFI::Platform::Math.atan2 y, x
end
module_function :atan2
def cos(x)
FFI::Platform::Math.cos Rubinius::Type.coerce_to_float(x)
end
module_function :cos
def sin(x)
FFI::Platform::Math.sin Rubinius::Type.coerce_to_float(x)
end
module_function :sin
def tan(x)
FFI::Platform::Math.tan Rubinius::Type.coerce_to_float(x)
end
module_function :tan
def atan(x)
FFI::Platform::Math.atan Rubinius::Type.coerce_to_float(x)
end
module_function :atan
def cosh(x)
FFI::Platform::Math.cosh Rubinius::Type.coerce_to_float(x)
end
module_function :cosh
def sinh(x)
FFI::Platform::Math.sinh Rubinius::Type.coerce_to_float(x)
end
module_function :sinh
def tanh(x)
FFI::Platform::Math.tanh Rubinius::Type.coerce_to_float(x)
end
module_function :tanh
def asinh(x)
FFI::Platform::Math.asinh Rubinius::Type.coerce_to_float(x)
end
module_function :asinh
def atanh(x)
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'atanh' unless x.abs <= 1.0
FFI::Platform::POSIX.errno = 0
ret = FFI::Platform::Math.atanh x
begin
Errno.handle
# Linux sets errno to ERANGE, but it should be EDOM
rescue Errno::ERANGE
raise Errno::EDOM
end
ret
end
module_function :atanh
def exp(x)
FFI::Platform::Math.exp Rubinius::Type.coerce_to_float(x)
end
module_function :exp
def frexp(x)
x = Rubinius::Type.coerce_to_float(x)
FFI::MemoryPointer.new :int do |exp|
result = FFI::Platform::Math.frexp x, exp
[result, exp.read_int]
end
end
module_function :frexp
def ldexp(x, n)
if n.kind_of? Float and n.nan?
raise RangeError, "NaN cannot be converted to an Integer"
end
n = Rubinius::Type.coerce_to(n, Integer, :to_int)
FFI::Platform::Math.ldexp Rubinius::Type.coerce_to_float(x), n
end
module_function :ldexp
# Rubinius-specific, used in Marshal
def modf(x)
FFI::MemoryPointer.new :double do |integral|
fractional = FFI::Platform::Math.modf x, integral
[fractional, integral.read_double]
end
end
module_function :modf
def hypot(x, y)
x = Rubinius::Type.coerce_to_float x
y = Rubinius::Type.coerce_to_float y
FFI::Platform::Math.hypot x, y
end
module_function :hypot
def erf(x)
FFI::Platform::Math.erf Rubinius::Type.coerce_to_float(x)
end
module_function :erf
def erfc(x)
FFI::Platform::Math.erfc Rubinius::Type.coerce_to_float(x)
end
module_function :erfc
def asin(x)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'asin' unless x.abs <= 1.0
FFI::Platform::Math.asin x
end
module_function :asin
def acos(x)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'acos' unless x.abs <= 1.0
FFI::Platform::POSIX.errno = 0
ret = FFI::Platform::Math.acos x
Errno.handle
ret
end
module_function :acos
def acosh(x)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'acosh' unless x >= 1.0
FFI::Platform::Math.acosh x
end
module_function :acosh
def cbrt(x)
x = Rubinius::Type.coerce_to_float x
FFI::Platform::Math.cbrt x
end
module_function :cbrt
def gamma(x)
x = Rubinius::Type.coerce_to_float x
# if x is negative zero, return -infinity
return -Float::INFINITY if (1 / x) == -Float::INFINITY
return Float::INFINITY if x == 0.0
return Float::NAN if x.nan?
if sign = x.infinite?
raise DomainError, "gamma" if sign == -1
return Float::INFINITY
end
FFI::MemoryPointer.new :double do |integral|
fractional = FFI::Platform::Math.modf x, integral
int = integral.read_double.to_i
if fractional == 0.0
raise DomainError, "gamma" if int < 0
return FactorialTable[int - 1] if int <= FactorialTable.size
end
end
FFI::Platform::Math.tgamma x
end
module_function :gamma
def lgamma(x)
x = Rubinius::Type.coerce_to_float x
if sign = x.infinite?
raise DomainError, "lgamma" if sign == -1
return [Float::INFINITY, 1]
end
FFI::MemoryPointer.new :int do |sign|
sign.write_int 1
result = FFI::Platform::Math.lgamma_r x, sign
[result, sign.read_int]
end
end
module_function :lgamma
def log(x, base=undefined)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float x
raise DomainError, 'log' unless x >= 0.0
return -Float::INFINITY if x == 0.0
y = FFI::Platform::Math.log x
unless undefined.equal? base
base = Rubinius::Type.coerce_to_float base
y /= log(base)
end
y
end
module_function :log
def log2(x)
return Float::NAN if x.kind_of? Float and x.nan?
if x.kind_of? Bignum and x >= 0 and Float::MAX_EXP <= (bits = x.bit_length)
bits -= Float::MANT_DIG
x >>= bits
else
bits = 0
end
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'log2' unless x >= 0.0
FFI::Platform::Math.log2(x) + bits
end
module_function :log2
def log10(x)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'log10' unless x >= 0.0
FFI::Platform::Math.log10 x
end
module_function :log10
def sqrt(x)
return Float::NAN if x.kind_of? Float and x.nan?
x = Rubinius::Type.coerce_to_float(x)
raise DomainError, 'sqrt' unless x >= 0.0
FFI::Platform::Math.sqrt x
end
module_function :sqrt
end