Class AppMath::C
In: cnum.rb
Parent: Numeric

Class of complex numbers

Methods

*   **   +   +@   -   -@   /   <=>   abs   abs2   acos   acosh   acot   acoth   arg   asin   asinh   atan   atanh   clone   coerce   complex?   conj   cos   cosh   cot   coth   dbi   dis   exp   expi   i   infinite?   integer?   inv   log   nan?   new   one   prn   pseudo_inv   ran   real?   round   sin   sinh   sqrt   tan   tanh   test   ti   to_0   to_1   to_s   tob   zero   zero?   zero?  

Attributes

im  [R] 
re  [R] 

Public Class methods

The constant i

[Source]

    # File cnum.rb, line 61
61:   def C.i
62:     C.new(R.c0,R.c1)
63:   end

[Source]

    # File cnum.rb, line 23
23:   def initialize(*arg)
24:     n = arg.size
25:     case n
26:     when 0
27:       @re = R.c0
28:       @im = R.c0
29:     when 1
30:       a0 = arg[0]
31:       if a0.integer? || a0.real?
32:         @re = R.c a0
33:         @im = R.c0
34:       elsif a0.complex? 
35:         @re = R.c a0.re
36:         @im = R.c a0.im
37:       else
38:         fail "can't construct a C from this argument"
39:       end
40:     when 2
41:       a0 = R.c arg[0]; a1 = R.c arg[1]
42:         @re = a0
43:         @im = a1
44:     else
45:        fail "can't construct a C from more than two arguments"
46:     end
47:   end

The constant 1.

[Source]

    # File cnum.rb, line 57
57:   def C.one
58:     C.new(R.c1,R.c0)
59:   end

Random value (sine-floor random generator).

Chaotic function from the integers into the subset [0,1] x [0,1] of C

[Source]

    # File cnum.rb, line 70
70:   def C.ran(anInteger)
71:     ai = anInteger.to_i * 2
72:     x1 = R.ran(ai)
73:     x2 = R.ran(ai + 1)
74:     C.new(x1,x2)
75:   end

Consistency test for class C This is intended to keep the class consistent despite of modifications. The first argument influences the numbers which are selected for the test. Returned is a sum of numbers each of which should be numerical noise and so the result has to be << 1 if the test is to indicate success. For instance, on my system

  Doing C.test(n = 137, verbose = false) for R.dig = 100:
  *************************************************
  class of s is AppMath::R
  class of s is AppMath::R .
  The error sum s is 0.95701879151814897746312007872622225589589551941
  73186692168823486932509515793972625242699350133964052E-98 .
  It should be close to 0.
  Computation time was 1.062 seconds.

[Source]

     # File cnum.rb, line 407
407:   def C.test(n0, verbose = false )
408:     puts "Doing C.test(n = #{n0}, verbose = #{verbose})" +
409:       " for R.dig = #{R.dig}:"
410:     puts "*************************************************"
411:     t1 = Time.now
412:     small = true # otherwise not all inverse function tests work well 

