Namespace

Class Index [+]

Quicksearch

Flt::Trigonometry

Trigonometry functions. The angular units used by these functions can be specified with the angle attribute of the context. The accepted values are:

These functions are injected in Context objects.

Constants

PI_MARGIN

Attributes

pi_value[RW]
pi_digits[RW]
pi_cache[RW]
pi_cache[RW]
pi_cache_digits[RW]

Private Class Methods

iarccot(x, unity) click to toggle source
     # File lib/flt/trigonometry.rb, line 741
741:         def iarccot(x, unity)
742:           xpow = unity / x
743:           n = 1
744:           sign = 1
745:           sum = 0
746:           loop do
747:               term = xpow / n
748:               break if term == 0
749:               sum += sign * (xpow/n)
750:               xpow /= x*x
751:               n += 2
752:               sign = -sign
753:           end
754:           sum
755:         end

Public Instance Methods

acos(x) click to toggle source

Arc-cosine. The result is in the units specified by the context angle attribute. If the angular units are radians the result is in [-pi/2, pi/2]; it is in [-90,90] in degrees.

    # File lib/flt/trigonometry.rb, line 50
50:     def acos(x)
51:       acos_base(num_class[x])
52:     end
acosh(x) click to toggle source

Hyperbolic arccosine

     # File lib/flt/trigonometry.rb, line 116
116:     def acosh(x)
117:       acosh_base(num_class[x])
118:     end
asin(x) click to toggle source

Arc-sine. The result is in the units specified by the context angle attribute. If the angular units are radians the result is in [-pi/2, pi/2]; it is in [-90,90] in degrees.

    # File lib/flt/trigonometry.rb, line 44
44:     def asin(x)
45:       asin_base(num_class[x])
46:     end
asinh(x) click to toggle source

Hyperbolic arcsine

     # File lib/flt/trigonometry.rb, line 111
111:     def asinh(x)
112:       asinh_base(num_class[x])
113:     end
atan(x) click to toggle source

Arc-tangent. The result is in the units specified by the context angle attribute. If the angular units are radians the result is in [-pi/2, pi/2]; it is in [-90,90] in degrees.

    # File lib/flt/trigonometry.rb, line 31
31:     def atan(x)
32:       atan_base(num_class[x])
33:     end
atan2(y, x) click to toggle source

Arc-tangent with two arguments (principal value of the argument of the complex number x+i*y). The result is in the units specified by the context angle attribute. If the angular units are radians the result is in [-pi, pi]; it is in [-180,180] in degrees.

    # File lib/flt/trigonometry.rb, line 38
38:     def atan2(y, x)
39:       atan2_base(num_class[y], num_class[x])
40:     end
atanh(x) click to toggle source

Hyperbolic arctangent

     # File lib/flt/trigonometry.rb, line 121
121:     def atanh(x)
122:       atanh_base(num_class[x])
123:     end
cos(x) click to toggle source

Cosine of an angle given in the units specified by the context angle attribute.

    # File lib/flt/trigonometry.rb, line 15
15:     def cos(x)
16:       cos_base(num_class[x])
17:     end
cosh(x) click to toggle source

Hyperbolic cosine

     # File lib/flt/trigonometry.rb, line 101
101:     def cosh(x)
102:       cosh_base(num_class[x])
103:     end
e(digits=nil) click to toggle source
    # File lib/flt/trigonometry.rb, line 84
84:     def e(digits=nil)
85:       num_class.context(self) do |local_context|
86:         local_context.precision = digits if digits
87:         num_class.Num(1).exp
88:       end
89:     end
half() click to toggle source
    # File lib/flt/trigonometry.rb, line 91
91:     def half
92:       @half ||= num_class.one_half
93:     end
hypot(x, y) click to toggle source

Length of the hypotenuse of a right-angle triangle (modulus or absolute value of the complex x+i*y).

    # File lib/flt/trigonometry.rb, line 55
55:     def hypot(x, y)
56:       hypot_base(num_class[x], num_class[y])
57:     end
pi(round_digits=nil) click to toggle source
     # File lib/flt/trigonometry.rb, line 732
732:       def pi(round_digits=nil)
733:         v = pi_hex_digits(round_digits)
734:         l = v.size
735:         num_class.context(self, :precision=>round_digits){+num_class.Num(1,v.to_i(16),1-l)}
736:       end
pi(round_digits=nil) click to toggle source

Pi

    # File lib/flt/trigonometry.rb, line 60
