appmath 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/kepler_2d_app.rb +130 -0
- data/bin/linalg_app.rb +193 -0
- data/bin/rnum_app.rb +199 -0
- data/gpl-3.0.txt +674 -0
- data/lib/appmath_basics.rb +118 -0
- data/lib/cnum.rb +615 -0
- data/lib/float_ext.rb +223 -0
- data/lib/graph.rb +415 -0
- data/lib/interval.rb +282 -0
- data/lib/kepler_2d.rb +162 -0
- data/lib/linalg.rb +1309 -0
- data/lib/random.rb +88 -0
- data/lib/rnum.rb +1648 -0
- data/readme.txt +126 -0
- metadata +72 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
ruby
|
3
|
+
|
4
|
+
Ulrich Mutze, www.ulrichmutze.de
|
5
|
+
|
6
|
+
2008-12-09
|
7
|
+
|
8
|
+
Defines the module AppMath::Basics.
|
9
|
+
|
10
|
+
Requires files rnum and float_ext.
|
11
|
+
|
12
|
+
The intention is that a statement
|
13
|
+
require 'appmath_basics.rb'
|
14
|
+
allows us to use in the following a programming style in which the concept
|
15
|
+
of real numbers is handled in a flexibel manner so that switching from
|
16
|
+
standard type Float to arbitrary precision type R can be achieved
|
17
|
+
by a single statement of the type
|
18
|
+
R.prec = 0 ( for using Float)
|
19
|
+
or
|
20
|
+
R.prec = 100 ( for using R with 100 decimal places )
|
21
|
+
All modules and classes to be defined furtheron within the module
|
22
|
+
AppMath
|
23
|
+
will require appmath_basics.rb and will use real numbers in the manner
|
24
|
+
indicated above.
|
25
|
+
Copyright (C) 2008 Ulrich Mutze
|
26
|
+
|
27
|
+
This program is free software: you can redistribute it and/or modify
|
28
|
+
it under the terms of the GNU General Public License as published by
|
29
|
+
the Free Software Foundation, either version 3 of the License, or
|
30
|
+
(at your option) any later version.
|
31
|
+
|
32
|
+
This program is distributed in the hope that it will be useful,
|
33
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
34
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
35
|
+
GNU General Public License for more details.
|
36
|
+
|
37
|
+
You should have received a copy of the GNU General Public License
|
38
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
39
|
+
=end
|
40
|
+
|
41
|
+
require File.join(File.dirname(__FILE__), 'rnum')
|
42
|
+
require File.join(File.dirname(__FILE__), 'float_ext')
|
43
|
+
#require 'rnum'
|
44
|
+
#require 'float_ext'
|
45
|
+
|
46
|
+
# A Module which collects concepts of applied mathematics and of physics.
|
47
|
+
module AppMath
|
48
|
+
|
49
|
+
# A Module which collects simple utility functions.
|
50
|
+
module Basics
|
51
|
+
|
52
|
+
# Returns the larger of the two numbers a and b.
|
53
|
+
def Basics.sup(a, b)
|
54
|
+
a <= b ? b : a
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the smaller of the two numbers a and b.
|
58
|
+
def Basics.inf(a, b)
|
59
|
+
a < b ? a : b
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the sign of a as a real number.
|
63
|
+
def Basics.sign(a)
|
64
|
+
if a > R.c0
|
65
|
+
R.c1
|
66
|
+
elsif a < R.c0
|
67
|
+
-R.c1
|
68
|
+
else
|
69
|
+
R.c0
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns 'a with the sign of b'. Programming idiom frequently used in
|
74
|
+
# the 'Numerical Recipes in C' by Press et al.
|
75
|
+
def Basics.sign2(a, b)
|
76
|
+
b >= R.c0 ? a.abs : -a.abs
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the nearest number to x, which up to sign and power of 10
|
80
|
+
# is one of the numbers in the array c in the function
|
81
|
+
# body. For instance,
|
82
|
+
# c = [1,2,5,7.5,10]
|
83
|
+
# In a sense, here cutting is a more drastic version of rounding.
|
84
|
+
# It will be used in order to create reasonable axis subdivsion in
|
85
|
+
# graphical representation of data.
|
86
|
+
def Basics.cut(x)
|
87
|
+
fail "x is not a number" if x.nan?
|
88
|
+
fail "x is not finite" if x.infinite?
|
89
|
+
c = [R.c1,R.c2,R.c5,R.c(7.5),R.c10]
|
90
|
+
return R.c0 if x.zero?
|
91
|
+
s = Basics.sign(x)
|
92
|
+
y1 = x.abs
|
93
|
+
ylog = y1.log10
|
94
|
+
ylogInt = ylog.floor
|
95
|
+
yMantisse = ylog - ylogInt
|
96
|
+
y = R.c10 ** yMantisse
|
97
|
+
fail "Basics.cut(): !(1 <= y)" if !(R.c1 <= y)
|
98
|
+
fail "Basics.cut(): !(y < 10)" if !(y < R.c10)
|
99
|
+
i = 0
|
100
|
+
while y > c[i]
|
101
|
+
i += 1
|
102
|
+
end
|
103
|
+
cd = c.length
|
104
|
+
fail "unexpected failure in function Basics.cut" if i < 0 || i >= cd
|
105
|
+
yu = c[i] # yu is the smallest c[k] which is larger or equal to y
|
106
|
+
if i==0
|
107
|
+
yf = yu
|
108
|
+
else
|
109
|
+
fail "unexpected failure in function Basics.cut" if (i-1) < 0 || (i-1) >= cd
|
110
|
+
yl = c[i-1]
|
111
|
+
yf = yu-y <y -yl ? yu : yl # now yf is the c[k] which is nearest to y
|
112
|
+
end
|
113
|
+
return yf.ldexp(ylogInt) * s # sign and exponent are restored
|
114
|
+
end
|
115
|
+
|
116
|
+
end # Basics
|
117
|
+
|
118
|
+
end # module AppMath
|
data/lib/cnum.rb
ADDED
@@ -0,0 +1,615 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
ruby
|
3
|
+
|
4
|
+
Ulrich Mutze www.ulrichmutze.de
|
5
|
+
|
6
|
+
Started 2008-12-03 by modifying cpmc.h and cpmc.cpp
|
7
|
+
|
8
|
+
Defining a class C of complex numbers.
|
9
|
+
|
10
|
+
Defines the class AppMath::C.
|
11
|
+
|
12
|
+
Requires file appmath_basics.
|
13
|
+
|
14
|
+
Copyright (C) 2008 Ulrich Mutze
|
15
|
+
|
16
|
+
This program is free software: you can redistribute it and/or modify
|
17
|
+
it under the terms of the GNU General Public License as published by
|
18
|
+
the Free Software Foundation, either version 3 of the License, or
|
19
|
+
(at your option) any later version.
|
20
|
+
|
21
|
+
This program is distributed in the hope that it will be useful,
|
22
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
24
|
+
GNU General Public License for more details.
|
25
|
+
|
26
|
+
You should have received a copy of the GNU General Public License
|
27
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
28
|
+
=end
|
29
|
+
|
30
|
+
require File.join(File.dirname(__FILE__), 'appmath_basics')
|
31
|
+
#require 'appmath_basics'
|
32
|
+
|
33
|
+
module AppMath
|
34
|
+
|
35
|
+
# Class of arbitrary precision complex numbers. The underlying real numbers may be Float
|
36
|
+
# or R.
|
37
|
+
class C < Numeric
|
38
|
+
|
39
|
+
attr_reader :re, :im
|
40
|
+
|
41
|
+
def initialize(*arg)
|
42
|
+
n = arg.size
|
43
|
+
case n
|
44
|
+
when 0
|
45
|
+
@re = R.c0
|
46
|
+
@im = R.c0
|
47
|
+
when 1
|
48
|
+
a0 = arg[0]
|
49
|
+
if a0.integer? || a0.real?
|
50
|
+
@re = R.c a0
|
51
|
+
@im = R.c0
|
52
|
+
elsif a0.complex?
|
53
|
+
@re = R.c a0.re
|
54
|
+
@im = R.c a0.im
|
55
|
+
else
|
56
|
+
fail "can't construct a C from this argument"
|
57
|
+
end
|
58
|
+
when 2
|
59
|
+
a0 = R.c arg[0]; a1 = R.c arg[1]
|
60
|
+
@re = a0
|
61
|
+
@im = a1
|
62
|
+
else
|
63
|
+
fail "can't construct a C from more than two arguments"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def clone; C.new(@re,@im); end
|
68
|
+
|
69
|
+
# The constant 0.
|
70
|
+
def C.zero
|
71
|
+
C.new
|
72
|
+
end
|
73
|
+
|
74
|
+
# The constant 1.
|
75
|
+
def C.one
|
76
|
+
C.new(R.c1,R.c0)
|
77
|
+
end
|
78
|
+
# The constant i
|
79
|
+
def C.i
|
80
|
+
C.new(R.c0,R.c1)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Random value (sine-floor random generator).
|
84
|
+
#
|
85
|
+
# Chaotic function from the integers into the
|
86
|
+
# subset [0,1] x [0,1] of C
|
87
|
+
|
88
|
+
def C.ran(anInteger)
|
89
|
+
ai = anInteger.to_i * 2
|
90
|
+
x1 = R.ran(ai)
|
91
|
+
x2 = R.ran(ai + 1)
|
92
|
+
C.new(x1,x2)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Test object.
|
96
|
+
#
|
97
|
+
# Needed for automatic tests of arithmetic relations. Intended
|
98
|
+
# to give numbers which rapidly change sign and order of
|
99
|
+
# magnitude when the argument grows regularly e.g.
|
100
|
+
# as in 1,2,3,... . However, suitibility as a random generator is
|
101
|
+
# not the focus. If the second argument is 'true', the result
|
102
|
+
# is multplied by a number << 1 in order to prevent the result
|
103
|
+
# from overloading the exponential function.
|
104
|
+
|
105
|
+
def C.tob(anInteger, small = false)
|
106
|
+
ai = anInteger.to_i * 2
|
107
|
+
x1 = R.tob(ai,small)
|
108
|
+
x2 = R.tob(ai + 1,small)
|
109
|
+
C.new(x1,x2)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Unary minus operator. It returns the C-object -self.
|
113
|
+
def -@; C.new(-@re, -@im); end
|
114
|
+
|
115
|
+
# Unary plus operator. It returns the C-object self.
|
116
|
+
def +@; self; end
|
117
|
+
|
118
|
+
# (Complex) conjugation, no effect on real numbers.
|
119
|
+
# Supports the unified treatment of real and complex numbers.
|
120
|
+
def conj; C.new(@re, -@im); end
|
121
|
+
|
122
|
+
# Returns self times i.
|
123
|
+
def ti; self * C.i; end
|
124
|
+
|
125
|
+
# Returns self divided by i.
|
126
|
+
def dbi; self * C.new(0,-1); end
|
127
|
+
|
128
|
+
# Returns the absolute value of self.
|
129
|
+
def abs; @re.hypot(@im); end
|
130
|
+
|
131
|
+
# Returns the absolute value squared of self.
|
132
|
+
def abs2; @re * @re + @im * @im; end
|
133
|
+
|
134
|
+
# Returns the argument (i.e. the polar angle) of self.
|
135
|
+
def arg; @re.arg(@im); end
|
136
|
+
|
137
|
+
# Redefining coerce from Numeric.
|
138
|
+
# This allows writing 1 + C.new(137) instead of C.new(137) + 1
|
139
|
+
# or C.new(137) + R.c1.
|
140
|
+
#-- Notice that the order in the resulting array is essential for
|
141
|
+
# correct functionality.
|
142
|
+
def coerce(a)
|
143
|
+
[ C.new(a), self]
|
144
|
+
end
|
145
|
+
|
146
|
+
# The order relation is here lexicographic ordering based on the
|
147
|
+
# agreement that re is the 'first letter' and im the 'second letter'
|
148
|
+
# of 'the word'. Needed only for book-keeping purposes.
|
149
|
+
def <=> (a)
|
150
|
+
cr = @re <=> a.re
|
151
|
+
return cr unless cr.zero?
|
152
|
+
ci = @im <=> a.im
|
153
|
+
return ci unless ci.zero?
|
154
|
+
return 0
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns 'true' if self equals zero.
|
158
|
+
def zero?; @re.zero? && @im.zero?; end
|
159
|
+
|
160
|
+
# Returns 'true' if self is 'not a number' (NaN).
|
161
|
+
def nan?; @re.nan? || @im.nan?; end
|
162
|
+
|
163
|
+
# Returns 'true' if the real art or the iaginary part of self is
|
164
|
+
# infinite.
|
165
|
+
def infinite?; @re.infinite? || @im.infinite?; end
|
166
|
+
|
167
|
+
# Since R is not Fixnum or Bignum we return 'false'. In scientific
|
168
|
+
# computation there may be the need to use various types of
|
169
|
+
# 'real number types' but there should always a clear-cut distinction
|
170
|
+
# between integer types and real types.
|
171
|
+
def integer?; false; end
|
172
|
+
|
173
|
+
# Supports the unified treatment of real and complex numbers.
|
174
|
+
def real?; false; end
|
175
|
+
|
176
|
+
# Supports the unified treatment of real and complex numbers.
|
177
|
+
def complex?; true; end
|
178
|
+
|
179
|
+
# Returns the C-object self + a.
|
180
|
+
def +(a)
|
181
|
+
if a.integer? || a.real?
|
182
|
+
b = R.c a
|
183
|
+
C.new(@re + b, @im)
|
184
|
+
elsif a.complex?
|
185
|
+
C.new(@re + a.re, @im + a.im)
|
186
|
+
else
|
187
|
+
fail "cannot add this argument to a complex number"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns the C-object self - a.
|
192
|
+
def -(a)
|
193
|
+
if a.integer? || a.real?
|
194
|
+
b = R.c a
|
195
|
+
C.new(@re - b, @im)
|
196
|
+
elsif a.complex?
|
197
|
+
C.new(@re - a.re, @im - a.im)
|
198
|
+
else
|
199
|
+
fail "cannot subtract this argument from a complex number"
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns the C-object self * a.
|
205
|
+
def *(a)
|
206
|
+
if a.integer? || a.real?
|
207
|
+
b = R.c a
|
208
|
+
C.new(@re * b, @im * b)
|
209
|
+
elsif a.complex?
|
210
|
+
C.new(@re * a.re - @im * a.im , @re * a.im + @im * a.re )
|
211
|
+
else
|
212
|
+
fail "cannot multiply a complex number with this argument"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns the C-object self / a.
|
217
|
+
def /(a)
|
218
|
+
if a.integer? || a.real?
|
219
|
+
b = R.c a
|
220
|
+
C.new(@re / b, @im / b)
|
221
|
+
elsif a.complex?
|
222
|
+
r2 = a.abs2
|
223
|
+
C.new((@re * a.re + @im * a.im)/r2 , (@im * a.re - @re * a.im)/r2 )
|
224
|
+
else
|
225
|
+
fail "cannot divide a complex number by this argument"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Exponential function.
|
230
|
+
def exp; C.new(@im.cos, @im.sin) * @re.exp; end
|
231
|
+
|
232
|
+
# Exponential function of the argument multiplied by C.i
|
233
|
+
def expi; (self * C.i).exp; end
|
234
|
+
|
235
|
+
|
236
|
+
# Natural logarithm.
|
237
|
+
def log; C.new(abs.log,arg); end
|
238
|
+
|
239
|
+
# Returns the a-th power of self. A may be integer, real, or
|
240
|
+
# complex. The result is always complex.
|
241
|
+
def **(a)
|
242
|
+
return C.nan if nan?
|
243
|
+
if a.integer?
|
244
|
+
if a.zero?
|
245
|
+
C.one
|
246
|
+
elsif a == 1
|
247
|
+
self
|
248
|
+
elsif a == -1
|
249
|
+
inv
|
250
|
+
else
|
251
|
+
b = a.abs
|
252
|
+
res = self
|
253
|
+
for i in 1...b
|
254
|
+
res *= self
|
255
|
+
end
|
256
|
+
if a < 0
|
257
|
+
res = res.inv
|
258
|
+
end
|
259
|
+
res
|
260
|
+
end
|
261
|
+
elsif a.real?
|
262
|
+
b = C.new(a)
|
263
|
+
(log * b).exp
|
264
|
+
elsif a.complex?
|
265
|
+
(log * a).exp
|
266
|
+
else
|
267
|
+
fail "Argument not acceptable as an exponent"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Returns the zero-element which belongs to the same class than self
|
272
|
+
def to_0; C.zero; end
|
273
|
+
|
274
|
+
# Returns the unit-element which belongs to the same class than self
|
275
|
+
def to_1; C.one; end
|
276
|
+
|
277
|
+
# Returns the inverse 1/self.
|
278
|
+
def inv
|
279
|
+
C.one / self
|
280
|
+
end
|
281
|
+
|
282
|
+
# Returns 'true' iff self == C(0,0)
|
283
|
+
def zero?; @re.zero? && @im.zero?; end
|
284
|
+
|
285
|
+
# The pseudo_inverse of zero is zero, and equal to the inverse for
|
286
|
+
# all other arguments.
|
287
|
+
def pseudo_inv
|
288
|
+
zero? ? C.zero : C.one / self
|
289
|
+
end
|
290
|
+
|
291
|
+
# For the return value res we have res.int? true and (self - res).abs <= 0.5
|
292
|
+
def round(n)
|
293
|
+
u = @re.round(n)
|
294
|
+
v = @im.round(n)
|
295
|
+
C.new(u,v)
|
296
|
+
end
|
297
|
+
|
298
|
+
# Returns the square root of self.
|
299
|
+
def sqrt
|
300
|
+
self ** R.i2
|
301
|
+
end
|
302
|
+
|
303
|
+
# Returns a kind of relative distance between self and aR.
|
304
|
+
# The return value varies from 0 to 1, where 1 means maximum dissimilarity
|
305
|
+
# of the arguments.
|
306
|
+
# Such a function is needed for testing the validity of arithmetic laws,
|
307
|
+
# which, due to numerical noise, should not be expected to be fulfilled
|
308
|
+
# exactly.
|
309
|
+
def dis(aC)
|
310
|
+
a = abs
|
311
|
+
b = aC.abs
|
312
|
+
d = (self - aC).abs
|
313
|
+
s = a + b
|
314
|
+
return R.c0 if s.zero?
|
315
|
+
d1 = d/s
|
316
|
+
Basics.inf(d,d1)
|
317
|
+
end
|
318
|
+
|
319
|
+
# Conversion to String.
|
320
|
+
def to_s; "C(#{@re}, #{@im})"; end
|
321
|
+
|
322
|
+
# Printing the value together with a label
|
323
|
+
def prn(name)
|
324
|
+
puts "#{name} = " + to_s
|
325
|
+
end
|
326
|
+
#=begin
|
327
|
+
|
328
|
+
# Sine.
|
329
|
+
def sin
|
330
|
+
(expi - (-self).expi) * C.new(0,-R.i2)
|
331
|
+
end
|
332
|
+
|
333
|
+
# Cosine.
|
334
|
+
def cos
|
335
|
+
(expi + (-self).expi) * R.i2
|
336
|
+
end
|
337
|
+
|
338
|
+
# Tangent.
|
339
|
+
def tan
|
340
|
+
sin / cos
|
341
|
+
end
|
342
|
+
|
343
|
+
# Cotangent.
|
344
|
+
def cot
|
345
|
+
cos / sin
|
346
|
+
end
|
347
|
+
|
348
|
+
# Hyperbolic sine.
|
349
|
+
def sinh; (exp - (-self).exp) * R.i2; end
|
350
|
+
|
351
|
+
# Hyperbolic cosine.
|
352
|
+
def cosh; (exp + (-self).exp) * R.i2; end
|
353
|
+
|
354
|
+
# Hyperbolic tangent.
|
355
|
+
def tanh
|
356
|
+
s = exp - (-self).exp
|
357
|
+
c = exp + (-self).exp
|
358
|
+
s/c
|
359
|
+
end
|
360
|
+
|
361
|
+
# Hyperbolic cotangent.
|
362
|
+
def coth
|
363
|
+
s = exp - (-self).exp
|
364
|
+
c = exp + (-self).exp
|
365
|
+
c/s
|
366
|
+
end
|
367
|
+
|
368
|
+
# Inverse hyperbolic sine.
|
369
|
+
def asinh
|
370
|
+
((self * self + C.one).sqrt + self).log
|
371
|
+
end
|
372
|
+
|
373
|
+
# Inverse hyperbolic cosine.
|
374
|
+
def acosh
|
375
|
+
((self * self - C.one).sqrt + self).log
|
376
|
+
end
|
377
|
+
|
378
|
+
# Inverse hyperbolic tangent.
|
379
|
+
def atanh
|
380
|
+
((C.one + self)/(C.one - self)).log * R.i2
|
381
|
+
end
|
382
|
+
|
383
|
+
# Inverse hyperbolic cotangent.
|
384
|
+
def acoth
|
385
|
+
((self + C.one)/(self - C.one)).log * R.i2
|
386
|
+
end
|
387
|
+
|
388
|
+
# Inverse sine.
|
389
|
+
def asin
|
390
|
+
ti.asinh.dbi
|
391
|
+
end
|
392
|
+
|
393
|
+
# Inverse cosine.
|
394
|
+
def acos
|
395
|
+
acosh.dbi
|
396
|
+
end
|
397
|
+
|
398
|
+
# Inverse tangent.
|
399
|
+
def atan
|
400
|
+
ti.atanh.dbi
|
401
|
+
end
|
402
|
+
|
403
|
+
# Inverse cotangent.
|
404
|
+
def acot
|
405
|
+
ti.acoth.ti
|
406
|
+
end
|
407
|
+
|
408
|
+
# Consistency test for class C
|
409
|
+
# This is intended to keep the class consistent despite of modifications.
|
410
|
+
# The first argument influences the numbers which are selected for the
|
411
|
+
# test. Returned is a sum of numbers each of which should be numerical
|
412
|
+
# noise and so the result has to be << 1 if the test is to indicate
|
413
|
+
# success.
|
414
|
+
# For instance, on my system
|
415
|
+
#
|
416
|
+
# Doing C.test(n = 137, verbose = false) for R.dig = 100:
|
417
|
+
# *************************************************
|
418
|
+
# class of s is AppMath::R
|
419
|
+
# class of s is AppMath::R .
|
420
|
+
# The error sum s is 0.95701879151814897746312007872622225589589551941
|
421
|
+
# 73186692168823486932509515793972625242699350133964052E-98 .
|
422
|
+
# It should be close to 0.
|
423
|
+
# Computation time was 1.062 seconds.
|
424
|
+
|
425
|
+
def C.test(n0, verbose = false )
|
426
|
+
puts "Doing C.test(n = #{n0}, verbose = #{verbose})" +
|
427
|
+
" for R.dig = #{R.dig}:"
|
428
|
+
puts "*************************************************"
|
429
|
+
t1 = Time.now
|
430
|
+
small = true # otherwise not all inverse function tests work well
|
431
|
+
s = R.c0
|
432
|
+
puts "class of s is " + s.class.to_s
|
433
|
+
i = n0
|
434
|
+
a = C.tob(i,small)
|
435
|
+
i += 1
|
436
|
+
b = C.tob(i,small)
|
437
|
+
i += 1
|
438
|
+
c = C.tob(i,small)
|
439
|
+
i += 1
|
440
|
+
|
441
|
+
if verbose
|
442
|
+
a.prn("a")
|
443
|
+
b.prn("b")
|
444
|
+
c.prn("c")
|
445
|
+
end
|
446
|
+
|
447
|
+
r = 2 + a
|
448
|
+
l = a + 2
|
449
|
+
ds = r.dis(l)
|
450
|
+
puts "coerce 2 + a: ds = " + ds.to_s if verbose
|
451
|
+
s += ds
|
452
|
+
|
453
|
+
r = a + 1.234
|
454
|
+
l = a + R.c(1.234)
|
455
|
+
ds = r.dis(l)
|
456
|
+
puts "coerce a + float: ds = " + ds.to_s if verbose
|
457
|
+
s += ds
|
458
|
+
|
459
|
+
r = (a + b) * c
|
460
|
+
l = a * c + b * c
|
461
|
+
|
462
|
+
ds = r.dis(l)
|
463
|
+
puts "Distributive law for +: ds = " + ds.to_s if verbose
|
464
|
+
s += ds
|
465
|
+
|
466
|
+
r = (a - b) * c
|
467
|
+
l = a * c - b * c
|
468
|
+
ds = r.dis(l)
|
469
|
+
puts "Distributive law for -: ds = " + ds.to_s if verbose
|
470
|
+
s += ds
|
471
|
+
|
472
|
+
r = (a * b) * c
|
473
|
+
l = b * (c * a)
|
474
|
+
ds = r.dis(l)
|
475
|
+
puts "Multiplication: ds = " + ds.to_s if verbose
|
476
|
+
s += ds
|
477
|
+
|
478
|
+
r = (a * b) / c
|
479
|
+
l = (a / c) * b
|
480
|
+
ds = r.dis(l)
|
481
|
+
puts "Division: ds = " + ds.to_s if verbose
|
482
|
+
s += ds
|
483
|
+
|
484
|
+
r = C.one
|
485
|
+
l = a * a.inv
|
486
|
+
ds = r.dis(l)
|
487
|
+
puts "inv: ds = " + ds.to_s if verbose
|
488
|
+
s += ds
|
489
|
+
|
490
|
+
r = 1/a
|
491
|
+
l = a.inv
|
492
|
+
ds = r.dis(l)
|
493
|
+
puts "inv and 1/x: ds = " + ds.to_s if verbose
|
494
|
+
s += ds
|
495
|
+
|
496
|
+
r = b
|
497
|
+
l = -(-b)
|
498
|
+
ds = r.dis(l)
|
499
|
+
puts "Unary minus is idempotent: ds = " + ds.to_s if verbose
|
500
|
+
s += ds
|
501
|
+
x = -a
|
502
|
+
y = x + a
|
503
|
+
r = y
|
504
|
+
l = C.zero
|
505
|
+
ds = r.dis(l)
|
506
|
+
puts "Unary -: ds = " + ds.to_s if verbose
|
507
|
+
s += ds
|
508
|
+
|
509
|
+
l = a
|
510
|
+
x = a.sqrt
|
511
|
+
r = x * x
|
512
|
+
s = r.dis(l)
|
513
|
+
puts "square root: ds = " + ds.to_s if verbose
|
514
|
+
s += ds
|
515
|
+
|
516
|
+
n = 11
|
517
|
+
l = a ** n
|
518
|
+
r = a ** C.new(n)
|
519
|
+
ds = r.dis(l)
|
520
|
+
puts "power with integer exponent: ds = " + ds.to_s if verbose
|
521
|
+
s += ds
|
522
|
+
|
523
|
+
n = -7
|
524
|
+
l = a ** n
|
525
|
+
r = a ** C.new(n)
|
526
|
+
ds = r.dis(l)
|
527
|
+
puts "power with negative integer exponent: ds = " + ds.to_s if verbose
|
528
|
+
s += ds
|
529
|
+
|
530
|
+
l = -C.one
|
531
|
+
r = (C.i * R.pi).exp
|
532
|
+
ds = r.dis(l)
|
533
|
+
puts "Euler's relation: ds = " + ds.to_s if verbose
|
534
|
+
s += ds
|
535
|
+
|
536
|
+
l = a.sin * b.cos + a.cos * b.sin
|
537
|
+
r = (a + b).sin
|
538
|
+
ds = r.dis(l)
|
539
|
+
puts "Addition theorem for sin: ds = " + ds.to_s if verbose
|
540
|
+
s += ds
|
541
|
+
|
542
|
+
l = a.exp * b.exp
|
543
|
+
r = (a + b).exp
|
544
|
+
ds = r.dis(l)
|
545
|
+
puts "Addition theorem for exp: ds = " + ds.to_s if verbose
|
546
|
+
s += ds
|
547
|
+
|
548
|
+
l = b.exp
|
549
|
+
r = l.log.exp
|
550
|
+
ds = r.dis(l)
|
551
|
+
puts "exp and log: ds = " + ds.to_s if verbose
|
552
|
+
s += ds
|
553
|
+
|
554
|
+
l = c.sin
|
555
|
+
r = l.asin.sin
|
556
|
+
ds = r.dis(l)
|
557
|
+
puts "sin and asin: ds = " + ds.to_s if verbose
|
558
|
+
s += ds
|
559
|
+
|
560
|
+
l = b.cos
|
561
|
+
r = l.acos.cos
|
562
|
+
ds = r.dis(l)
|
563
|
+
puts "cos and acos: ds = " + ds.to_s if verbose
|
564
|
+
s += ds
|
565
|
+
|
566
|
+
l = a.tan
|
567
|
+
r = l.atan.tan
|
568
|
+
ds = r.dis(l)
|
569
|
+
puts "tan and atan: ds = " + ds.to_s if verbose
|
570
|
+
s += ds
|
571
|
+
|
572
|
+
l = a.cot
|
573
|
+
r = l.acot.cot
|
574
|
+
ds = r.dis(l)
|
575
|
+
puts "cot and acot: ds = " + ds.to_s if verbose
|
576
|
+
s += ds
|
577
|
+
|
578
|
+
l = c.sinh
|
579
|
+
r = l.asinh.sinh
|
580
|
+
ds = r.dis(l)
|
581
|
+
puts "sinh and asinh: ds = " + ds.to_s if verbose
|
582
|
+
s += ds
|
583
|
+
|
584
|
+
l = a.cosh
|
585
|
+
r = l.acosh.cosh
|
586
|
+
ds = r.dis(l)
|
587
|
+
puts "cosh and acosh: ds = " + ds.to_s if verbose
|
588
|
+
s += ds
|
589
|
+
|
590
|
+
l = b.tanh
|
591
|
+
r = l.atanh.tanh
|
592
|
+
ds = r.dis(l)
|
593
|
+
puts "tanh and atanh: ds = " + ds.to_s if verbose
|
594
|
+
s += ds
|
595
|
+
|
596
|
+
l = a.coth
|
597
|
+
r = l.acoth.coth
|
598
|
+
ds = r.dis(l)
|
599
|
+
puts "coth and acoth: ds = " + ds.to_s if verbose
|
600
|
+
s += ds
|
601
|
+
|
602
|
+
t2 = Time.now
|
603
|
+
puts "class of s is " + s.class.to_s + " ."
|
604
|
+
puts "The error sum s is " + s.to_s + " ."
|
605
|
+
puts "It should be close to 0."
|
606
|
+
puts "Computation time was #{t2-t1} seconds."
|
607
|
+
s
|
608
|
+
end
|
609
|
+
|
610
|
+
protected :coerce
|
611
|
+
|
612
|
+
end # class C
|
613
|
+
|
614
|
+
end # module AppMath
|
615
|
+
|