413:     s = R.c0
414:     puts "class of s is " + s.class.to_s
415:     i = n0
416:     a = C.tob(i,small) 
417:     i += 1
418:     b = C.tob(i,small)
419:     i += 1
420:     c = C.tob(i,small)
421:     i += 1
422:     
423:     if verbose
424:       a.prn("a")
425:       b.prn("b")
426:       c.prn("c")
427:     end
428:   
429:     r = 2 + a
430:     l = a + 2
431:     ds = r.dis(l)
432:     puts "coerce 2 + a: ds = " + ds.to_s if verbose
433:     s += ds
434:     
435:     r =  a + 1.234
436:     l =  a + R.c(1.234)
437:     ds = r.dis(l)
438:     puts "coerce a + float: ds = " + ds.to_s if verbose
439:     s += ds
440:   
441:     r = (a + b) * c
442:     l = a * c + b * c
443:   
444:     ds = r.dis(l)
445:     puts "Distributive law for +: ds = " + ds.to_s if verbose
446:     s += ds
447:     
448:     r = (a - b) * c
449:     l = a * c - b * c
450:     ds = r.dis(l)
451:     puts "Distributive law for -: ds = " + ds.to_s if verbose
452:     s += ds
453:     
454:     r = (a * b) * c
455:     l = b * (c * a)
456:     ds = r.dis(l)
457:     puts "Multiplication: ds = " + ds.to_s if verbose
458:     s += ds
459:   
460:     r = (a * b) / c
461:     l = (a / c) * b
462:     ds = r.dis(l)
463:     puts "Division: ds = " + ds.to_s if verbose
464:     s += ds
465:     
466:     r = C.one
467:     l = a * a.inv
468:     ds = r.dis(l)
469:     puts "inv: ds = " + ds.to_s if verbose
470:     s += ds
471:  
472:     r = 1/a
473:     l = a.inv
474:     ds = r.dis(l)
475:     puts "inv and 1/x: ds = " + ds.to_s if verbose
476:     s += ds
477:   
478:     r = b
479:     l = -(-b)
480:     ds = r.dis(l)
481:     puts "Unary minus is idempotent: ds = " + ds.to_s if verbose
482:     s += ds
483:     x = -a
484:     y = x + a
485:     r = y
486:     l = C.zero
487:     ds = r.dis(l)
488:     puts "Unary -: ds = " + ds.to_s if verbose
489:     s += ds
490:     
491:     l = a
492:     x = a.sqrt
493:     r = x * x
494:     s = r.dis(l)
495:     puts "square root: ds = " + ds.to_s if verbose
496:     s += ds
497:     
498:     n = 11
499:     l = a ** n
500:     r = a ** C.new(n)
501:     ds = r.dis(l)
502:     puts "power with integer exponent: ds = " + ds.to_s if verbose
503:     s += ds
504:     
505:     n = -7
506:     l = a ** n
507:     r = a ** C.new(n)
508:     ds = r.dis(l)
509:     puts "power with negative integer exponent: ds = " + ds.to_s if verbose
510:     s += ds
511:     
512:     l = -C.one
513:     r = (C.i * R.pi).exp
514:     ds = r.dis(l)
515:     puts "Euler's relation: ds = " + ds.to_s if verbose
516:     s += ds
517:   
518:     l = a.sin * b.cos + a.cos * b.sin
519:     r = (a + b).sin
520:     ds = r.dis(l)
521:     puts "Addition theorem for sin: ds = " + ds.to_s if verbose
522:     s += ds
523:     
524:     l = a.exp * b.exp
525:     r = (a + b).exp
526:     ds = r.dis(l)
527:     puts "Addition theorem for exp: ds = " + ds.to_s if verbose
528:     s += ds
529: 
530:     l = b.exp
531:     r = l.log.exp
532:     ds = r.dis(l)
533:     puts "exp and log: ds = " + ds.to_s if verbose
534:     s += ds
535:     
536:     l = c.sin
537:     r = l.asin.sin
538:     ds = r.dis(l)
539:     puts "sin and asin: ds = " + ds.to_s if verbose
540:     s += ds
541:    
542:     l = b.cos
543:     r = l.acos.cos
544:     ds = r.dis(l)
545:     puts "cos and acos: ds = " + ds.to_s if verbose
546:     s += ds
547:     
548:     l = a.tan
549:     r = l.atan.tan
550:     ds = r.dis(l)
551:     puts "tan and atan: ds = " + ds.to_s if verbose
552:     s += ds
553: 
554:     l = a.cot
555:     r = l.acot.cot
556:     ds = r.dis(l)
557:     puts "cot and acot: ds = " + ds.to_s if verbose
558:     s += ds
559:     
560:     l = c.sinh
561:     r = l.asinh.sinh
562:     ds = r.dis(l)
563:     puts "sinh and asinh: ds = " + ds.to_s if verbose
564:     s += ds
565:     
566:     l = a.cosh
567:     r = l.acosh.cosh
568:     ds = r.dis(l)
569:     puts "cosh and acosh: ds = " + ds.to_s if verbose
570:     s += ds
571:     
572:     l = b.tanh
573:     r = l.atanh.tanh
574:     ds = r.dis(l)
575:     puts "tanh and atanh: ds = " + ds.to_s if verbose
576:     s += ds
577:    
578:     l = a.coth
579:     r = l.acoth.coth
580:     ds = r.dis(l)
581:     puts "coth and acoth: ds = " + ds.to_s if verbose
582:     s += ds
583:     
584:     t2 = Time.now
585:     puts "class of s is " + s.class.to_s + " ."
586:     puts "The error sum s is " + s.to_s + " ."
587:     puts "It should be close to 0."
588:     puts "Computation time was #{t2-t1} seconds."
589:     s
590:   end