60:     def pi(round_digits=nil)
61:       round_digits ||= self.precision
62:       if Trigonometry.pi_digits < round_digits
63:         # provisional implementation (very slow)
64:         lasts = 0
65:         t, s, n, na, d, da = Trigonometry.pi_cache
66:         num_class.context(self) do |local_context|
67:           local_context.precision = round_digits + 6
68:           tol = Rational(1,num_class.int_radix_power(local_context.precision+1))
69:           while (s-lasts)>tol
70:             lasts = s
71:             n, na = n+na, na+8
72:             d, da = d+da, da+32
73:             t = (t * n) / d
74:             s += t
75:           end
76:           Trigonometry.pi_value = num_class[s]
77:           Trigonometry.pi_digits = round_digits
78:           Trigonometry.pi_cache = [t, s, n, na, d, da]
79:         end
80:       end
81:       num_class.context(self, :precision=>round_digits){+Trigonometry.pi_value}
82:     end
pi_hex_digits(round_digits=nil) click to toggle source

truncated hex digits for rounding hexadecimally at round_digits

     # File lib/flt/trigonometry.rb, line 695
695:       def pi_hex_digits(round_digits=nil)
696:         round_digits ||= self.precision
697:         digits = round_digits
698:           if Trigonometry.pi_cache_digits <= digits # we need at least one more truncated digit
699:              continue = true
700:              while continue
701:                margin = PI_MARGIN # margin to reduce recomputing with more digits to avoid ending in 0 or 5
702:                digits += margin + 1
703:                fudge = 16
704:                unity = 16**(digits+fudge)
705:                v = 4*(4*Trigonometry.iarccot(5, unity) - Trigonometry.iarccot(239, unity))
706:                v = v.to_s(16)[0,digits]
707:                # if the last digit is 0 or 8 the truncated value may not be good for rounding
708:                loop do
709:                  #last_digit = v%16
710:                  last_digit = v[1,1].to_i(16)
711:                  continue = (last_digit==8 || last_digit==0)
712:                  if continue && margin>0
713:                    # if we have margin we back-up one digit
714:                    margin -= 1
715:                    v = v[0...1]
716:                  else
717:                    break
718:                  end
719:                end
720:              end
721:              Trigonometry.pi_cache_digits = digits + margin - PI_MARGIN # @pi_cache.size
722:              Trigonometry.pi_cache = v # DecNum(+1, v, 1-digits) # cache truncated value
723:           end
724:           # Now we avoid rounding too much because it is slow
725:           l = round_digits + 1
726:           while (l<Trigonometry.pi_cache_digits) && [0,8].include?(Trigonometry.pi_cache[l-1,1].to_i(16))
727:             l += 1
728:           end
729:           Trigonometry.pi_cache[0,l]
730:       end
sin(x) click to toggle source

Sine of an angle given in the units specified by the context angle attribute.

    # File lib/flt/trigonometry.rb, line 20
20:     def sin(x)
21:       sin_base(num_class[x])
22:     end
sinh(x) click to toggle source

Hyperbolic sine

    # File lib/flt/trigonometry.rb, line 96
96:     def sinh(x)
97:       sinh_base(num_class[x])
98:     end
tan(x) click to toggle source

Tangent of an angle given in the units specified by the context angle attribute.

    # File lib/flt/trigonometry.rb, line 25
25:     def tan(x)
26:       tan_base(num_class[x])
27:     end
tanh(x) click to toggle source

Hyperbolic tangent

     # File lib/flt/trigonometry.rb, line 106
106:     def tanh(x)
107:       tanh_base(num_class[x])
108:     end

Protected Instance Methods

acos_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 284
284:     def acos_base(x)
285: 
286:       return self.exception(Num::InvalidOperation, 'acos needs -1 <= x <= 2') if x.abs > 1
287: 
288:       if x == 1
289:           return half_cycle
290:       elsif x == 0
291:           return quarter_cycle
292:       elsif x == 1
293:           return num_class.zero
294:       end
295: 
296:       required_precision = self.precision
297: 
298:       if x < half
299:         num_class.context(self, :precision=>required_precision+2) do
300:           x = x/(1-x*x).sqrt
301:           x = num_class.context.quarter_cycle - num_class.context.atan(x)
302:         end
303:       else
304:         # valid for x>=0
305:         num_class.context(self, :precision=>required_precision+3) do
306: 
307:           # x = (1-x*x).sqrt # x*x may require double precision if x*x is near 1
308:           x = (1-num_class.context(self, :precision=>required_precision*2){x*x}).sqrt
309: 
310:           x = num_class.context.asin(x)
311:         end
312:       end
313:       +x
314: 
315:     end
acosh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 388
388:     def acosh_base(x)
389: 
390:       return self.exception(Num::InvalidOperation, 'acosh needs x >= 1') if x < 1
391: 
392:       x = x.copy_sign(1)
393:       s = nil
394: 
395:       num_class.context(self) do |local_context|
396:         if x == 1
397:           s = num_class.zero
398:         else
399:           if x.adjusted_exponent >= local_context.precision
400:             s = x+x
401:           else
402:             s = x + local_context.sqrt((x+1)*(x-1))
403:           end
404:           s = local_context.ln(s)
405:         end
406:       end
407:       return plus(s)
408:     end
angle_to(x, angular_units) click to toggle source
     # File lib/flt/trigonometry.rb, line 568
568:       def angle_to(x, angular_units)
569:         return plus(x) if angular_units == self.angle
570:         case angular_units
571:         when :rad
572:           rad_to(x)
573:         when :deg
574:           deg_to(x)
575:         when :grad
576:           grad_to(x)
577:         end
578:       end
asin_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 264
264:     def asin_base(x)
265:       x = +x
266:       return self.exception(Num::InvalidOperation, 'asin needs -1 <= x <= 1') if x.abs > 1
267: 
268:         if x == 1
269:             return -quarter_cycle
270:         elsif x == 0
271:             return num_class.zero
272:         elsif x == 1
273:             return quarter_cycle
274:         end
275: 
276:         num_class.context(self) do |local_context|
277:           local_context.precision += 3
278:           x = x/(1-x*x).sqrt
279:           x = local_context.atan(x)
280:         end
281:         +x
282:     end
asinh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 367
367:     def asinh_base(x)
368:       sign = x.sign
369:       x = x.copy_sign(1)
370:       s = nil
371: 
372:       num_class.context(self) do |local_context|
373:         x_squared = x ** 2
374:         if x_squared.zero? || x_squared.subnormal?
375:           s = x
376:         else
377:           # TODO: more accurate formula for small x: if x<...
378:           if x.adjusted_exponent >= local_context.precision
379:             s = local_context.ln(x+x)
380:           else
381:             s = local_context.ln(x + local_context.sqrt(x_squared + 1))
382:           end
383:         end
384:       end
385:       return plus(s).copy_sign(sign)
386:     end
atan2_base(y, x) click to toggle source
     # File lib/flt/trigonometry.rb, line 237