Test object.

Needed for automatic tests of arithmetic relations. Intended to give numbers which rapidly change sign and order of magnitude when the argument grows regularly e.g. as in 1,2,3,… . However, suitibility as a random generator is not the focus. If the second argument is ‘true’, the result is multplied by a number << 1 in order to prevent the result from overloading the exponential function.

[Source]

    # File cnum.rb, line 87
87:   def C.tob(anInteger, small = false)
88:     ai = anInteger.to_i * 2
89:     x1 = R.tob(ai,small)
90:     x2 = R.tob(ai + 1,small)
91:     C.new(x1,x2)
92:   end

The constant 0.

[Source]

    # File cnum.rb, line 52
52:   def C.zero
53:     C.new
54:   end

Public Instance methods

Returns the C-object self * a.

[Source]

     # File cnum.rb, line 187
187:   def *(a)
188:     if a.integer? || a.real?
189:       b = R.c a
190:       C.new(@re * b, @im * b)
191:     elsif a.complex?
192:       C.new(@re * a.re - @im * a.im , @re * a.im + @im * a.re )
193:     else
194:       fail "cannot multiply a complex number with this argument"
195:     end
196:   end

Returns the a-th power of self. A may be integer, real, or complex. The result is always complex.

[Source]

     # File cnum.rb, line 223
223:   def **(a)
224:     return C.nan if nan?
225:     if a.integer?
226:       if a.zero?
227:         C.one
228:       elsif a == 1
229:         self
230:       elsif a == -1
231:         inv
232:       else
233:         b = a.abs
234:         res = self
235:         for i in 1...b
236:           res *= self
237:         end
238:         if a < 0
239:           res = res.inv
240:         end
241:         res
242:       end
243:     elsif a.real?
244:       b = C.new(a)
245:       (log * b).exp
246:     elsif a.complex?
247:       (log * a).exp
248:     else
249:       fail "Argument not acceptable as an exponent"
250:     end
251:   end

Returns the C-object self + a.

[Source]

     # File cnum.rb, line 162
162:   def +(a)
163:     if a.integer? || a.real?
164:       b = R.c a
165:       C.new(@re + b, @im)
166:     elsif a.complex?
167:       C.new(@re + a.re, @im + a.im)
168:     else
169:       fail "cannot add this argument to a complex number"
170:     end
171:   end

Unary plus operator. It returns the C-object self.

[Source]

    # File cnum.rb, line 98
98:   def +@; self; end

Returns the C-object self - a.

[Source]

     # File cnum.rb, line 174
174:   def -(a)
175:     if a.integer? || a.real?
176:       b = R.c a
177:       C.new(@re - b, @im)
178:     elsif a.complex?
179:       C.new(@re - a.re, @im - a.im)
180:     else
181:       fail "cannot subtract this argument from a complex number"
182:     end  
183:     
184:   end

Unary minus operator. It returns the C-object -self.

[Source]

    # File cnum.rb, line 95
95:   def -@; C.new(-@re, -@im); end

Returns the C-object self / a.

[Source]

     # File cnum.rb, line 199
199:   def /(a)
200:     if a.integer? || a.real?
201:       b = R.c a
202:       C.new(@re / b, @im / b)
203:     elsif a.complex?
204:       r2 = a.abs2
205:       C.new((@re * a.re + @im * a.im)/r2 , (@im * a.re - @re * a.im)/r2 )
206:     else
207:       fail "cannot divide a complex number by this argument"
208:     end
209:   end

The order relation is here lexicographic ordering based on the agreement that re is the ‘first letter’ and im the ‘second letter’ of ‘the word’. Needed only for book-keeping purposes.

[Source]

     # File cnum.rb, line 131
131:   def <=> (a)
132:     cr = @re <=> a.re
133:     return cr unless cr.zero?
134:     ci = @im <=> a.im
135:     return ci unless ci.zero?
136:     return 0
137:   end

Returns the absolute value of self.

[Source]

     # File cnum.rb, line 111
111:   def abs; @re.hypot(@im); end

Returns the absolute value squared of self.

[Source]

     # File cnum.rb, line 114
114:   def abs2; @re * @re + @im * @im; end

Inverse cosine.

[Source]

     # File cnum.rb, line 376
376:   def acos
377:     acosh.dbi
378:   end

Inverse hyperbolic cosine.

[Source]

     # File cnum.rb, line 356
356:   def acosh
357:     ((self * self - C.one).sqrt + self).log
358:   end

Inverse cotangent.

[Source]

     # File cnum.rb, line 386
386:   def acot 
387:     ti.acoth.ti
388:   end

Inverse hyperbolic cotangent.

[Source]

     # File cnum.rb, line 366
366:   def acoth
367:     ((self + C.one)/(self - C.one)).log * R.i2
368:   end

Returns the argument (i.e. the polar angle) of self.

[Source]

     # File cnum.rb, line 117
117:   def arg; @re.arg(@im); end

Inverse sine.

[Source]

     # File cnum.rb, line 371
371:   def asin
372:     ti.asinh.dbi
373:   end

Inverse hyperbolic sine.

[Source]

     # File cnum.rb, line 351
351:   def asinh
352:      ((self * self + C.one).sqrt + self).log
353:   end

Inverse tangent.

[Source]

     # File cnum.rb, line 381
381:   def atan 
382:     ti.atanh.dbi
383:   end

Inverse hyperbolic tangent.

[Source]

     # File cnum.rb, line 361
361:   def atanh
362:     ((C.one + self)/(C.one - self)).log * R.i2
363:   end

[Source]

    # File cnum.rb, line 49
49:  def clone; C.new(@re,@im); end

Supports the unified treatment of real and complex numbers.

[Source]

     # File cnum.rb, line 159
159:   def complex?; true; end

(Complex) conjugation, no effect on real numbers. Supports the unified treatment of real and complex numbers.

[Source]

     # File cnum.rb, line 102
102:   def conj; C.new(@re, -@im); end

Cosine.

[Source]

     # File cnum.rb, line 316
316:   def cos
317:     (expi + (-self).expi) * R.i2
318:   end

Hyperbolic cosine.

[Source]

     # File cnum.rb, line 334
334:   def cosh; (exp + (-self).exp) * R.i2; end

Cotangent.

[Source]

     # File cnum.rb, line 326
326:   def cot
327:     cos / sin
328:   end

Hyperbolic cotangent.

[Source]

     # File cnum.rb, line 344
344:   def coth
345:     s = exp - (-self).exp
346:     c = exp + (-self).exp
347:     c/s
348:   end

Returns self divided by i.

[Source]

     # File cnum.rb, line 108
108:   def dbi; self * C.new(0,-1); end

Returns a kind of relative distance between self and aR. The return value varies from 0 to 1, where 1 means maximum dissimilarity of the arguments. Such a function is needed for testing the validity of arithmetic laws, which, due to numerical noise, should not be expected to be fulfilled exactly.

[Source]

     # File cnum.rb, line 291