237:     def atan2_base(y, x)
238:         abs_y = y.abs
239:         abs_x = x.abs
240:         y_is_real = !x.infinite?
241: 
242:         if x != 0
243:             if y_is_real
244:                 a = y!=0 ? atan(y / x) : num_class.zero
245:                 a += half_cycle.copy_sign(y) if x < 0
246:                 return a
247:             elsif abs_y == abs_x
248:                 one = num_class[1]
249:                 x = one.copy_sign(x)
250:                 y = one.copy_sign(y)
251:                 return half_cycle * (2 - x) / (4 * y)
252:             end
253:         end
254: 
255:         if y != 0
256:             return atan(num_class.infinity(y.sign))
257:         elsif x < 0
258:             return half_cycle.copy_sign(x)
259:         else
260:             return num_class.zero
261:         end
262:     end
atan_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 194
194:     def atan_base(x)
195:       s = nil
196:       conversion = true
197:       extra_prec = num_class.radix==2 ? 4 : 2
198:       num_class.context(self) do |local_context|
199:         local_context.precision += extra_prec
200:         if x == 0
201:           return num_class.zero
202:         elsif x.abs > 1
203:           if x.infinite?
204:             s = local_context.quarter_cycle.copy_sign(x)
205:             conversion = false
206:             break
207:           else
208:             # c = (quarter_cycle).copy_sign(x)
209:             c = (half*local_context.pi).copy_sign(x)
210:             x = 1 / x
211:           end
212:         end
213:         local_context.precision += extra_prec
214:         x_squared = x ** 2
215:         if x_squared.zero? || x_squared.subnormal?
216:           s = x
217:           s = c - s if c && c!=0
218:           break
219:         end
220:         y = x_squared / (1 + x_squared)
221:         y_over_x = y / x
222:         i = num_class.zero; lasts = 0; s = y_over_x; coeff = 1; num = y_over_x
223:         while s != lasts
224:           lasts = s
225:           i += 2
226:           coeff *= i / (i + 1)
227:           num *= y
228:           s += coeff * num
229:         end
230:         if c && c!= 0
231:           s = c - s
232:         end
233:       end
234:       return conversion ? rad_to(s) : plus(s)
235:     end
atanh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 410
410:     def atanh_base(x)
411:       sign = x.sign
412:       x = x.copy_sign(1)
413:       s = nil
414: 
415:       return self.exception(Num::InvalidOperation, 'asinh needs -1 <= x <= 1') if x > 1
416: 
417:       num_class.context(self) do |local_context|
418:         if x.adjusted_exponent <= -local_context.precision
419:           s = x
420:         else
421:           s = (1 + x) / (1 - x)
422:           s = half*local_context.ln(s)
423:         end
424:       end
425:       return plus(s).copy_sign(sign)
426:     end
cos_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 134
134:     def cos_base(x)
135:       x = x.copy_sign(1) # note that abs rounds; copy_sign does not.
136:       rev_sign = false
137:       s = nil
138:       num_class.context(self) do |local_context|
139:         local_context.precision += 3 # extra digits for intermediate steps
140:         x,k,pi_2 = local_context.reduce_angle2(x,2)
141:         rev_sign = true if k>1
142:         if k % 2 == 0
143:           x = pi_2 - x
144:         else
145:           rev_sign = !rev_sign
146:         end
147:         x = local_context.to_rad(x)
148:         i, lasts, fact, num = 1, 0, 1, num_class[x]
149:         s = num
150:         x2 = -x*x
151:         while s != lasts
152:           lasts = s
153:           i += 2
154:           fact *= i * (i-1)
155:           num *= x2
156:           s += num / fact
157:         end
158:       end
159:       return rev_sign ? minus(s) : plus(s)
160:     end
cosh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 348
348:     def cosh_base(x)
349:       s = nil
350:       num_class.context(self) do |local_context|
351:         local_context.precision += 3 # extra digits for intermediate steps
352:         x = x.copy_sign(1)
353:         s = half*(x.exp + (-x).exp)
354:       end
355:       return plus(s)
356:     end
deg_to(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 550
550:       def deg_to(x)
551:         case self.angle
552:         when :deg
553:           plus(x)
554:         else
555:           plus(num_class.context(self, :extra_precision=>3){x*half_cycle/num_class[180]})
556:         end
557:       end
grad_to(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 559
559:       def grad_to(x)
560:         case self.angle
561:         when :grad
562:           plus(x)
563:         else
564:           plus(num_class.context(self, :extra_precision=>3){x*half_cycle/num_class[200]})
565:         end
566:       end
half_cycle() click to toggle source
     # File lib/flt/trigonometry.rb, line 480
480:       def half_cycle
481:         case self.angle
482:         when :rad
483:           pi(num_class.context.precision)
484:         when :deg
485:           num_class.Num(180)
486:         when :grad
487:           num_class.Num(200)
488:         end
489:       end
hypot_base(x, y) click to toggle source
     # File lib/flt/trigonometry.rb, line 317
317:     def hypot_base(x, y)
318:       +num_class.context(self) do |local_context|
319:         local_context.precision += 3
320:         (x*x + y*y).sqrt
321:       end
322:     end
inv2pi(decimals=nil) click to toggle source
     # File lib/flt/trigonometry.rb, line 440
440:     def inv2pi(decimals=nil)
441:       num_class.context(self, :precision=>decimals) do |local_context|
442:         num_class.Num(1)/local_context.pi2
443:       end
444:     end
invpi(decimals=nil) click to toggle source
     # File lib/flt/trigonometry.rb, line 434
434:     def invpi(decimals=nil)
435:       num_class.context(self, :precision=>decimals) do |local_context|
436:         num_class[1]/local_context.pi
437:       end
438:     end
modtwopi(x) click to toggle source

class <

  private
     # File lib/flt/trigonometry.rb, line 449
449:       def modtwopi(x)
450:         return plus(num_class.context(self, :precision=>self.precision*3){x.modulo(one_cycle)})
451:       end
one_cycle() click to toggle source
     # File lib/flt/trigonometry.rb, line 469
469:       def one_cycle
470:         case self.angle
471:         when :rad
472:           pi2
473:         when :deg
474:           num_class.Num(360)
475:         when :grad
476:           num_class.Num(400)
477:         end
478:       end
pi2(decimals=nil) click to toggle source
     # File lib/flt/trigonometry.rb, line 428
428:     def pi2(decimals=nil)
429:       num_class.context(self, :precision=>decimals) do |local_context|
430:         local_context.pi*2
431:       end
432:     end
quarter_cycle() click to toggle source
     # File lib/flt/trigonometry.rb, line 491
491:       def quarter_cycle
492:         case self.angle
493:         when :rad
494:           half*pi(num_class.context.precision)
495:         when :deg
496:           num_class.Num(90)
497:         when :grad
498:           num_class.Num(100)
499:         end
500:       end
rad_to(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 541
541:       def rad_to(x)
542:         case self.angle
543:         when :rad
544:           plus(x)
545:         else
546:           plus(num_class.context(self, :extra_precision=>3){|lc| x*half_cycle/lc.pi})
547:         end
548:       end
reduce_angle(a) click to toggle source

Reduce angle to [0,2Pi)

     # File lib/flt/trigonometry.rb, line 454
454:       def reduce_angle(a)
455:         modtwopi(a)
456:       end
reduce_angle2(a,k0=nil) click to toggle source

Reduce angle to [0,Pi/k0) (result is not rounded to precision)

     # File lib/flt/trigonometry.rb, line 459
459:       def reduce_angle2(a,k0=nil) # divisor of pi or nil for pi*2
460:         # we could reduce first to pi*2 to avoid the mod k0 operation
461:         k,r,divisor = num_class.context do
462:           num_class.context.precision *= 3
463:           m = k0.nil? ? one_cycle : half_cycle/k0
464:           a.divmod(m)+[m]
465:         end
466:         [r, k.modulo(k0*2).to_i, divisor]
467:       end
sin_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 162
162:     def sin_base(x)
163:       sign = x.sign
164:       s = nil
165:       num_class.context(self) do |local_context|
166:         local_context.precision += 3 # extra digits for intermediate steps
167:         x = x.copy_sign(1) if sign<0
168:         x,k,pi_2 = local_context.reduce_angle2(x,2)
169:         sign = -sign if k>1
170:         x = pi_2 - x if k % 2 == 1
171:         x = local_context.to_rad(x)
172:         i, lasts, fact, num = 1, 0, 1, num_class[x]
173:         s = num
174:         x2 = -x*x
175:         while s != lasts
176:           lasts = s
177:           i += 2
178:           fact *= i * (i-1)
179:           num *= x2
180:           s += num / fact
181:         end
182:       end
183:       return plus(s).copy_sign(sign)
184:     end
sinh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 324
324:     def sinh_base(x)
325:       sign = x.sign
326:       s = nil
327:       num_class.context(self) do |local_context|
328:         local_context.precision += 3 # extra digits for intermediate steps
329:         x = x.copy_sign(1) if sign<0
330:         if x > 1
331:           s = half*(x.exp - (-x).exp)
332:         else
333:           i, lasts, fact, num = 1, 0, 1, num_class[x]
334:           s = num
335:           x2 = x*x
336:           while s != lasts
337:             lasts = s
338:             i += 2
339:             fact *= i * (i-1)
340:             num *= x2
341:             s += num / fact
342:           end
343:         end
344:       end
345:       return plus(s).copy_sign(sign)
346:     end
tan_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 186
186:     def tan_base(x)
187:       plus(num_class.context(self) do |local_context|
188:         local_context.precision += 2 # extra digits for intermediate steps
189:         s,c = local_context.sin(x), local_context.cos(x)
190:         s/c
191:       end)
192:     end
tanh_base(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 358
358:     def tanh_base(x)
359:       s = nil
360:       num_class.context(self) do |local_context|
361:         local_context.precision += 3 # extra digits for intermediate steps
362:         s = sinh_base(x)/cosh_base(x)
363:       end
364:       return plus(s)
365:     end
to_angle(angular_units, x) click to toggle source
     # File lib/flt/trigonometry.rb, line 529
529:       def to_angle(angular_units, x)
530:         return plus(x) if angular_units == self.angle
531:         case angular_units
532:         when :rad
533:           to_rad(x)
534:         when :deg
535:           to_deg(x)
536:         when :grad
537:           to_grad(x)
538:         end
539:       end
to_deg(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 511
511:       def to_deg(x)
512:         case self.angle
513:         when :deg
514:           plus(x)
515:         else
516:           plus(num_class.context(self, :extra_precision=>3){x*num_class[180]/half_cycle})
517:         end
518:       end
to_grad(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 520
520:       def to_grad(x)
521:         case self.angle
522:         when :deg
523:           plus(x)
524:         else
525:           plus(num_class.context(self, :extra_precision=>3){x*num_class[200]/half_cycle})
526:         end
527:       end
to_rad(x) click to toggle source
     # File lib/flt/trigonometry.rb, line 502
502:       def to_rad(x)
503:         case self.angle
504:         when :rad
505:           plus(x)
506:         else
507:           plus(num_class.context(self, :extra_precision=>3){|lc| x*lc.pi/half_cycle})
508:         end
509:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.