291:   def dis(aC)
292:     a = abs
293:     b = aC.abs
294:     d = (self - aC).abs
295:     s = a + b
296:     return R.c0 if s.zero?
297:     d1 = d/s
298:     Basics.inf(d,d1)
299:   end

Exponential function.

[Source]

     # File cnum.rb, line 212
212:   def exp; C.new(@im.cos, @im.sin) * @re.exp; end

Exponential function of the argument multiplied by C.i

[Source]

     # File cnum.rb, line 215
215:   def expi; (self * C.i).exp; end

Returns ‘true’ if the real art or the iaginary part of self is infinite.

[Source]

     # File cnum.rb, line 147
147:   def infinite?; @re.infinite? || @im.infinite?; end

Since R is not Fixnum or Bignum we return ‘false’. In scientific computation there may be the need to use various types of ‘real number types’ but there should always a clear-cut distinction between integer types and real types.

[Source]

     # File cnum.rb, line 153
153:   def integer?; false; end

Returns the inverse 1/self.

[Source]

     # File cnum.rb, line 260
260:   def inv
261:      C.one / self
262:   end

Natural logarithm.

[Source]

     # File cnum.rb, line 219
219:   def log; C.new(abs.log,arg); end

Returns ‘true’ if self is ‘not a number’ (NaN).

[Source]

     # File cnum.rb, line 143
143:   def nan?; @re.nan? || @im.nan?; end

Printing the value together with a label

[Source]

     # File cnum.rb, line 305
305:   def prn(name)
306:     puts "#{name} = " + to_s
307:   end

The pseudo_inverse of zero is zero, and equal to the inverse for all other arguments.

[Source]

     # File cnum.rb, line 269
269:   def pseudo_inv
270:      zero? ? C.zero : C.one / self
271:   end

Supports the unified treatment of real and complex numbers.

[Source]

     # File cnum.rb, line 156
156:   def real?; false; end

For the return value res we have res.int? true and (self - res).abs <= 0.5

[Source]

     # File cnum.rb, line 274
274:   def round(n)
275:     u = @re.round(n)
276:     v = @im.round(n)
277:     C.new(u,v)
278:   end

Sine.

[Source]

     # File cnum.rb, line 311
311:   def sin 
312:     (expi - (-self).expi) * C.new(0,-R.i2)
313:   end

Hyperbolic sine.

[Source]

     # File cnum.rb, line 331
331:   def sinh; (exp - (-self).exp) * R.i2; end

Returns the square root of self.

[Source]

     # File cnum.rb, line 281
281:   def sqrt
282:     self ** R.i2
283:   end

Tangent.

[Source]

     # File cnum.rb, line 321
321:   def tan
322:     sin / cos
323:   end

Hyperbolic tangent.

[Source]

     # File cnum.rb, line 337
337:   def tanh
338:     s = exp - (-self).exp
339:     c = exp + (-self).exp
340:     s/c
341:   end

Returns self times i.

[Source]

     # File cnum.rb, line 105
105:   def ti; self * C.i; end

Returns the zero-element which belongs to the same class than self

[Source]

     # File cnum.rb, line 254
254:   def to_0; C.zero; end

Returns the unit-element which belongs to the same class than self

[Source]

     # File cnum.rb, line 257
257:   def to_1; C.one; end

Conversion to String.

[Source]

     # File cnum.rb, line 302
302:   def to_s; "C(#{@re}, #{@im})"; end

Returns ‘true’ if self equals zero.

[Source]

     # File cnum.rb, line 140
140:   def zero?; @re.zero? && @im.zero?; end

Returns ‘true’ iff self == C(0,0)

[Source]

     # File cnum.rb, line 265
265:   def zero?; @re.zero? && @im.zero?; end

Protected Instance methods

Redefining coerce from Numeric. This allows writing 1 + C.new(137) instead of C.new(137) + 1 or C.new(137) + R.c1.

[Source]

     # File cnum.rb, line 124
124:   def coerce(a)
125:     [ C.new(a), self]
126:   end

[Validate]